From 155c5b5bcd09cdb13e90fcf2bff524fd1e786a2b Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 19 Nov 2013 21:41:45 -0800 Subject: [PATCH 01/41] Refactored Reader's new design for reuse elsewhere - Moved the view hierarchy and layout logic to ReaderPostView - Gutted ReaderPostTableViewCell and made it use ReaderPostView instead --- WordPress/Classes/ReaderPostTableViewCell.h | 19 +- WordPress/Classes/ReaderPostTableViewCell.m | 466 +---------------- WordPress/Classes/ReaderPostView.h | 31 ++ WordPress/Classes/ReaderPostView.m | 481 ++++++++++++++++++ WordPress/Classes/ReaderPostsViewController.m | 45 +- WordPress/WordPress.xcodeproj/project.pbxproj | 10 +- 6 files changed, 576 insertions(+), 476 deletions(-) create mode 100644 WordPress/Classes/ReaderPostView.h create mode 100644 WordPress/Classes/ReaderPostView.m diff --git a/WordPress/Classes/ReaderPostTableViewCell.h b/WordPress/Classes/ReaderPostTableViewCell.h index cb8a14a9de9c..9f2381beb836 100644 --- a/WordPress/Classes/ReaderPostTableViewCell.h +++ b/WordPress/Classes/ReaderPostTableViewCell.h @@ -8,28 +8,19 @@ #import #import "ReaderPost.h" -#import "ReaderTableViewCell.h" +#import "WPTableViewCell.h" -@interface ReaderPostTableViewCell : ReaderTableViewCell +@class ReaderPostView; + +@interface ReaderPostTableViewCell : WPTableViewCell @property (nonatomic, strong) UIImageView *avatarImageView; + (CGFloat)cellHeightForPost:(ReaderPost *)post withWidth:(CGFloat)width; + (ReaderPostTableViewCell *)cellForSubview:(UIView *)subview; - (void)configureCell:(ReaderPost *)post; -- (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; +@property (nonatomic, strong) ReaderPostView *postView; @end diff --git a/WordPress/Classes/ReaderPostTableViewCell.m b/WordPress/Classes/ReaderPostTableViewCell.m index fb0d21c28c73..021cdb1eeb07 100644 --- a/WordPress/Classes/ReaderPostTableViewCell.m +++ b/WordPress/Classes/ReaderPostTableViewCell.m @@ -7,150 +7,31 @@ // #import "ReaderPostTableViewCell.h" -#import -#import -#import "UIImageView+Gravatar.h" #import "WordPressAppDelegate.h" -#import "WPWebViewController.h" -#import "UIImageView+AFNetworkingExtra.h" -#import "UILabel+SuggestSize.h" -#import "WPAvatarSource.h" -#import "ReaderButton.h" -#import "NSDate+StringFormatting.h" -#import "UIColor+Helpers.h" +#import "ReaderPost.h" +#import "ReaderPostView.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; +const CGFloat RPTVCVerticalOuterPadding = 16.0f; @interface ReaderPostTableViewCell() - -@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, assign) BOOL showImage; - +@property (nonatomic, strong) UIView *sideBorderView; @end @implementation ReaderPostTableViewCell { - BOOL _avatarIsSet; - UIView *_sideBorderView; } + (CGFloat)cellHeightForPost:(ReaderPost *)post withWidth:(CGFloat)width { - CGFloat desiredHeight = 0.0f; - - // Margins - CGFloat contentWidth = width; - if (IS_IPAD) { - contentWidth = contentWidth * (1 - WPTableViewCellMarginPercentage * 2); - } - // iPhone has extra padding around each cell if (IS_IPHONE) { - 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 * 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; + width = width - 2 * RPTVCHorizontalOuterPadding; } - // Tag - NSString *tagName = post.primaryTagName; - if ([tagName length] > 0) { - desiredHeight += [tagName sizeWithFont:[self summaryFont] constrainedToSize:CGSizeMake(contentWidth, CGFLOAT_MAX) lineBreakMode:NSLineBreakByClipping].height; - } - - // Padding above and below the line - desiredHeight += RPTVCVerticalPadding * 2; - - // Size of the meta view - desiredHeight += RPTVCMetaViewHeight; + CGFloat desiredHeight = [ReaderPostView heightForPost:post withWidth:width]; 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]) { @@ -173,23 +54,17 @@ - (void)dealloc { - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; - if (self) { - self.backgroundColor = [UIColor colorWithWhite:0.9453125f alpha:1.f]; - self.contentView.backgroundColor = [WPStyleGuide itsEverywhereGrey]; + if (self) { + self.sideBorderView = [[UIView alloc] init]; + self.sideBorderView.backgroundColor = [UIColor colorWithWhite:0.9f alpha:1.f]; + self.sideBorderView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self.contentView addSubview:self.sideBorderView]; - _sideBorderView = [[UIView alloc] init]; - _sideBorderView.backgroundColor = [UIColor colorWithWhite:0.9f alpha:1.f]; - _sideBorderView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [self.contentView addSubview:_sideBorderView]; + self.postView = [[ReaderPostView alloc] initWithFrame:self.frame]; + self.postView.backgroundColor = [UIColor whiteColor]; + self.backgroundColor = [WPStyleGuide itsEverywhereGrey]; - self.containerView = [[UIView alloc] init]; - _containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - _containerView.backgroundColor = [UIColor whiteColor]; - _containerView.opaque = YES; - [self.contentView addSubview:_containerView]; - - [self buildPostContent]; - [self buildMetaContent]; + [self.contentView addSubview:self.postView]; } return self; @@ -200,7 +75,7 @@ - (void)setHighlightedEffect:(BOOL)highlighted animated:(BOOL)animated { delay:0 options:UIViewAnimationCurveEaseInOut animations:^{ - _sideBorderView.hidden = highlighted; + self.sideBorderView.hidden = highlighted; self.alpha = highlighted ? .7f : 1.f; if (highlighted) { CGFloat perspective = IS_IPAD ? -0.00005 : -0.0001; @@ -220,6 +95,8 @@ - (void)setHighlightedEffect:(BOOL)highlighted animated:(BOOL)animated { - (void)setPost:(ReaderPost *)post { if ([post isEqual:_post]) return; + + self.postView.post = post; if (_post) { [_post removeObserver:self forKeyPath:@"isReblogged" context:@"reblogging"]; @@ -252,322 +129,35 @@ - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [self setHighlightedEffect:selected animated:animated]; } -- (void)buildPostContent { - self.cellImageView.contentMode = UIViewContentModeScaleAspectFill; - [_containerView addSubview:self.cellImageView]; - self.titleLabel = [[UILabel alloc] init]; - _titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _titleLabel.backgroundColor = [UIColor clearColor]; - _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.textColor = [UIColor colorWithHexString:@"333"]; - _snippetLabel.lineBreakMode = NSLineBreakByTruncatingTail; - _snippetLabel.numberOfLines = 4; - [_containerView addSubview:_snippetLabel]; - - self.byView = [[UIView alloc] init]; - _byView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _byView.backgroundColor = [UIColor whiteColor]; - _byView.userInteractionEnabled = YES; - [_containerView addSubview:_byView]; - - 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 = 1; - _bylineLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _bylineLabel.font = [UIFont fontWithName:@"OpenSans" size:12.0f]; - _bylineLabel.adjustsFontSizeToFitWidth = NO; - _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]; +- (void)prepareForReuse { + [super prepareForReuse]; - 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]; + [self.postView reset]; + [self setHighlightedEffect:NO animated:NO]; } -- (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 setImage:[UIImage imageNamed:@"reader-postaction-like-blue"] forState:UIControlStateNormal]; - [_likeButton setImage:[UIImage imageNamed:@"reader-postaction-like-active"] forState:UIControlStateSelected]; - [_metaView addSubview:_likeButton]; - - self.reblogButton = [ReaderButton buttonWithType:UIButtonTypeCustom]; - _reblogButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin; - _reblogButton.backgroundColor = [UIColor whiteColor]; - [_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]; -} +#pragma mark - Instance Methods - (void)layoutSubviews { [super layoutSubviews]; CGFloat leftPadding = IS_IPHONE ? RPTVCHorizontalOuterPadding : 0; CGFloat contentWidth = self.frame.size.width - leftPadding * 2; - CGFloat innerContentWidth = contentWidth - RPTVCHorizontalInnerPadding * 2; - CGFloat nextY = RPTVCAuthorPadding; - CGFloat height = 0.0f; - - 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) { - _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 - nextY += RPTVCVerticalPadding; - height = ceil([_titleLabel suggestedSizeForWidth:innerContentWidth].height); - _titleLabel.frame = CGRectMake(RPTVCHorizontalInnerPadding, nextY, innerContentWidth, height); - nextY += height + RPTVCVerticalPadding; - - // Position the snippet - 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); - - 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 - - // Button order from right-to-left: Like, [Comment], Reblog, - _likeButton.frame = CGRectMake(buttonX, buttonY, buttonWidth, RPTVCControlButtonHeight); - buttonX -= buttonWidth + RPTVCControlButtonSpacing; - - 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); + CGRect frame = CGRectMake(leftPadding, 0, contentWidth, self.frame.size.height - RPTVCVerticalOuterPadding); + self.postView.frame = frame; 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 { - [super prepareForReuse]; - - _avatarIsSet = NO; - - _bylineLabel.text = nil; - _titleLabel.text = nil; - _snippetLabel.text = nil; - [_tagButton setTitle:nil forState:UIControlStateNormal]; - - [self setHighlightedEffect:NO animated:NO]; -} - - -#pragma mark - Instance Methods - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - [self updateControlBar]; + CGFloat sideBorderHeight = self.frame.size.height - RPTVCVerticalOuterPadding; // Just below it + self.sideBorderView.frame = CGRectMake(sideBorderX, 1, self.frame.size.width - sideBorderX * 2, sideBorderHeight); } - (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.attributedText = [ReaderPostTableViewCell titleAttributedStringForPost:post]; - _snippetLabel.attributedText = [ReaderPostTableViewCell summaryAttributedStringForPost:post]; - - _bylineLabel.text = [post authorString]; - - [_timeButton setTitle:[post.dateCreated shortString] forState:UIControlStateNormal]; - self.showImage = NO; - self.cellImageView.hidden = YES; - self.cellImageView.contentMode = UIViewContentModeCenter; - self.cellImageView.image = [UIImage imageNamed:@"wp_img_placeholder"]; - if (post.featuredImageURL) { - 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]; - - [self updateControlBar]; -} - -- (void)setAvatar:(UIImage *)avatar { - if (_avatarIsSet) - return; - - static UIImage *wpcomBlavatar; - static UIImage *wporgBlavatar; - if (!wpcomBlavatar) { - wpcomBlavatar = [UIImage imageNamed:@"wpcom_blavatar"]; - } - - if (!wporgBlavatar) { - wporgBlavatar = [UIImage imageNamed:@"wporg_blavatar"]; - } - - if (avatar) { - self.avatarImageView.image = avatar; - _avatarIsSet = YES; - } else { - self.avatarImageView.image = [self.post isWPCom] ? wpcomBlavatar : wporgBlavatar; - } -} - -- (void)setFeaturedImage:(UIImage *)image { - self.cellImageView.contentMode = UIViewContentModeScaleAspectFill; - self.cellImageView.image = image; -} - -- (void)updateControlBar { - if (!_post) - return; - - _likeButton.selected = _post.isLiked.boolValue; - _reblogButton.selected = _post.isReblogged.boolValue; - _reblogButton.userInteractionEnabled = !_reblogButton.selected; -} - -- (void)likeAction:(id)sender { - [self.post toggleLikedWithSuccess:^{ - if ([self.post.isLiked boolValue]) { - [WPMobileStats trackEventForWPCom:StatsEventReaderLikedPost]; - } else { - [WPMobileStats trackEventForWPCom:StatsEventReaderUnlikedPost]; - } - } failure:^(NSError *error) { - DDLogError(@"Error Liking Post : %@", [error localizedDescription]); - [self updateControlBar]; - }]; - - [self updateControlBar]; + [self.postView configure:post]; } @end diff --git a/WordPress/Classes/ReaderPostView.h b/WordPress/Classes/ReaderPostView.h new file mode 100644 index 000000000000..d0ba079a7b12 --- /dev/null +++ b/WordPress/Classes/ReaderPostView.h @@ -0,0 +1,31 @@ +// +// ReaderPostView.h +// WordPress +// +// Created by Michael Johnston on 11/19/13. +// Copyright (c) 2013 WordPress. All rights reserved. +// + +#import +#import "ReaderPost.h" + +@interface ReaderPostView : UIView + +@property (nonatomic, strong) ReaderPost *post; +@property (nonatomic, strong) UIImageView *cellImageView; +@property (nonatomic, strong) UIImageView *avatarImageView; +@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; + ++ (CGFloat)heightForPost:(ReaderPost *)post withWidth:(CGFloat)width; +- (void)configure:(ReaderPost *)post; +- (void)setFeaturedImage:(UIImage *)image; +- (void)setAvatar:(UIImage *)avatar; +- (void)updateControlBar; +- (void)reset; + +@end diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m new file mode 100644 index 000000000000..ed483abb1328 --- /dev/null +++ b/WordPress/Classes/ReaderPostView.m @@ -0,0 +1,481 @@ +// +// ReaderPostView.m +// WordPress +// +// Created by Michael Johnston on 11/19/13. +// Copyright (c) 2013 WordPress. All rights reserved. +// + +#import "ReaderPostView.h" + +#import +#import +#import "UIImageView+Gravatar.h" +#import "WordPressAppDelegate.h" +#import "WPWebViewController.h" +#import "UIImageView+AFNetworkingExtra.h" +#import "UILabel+SuggestSize.h" +#import "WPAvatarSource.h" +#import "ReaderButton.h" +#import "NSDate+StringFormatting.h" +#import "UIColor+Helpers.h" +#import "WPTableViewCell.h" + +const CGFloat RPVAuthorPadding = 8.0f; +const CGFloat RPVHorizontalInnerPadding = 12.0f; +const CGFloat RPVMetaViewHeight = 48.0f; +const CGFloat RPVAuthorViewHeight = 32.0f; +const CGFloat RPVVerticalPadding = 16.0f; +const CGFloat RPVAvatarSize = 32.0f; +const CGFloat RPVBorderHeight = 1.0f; +const CGFloat RPVSmallButtonLeftPadding = 2; // Follow, tag +const CGFloat RPVMaxImageHeightPercentage = 0.59f; +const CGFloat RPVMaxSummaryHeight = 88.0f; +const CGFloat RPVLineHeightMultiple = 1.15f; + +// Control buttons (Like, Reblog, ...) +const CGFloat RPVControlButtonHeight = 48.0f; +const CGFloat RPVControlButtonWidth = 48.0f; +const CGFloat RPVControlButtonSpacing = 12.0f; +const CGFloat RPVControlButtonBorderSize = 0.0f; + +@interface ReaderPostView() + +@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, assign) BOOL showImage; + +@end + +@implementation ReaderPostView { + BOOL _avatarIsSet; +} + ++ (CGFloat)heightForPost:(ReaderPost *)post withWidth:(CGFloat)width { + CGFloat desiredHeight = 0.0f; + + // Margins + CGFloat contentWidth = width; + if (IS_IPAD) { + contentWidth = contentWidth * (1 - WPTableViewCellMarginPercentage * 2); + } + + desiredHeight += RPVAuthorPadding; + desiredHeight += RPVAuthorViewHeight; + desiredHeight += RPVAuthorPadding; + + // Are we showing an image? What size should it be? + if (post.featuredImageURL) { + CGFloat height = ceilf((contentWidth * RPVMaxImageHeightPercentage)); + desiredHeight += height; + } + + // Everything but the image has inner padding + contentWidth -= RPVHorizontalInnerPadding * 2; + + // Title + desiredHeight += RPVVerticalPadding; + NSAttributedString *postTitle = [self titleAttributedStringForPost:post]; + desiredHeight += [postTitle boundingRectWithSize:CGSizeMake(contentWidth, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil].size.height; + desiredHeight += RPVVerticalPadding; + + // Post summary + if ([post.summary length] > 0) { + NSAttributedString *postSummary = [self summaryAttributedStringForPost:post]; + desiredHeight += [postSummary boundingRectWithSize:CGSizeMake(contentWidth, RPVMaxSummaryHeight) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil].size.height; + desiredHeight += RPVVerticalPadding; + } + + // Tag + NSString *tagName = post.primaryTagName; + if ([tagName length] > 0) { + desiredHeight += [tagName sizeWithFont:[self summaryFont] constrainedToSize:CGSizeMake(contentWidth, CGFLOAT_MAX) lineBreakMode:NSLineBreakByClipping].height; + } + + // Padding above and below the line + desiredHeight += RPVVerticalPadding * 2; + + // Size of the meta view + desiredHeight += RPVMetaViewHeight; + + return ceil(desiredHeight); +} + ++ (NSAttributedString *)titleAttributedStringForPost:(ReaderPost *)post { + NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; + [style setLineHeightMultiple:RPVLineHeightMultiple]; + 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:RPVLineHeightMultiple]; + 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]; +} + + +#pragma mark - Lifecycle Methods + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.opaque = YES; + + self.cellImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 44.0f, 44.0f)]; // arbitrary size. + _cellImageView.backgroundColor = [WPStyleGuide readGrey]; + _cellImageView.contentMode = UIViewContentModeScaleAspectFill; + _cellImageView.clipsToBounds = YES; + + [self buildPostContent]; + [self buildMetaContent]; + } + return self; +} + + + +- (void)dealloc { + self.post = nil; +} + +- (void)setPost:(ReaderPost *)post { + if ([post isEqual:_post]) + return; + + if (_post) { + [_post removeObserver:self forKeyPath:@"isReblogged" context:@"reblogging"]; + } + + _post = post; + [_post addObserver:self forKeyPath:@"isReblogged" options:NSKeyValueObservingOptionNew context:@"reblogging"]; +} + +- (void)buildPostContent { + self.cellImageView.contentMode = UIViewContentModeScaleAspectFill; + [self addSubview:self.cellImageView]; + + self.titleLabel = [[UILabel alloc] init]; + _titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; + _titleLabel.backgroundColor = [UIColor clearColor]; + _titleLabel.textColor = [UIColor colorWithHexString:@"333"]; + _titleLabel.lineBreakMode = NSLineBreakByWordWrapping; + _titleLabel.numberOfLines = 0; + [self addSubview:_titleLabel]; + + self.titleBorder = [[CALayer alloc] init]; + _titleBorder.backgroundColor = [[UIColor colorWithHexString:@"f1f1f1"] CGColor]; + [self.layer addSublayer:_titleBorder]; + + self.snippetLabel = [[UILabel alloc] init]; + _snippetLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; + _snippetLabel.backgroundColor = [UIColor clearColor]; + _snippetLabel.textColor = [UIColor colorWithHexString:@"333"]; + _snippetLabel.lineBreakMode = NSLineBreakByTruncatingTail; + _snippetLabel.numberOfLines = 4; + [self addSubview:_snippetLabel]; + + self.byView = [[UIView alloc] init]; + _byView.autoresizingMask = UIViewAutoresizingFlexibleWidth; + _byView.backgroundColor = [UIColor clearColor]; + _byView.userInteractionEnabled = YES; + [self addSubview:_byView]; + + CGRect avatarFrame = CGRectMake(RPVHorizontalInnerPadding, RPVAuthorPadding, RPVAvatarSize, RPVAvatarSize); + self.avatarImageView = [[UIImageView alloc] initWithFrame:avatarFrame]; + [_byView addSubview:_avatarImageView]; + + self.bylineLabel = [[UILabel alloc] init]; + _bylineLabel.backgroundColor = [UIColor clearColor]; + _bylineLabel.numberOfLines = 1; + _bylineLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; + _bylineLabel.font = [UIFont fontWithName:@"OpenSans" size:12.0f]; + _bylineLabel.adjustsFontSizeToFitWidth = NO; + _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, RPVSmallButtonLeftPadding, 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, RPVSmallButtonLeftPadding, 0, 0)]; + [_tagButton setImage:[UIImage imageNamed:@"reader-postaction-tag"] forState:UIControlStateNormal]; + [_tagButton setTitleColor:[UIColor colorWithHexString:@"aaa"] forState:UIControlStateNormal]; + [self addSubview:_tagButton]; +} + +- (void)buildMetaContent { + self.metaView = [[UIView alloc] init]; + _metaView.autoresizingMask = UIViewAutoresizingFlexibleWidth; + _metaView.backgroundColor = [UIColor clearColor]; + [self 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, RPVSmallButtonLeftPadding, 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 setImage:[UIImage imageNamed:@"reader-postaction-like-blue"] forState:UIControlStateNormal]; + [_likeButton setImage:[UIImage imageNamed:@"reader-postaction-like-active"] forState:UIControlStateSelected]; + [_metaView addSubview:_likeButton]; + + self.reblogButton = [ReaderButton buttonWithType:UIButtonTypeCustom]; + _reblogButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin; + _reblogButton.backgroundColor = [UIColor whiteColor]; + [_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 contentWidth = self.frame.size.width; + CGFloat innerContentWidth = contentWidth - RPVHorizontalInnerPadding * 2; + CGFloat nextY = RPVAuthorPadding; + CGFloat height = 0.0f; + + _byView.frame = CGRectMake(0, 0, contentWidth, RPVAuthorViewHeight + RPVAuthorPadding * 2); + CGFloat bylineX = RPVAvatarSize + RPVAuthorPadding + RPVHorizontalInnerPadding; + _bylineLabel.frame = CGRectMake(bylineX, RPVAuthorPadding - 2, contentWidth - bylineX, 18); + + if ([self.post isFollowable]) { + _followButton.hidden = NO; + CGFloat followX = bylineX - 4; // Fudge factor for image alignment + CGFloat followY = RPVAuthorPadding + _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 += RPVAuthorViewHeight + RPVAuthorPadding; + + // Are we showing an image? What size should it be? + if (_showImage) { + _titleBorder.hidden = YES; + height = ceilf(contentWidth * RPVMaxImageHeightPercentage); + self.cellImageView.frame = CGRectMake(0, nextY, contentWidth, height); + nextY += height; + } else { + _titleBorder.hidden = NO; + _titleBorder.frame = CGRectMake(RPVHorizontalInnerPadding, nextY, contentWidth - RPVHorizontalInnerPadding * 2, RPVBorderHeight); + } + + // Position the title + nextY += RPVVerticalPadding; + height = ceil([_titleLabel suggestedSizeForWidth:innerContentWidth].height); + _titleLabel.frame = CGRectMake(RPVHorizontalInnerPadding, nextY, innerContentWidth, height); + nextY += height + RPVVerticalPadding; + + // Position the snippet + if ([self.post.summary length] > 0) { + height = ceil([_snippetLabel suggestedSizeForWidth:innerContentWidth].height); + height = MIN(height, RPVMaxSummaryHeight); + _snippetLabel.frame = CGRectMake(RPVHorizontalInnerPadding, nextY, innerContentWidth, height); + nextY += ceilf(height + RPVVerticalPadding); + } + + // Tag + if ([self.post.primaryTagName length] > 0) { + height = ceil([_tagButton.titleLabel suggestedSizeForWidth:innerContentWidth].height); + _tagButton.frame = CGRectMake(RPVHorizontalInnerPadding, nextY, innerContentWidth, height); + nextY += height + RPVVerticalPadding; + self.tagButton.hidden = NO; + } else { + self.tagButton.hidden = YES; + } + + // Position the meta view and its subviews + _metaView.frame = CGRectMake(0, nextY, contentWidth, RPVMetaViewHeight); + _metaBorder.frame = CGRectMake(RPVHorizontalInnerPadding, 0, contentWidth - RPVHorizontalInnerPadding * 2, RPVBorderHeight); + + BOOL commentsOpen = [[self.post commentsOpen] boolValue] && [self.post isWPCom]; + CGFloat buttonWidth = RPVControlButtonWidth; + CGFloat buttonX = _metaView.frame.size.width - RPVControlButtonWidth; + CGFloat buttonY = RPVBorderHeight; // Just below the line + + // Button order from right-to-left: Like, [Comment], Reblog, + _likeButton.frame = CGRectMake(buttonX, buttonY, buttonWidth, RPVControlButtonHeight); + buttonX -= buttonWidth + RPVControlButtonSpacing; + + if (commentsOpen) { + self.commentButton.hidden = NO; + self.commentButton.frame = CGRectMake(buttonX, buttonY, buttonWidth, RPVControlButtonHeight); + buttonX -= buttonWidth + RPVControlButtonSpacing; + } else { + self.commentButton.hidden = YES; + } + _reblogButton.frame = CGRectMake(buttonX, buttonY, buttonWidth - RPVControlButtonBorderSize, RPVControlButtonHeight); + + CGFloat timeWidth = contentWidth - _reblogButton.frame.origin.x; + _timeButton.frame = CGRectMake(RPVHorizontalInnerPadding, RPVBorderHeight, timeWidth, RPVControlButtonHeight); +} + +- (void)reset { + _avatarIsSet = NO; + + _bylineLabel.text = nil; + _titleLabel.text = nil; + _snippetLabel.text = nil; + [_tagButton setTitle:nil forState:UIControlStateNormal]; + + [_cellImageView cancelImageRequestOperation]; + _cellImageView.image = nil; +} + + +#pragma mark - Instance Methods + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { + [self updateControlBar]; +} + +- (void)configure:(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.attributedText = [ReaderPostView titleAttributedStringForPost:post]; + _snippetLabel.attributedText = [ReaderPostView summaryAttributedStringForPost:post]; + + _bylineLabel.text = [post authorString]; + + [_timeButton setTitle:[post.dateCreated shortString] forState:UIControlStateNormal]; + + self.showImage = NO; + self.cellImageView.hidden = YES; + self.cellImageView.contentMode = UIViewContentModeCenter; + self.cellImageView.image = [UIImage imageNamed:@"wp_img_placeholder"]; + if (post.featuredImageURL) { + 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]; + + [self updateControlBar]; +} + +- (void)setAvatar:(UIImage *)avatar { + if (_avatarIsSet) + return; + + static UIImage *wpcomBlavatar; + static UIImage *wporgBlavatar; + if (!wpcomBlavatar) { + wpcomBlavatar = [UIImage imageNamed:@"wpcom_blavatar"]; + } + + if (!wporgBlavatar) { + wporgBlavatar = [UIImage imageNamed:@"wporg_blavatar"]; + } + + if (avatar) { + self.avatarImageView.image = avatar; + _avatarIsSet = YES; + } else { + self.avatarImageView.image = [self.post isWPCom] ? wpcomBlavatar : wporgBlavatar; + } +} + +- (void)setFeaturedImage:(UIImage *)image { + self.cellImageView.contentMode = UIViewContentModeScaleAspectFill; + self.cellImageView.image = image; +} + +- (void)updateControlBar { + if (!_post) + return; + + _likeButton.selected = _post.isLiked.boolValue; + _reblogButton.selected = _post.isReblogged.boolValue; + _reblogButton.userInteractionEnabled = !_reblogButton.selected; +} + +@end diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index a152274401de..ec49baf3d79f 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -28,9 +28,12 @@ #import "NSString+Helpers.h" #import "WPPopoverBackgroundView.h" #import "IOS7CorrectedTextView.h" +#import "readerPostView.h" static CGFloat const RPVCScrollingFastVelocityThreshold = 30.f; static CGFloat const RPVCHeaderHeightPhone = 10.f; +static CGFloat const RPVCMaxImageHeightPercentage = 0.58f; + NSString *const RPVCDisplayedNativeFriendFinder = @"DisplayedNativeFriendFinder"; @interface ReaderPostsViewController () { @@ -93,7 +96,7 @@ - (void)viewDidLoad { maxWidth = MAX(self.tableView.bounds.size.width, self.tableView.bounds.size.height); } maxWidth -= 20.f; // Container frame - CGFloat maxHeight = maxWidth * RPTVCMaxImageHeightPercentage; + CGFloat maxHeight = maxWidth * RPVCMaxImageHeightPercentage; _featuredImageSource = [[WPTableImageSource alloc] initWithMaxSize:CGSizeMake(maxWidth, maxHeight)]; _featuredImageSource.delegate = self; self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; @@ -307,25 +310,25 @@ - (void)loadImagesForVisibleRows { ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]; - UIImage *image = [post cachedAvatarWithSize:cell.avatarImageView.bounds.size]; - CGSize imageSize = cell.avatarImageView.bounds.size; + UIImage *image = [post cachedAvatarWithSize:cell.postView.avatarImageView.bounds.size]; + CGSize imageSize = cell.postView.avatarImageView.bounds.size; if (image) { - [cell setAvatar:image]; + [cell.postView setAvatar:image]; } else { __weak UITableView *tableView = self.tableView; [post fetchAvatarWithSize:imageSize success:^(UIImage *image) { if (cell == [tableView cellForRowAtIndexPath:indexPath]) { - [cell setAvatar:image]; + [cell.postView setAvatar:image]; } }]; } if (post.featuredImageURL) { NSURL *imageURL = post.featuredImageURL; - imageSize = cell.cellImageView.frame.size; + imageSize = cell.postView.cellImageView.frame.size; image = [_featuredImageSource imageForURL:imageURL withSize:imageSize]; if (image) { - [cell setFeaturedImage:image]; + [cell.postView setFeaturedImage:image]; } else { [_featuredImageSource fetchImageForURL:imageURL withSize:imageSize indexPath:indexPath isPrivate:post.isPrivate]; } @@ -367,10 +370,10 @@ - (void)likeAction:(id)sender { } } failure:^(NSError *error) { DDLogError(@"Error Liking Post : %@", [error localizedDescription]); - [cell updateControlBar]; + [cell.postView updateControlBar]; }]; - [cell updateControlBar]; + [cell.postView updateControlBar]; } - (void)topicsAction:(id)sender { @@ -564,11 +567,11 @@ - (UITableViewCell *)newCell { ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (cell == nil) { cell = [[ReaderPostTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; - [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]; + [cell.postView.reblogButton addTarget:self action:@selector(reblogAction:) forControlEvents:UIControlEventTouchUpInside]; + [cell.postView.likeButton addTarget:self action:@selector(likeAction:) forControlEvents:UIControlEventTouchUpInside]; + [cell.postView.followButton addTarget:self action:@selector(followAction:) forControlEvents:UIControlEventTouchUpInside]; + [cell.postView.commentButton addTarget:self action:@selector(commentAction:) forControlEvents:UIControlEventTouchUpInside]; + [cell.postView.tagButton addTarget:self action:@selector(tagAction:) forControlEvents:UIControlEventTouchUpInside]; } return cell; } @@ -585,14 +588,14 @@ - (void)configureCell:(UITableViewCell *)aCell atIndexPath:(NSIndexPath *)indexP [cell configureCell:post]; [self setImageForPost:post forCell:cell indexPath:indexPath]; - CGSize imageSize = cell.avatarImageView.bounds.size; + CGSize imageSize = cell.postView.avatarImageView.bounds.size; UIImage *image = [post cachedAvatarWithSize:imageSize]; if (image) { - [cell setAvatar:image]; + [cell.postView setAvatar:image]; } else if (!self.tableView.isDragging && !self.tableView.isDecelerating) { [post fetchAvatarWithSize:imageSize success:^(UIImage *image) { if (cell == [self.tableView cellForRowAtIndexPath:indexPath]) { - [cell setAvatar:image]; + [cell.postView setAvatar:image]; } }]; } @@ -603,14 +606,14 @@ - (void)setImageForPost:(ReaderPost *)post forCell:(ReaderPostTableViewCell *)ce if (!imageURL) return; - CGSize imageSize = cell.cellImageView.bounds.size; + CGSize imageSize = cell.postView.cellImageView.bounds.size; if (CGSizeEqualToSize(imageSize, CGSizeZero)) { imageSize.width = self.tableView.bounds.size.width; - imageSize.height = round(imageSize.width * RPTVCMaxImageHeightPercentage); + imageSize.height = round(imageSize.width * RPVCMaxImageHeightPercentage); } UIImage *image = [_featuredImageSource imageForURL:imageURL withSize:imageSize]; if (image) { - [cell setFeaturedImage:image]; + [cell.postView setFeaturedImage:image]; } else if (!_isScrollingFast) { [_featuredImageSource fetchImageForURL:imageURL withSize:imageSize indexPath:indexPath isPrivate:post.isPrivate]; } @@ -1003,7 +1006,7 @@ - (void)openFriendFinder:(id)sender { - (void)tableImageSource:(WPTableImageSource *)tableImageSource imageReady:(UIImage *)image forIndexPath:(NSIndexPath *)indexPath { if (!_isScrollingFast) { ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]; - [cell setFeaturedImage:image]; + [cell.postView setFeaturedImage:image]; } } diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 383a47b26a9a..bd00052850aa 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -298,6 +298,7 @@ 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 */; }; + 46F8D7FB183C293200E10A38 /* ReaderPostView.m in Sources */ = {isa = PBXBuildFile; fileRef = 46F8D7FA183C293200E10A38 /* ReaderPostView.m */; }; 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 */; }; @@ -1314,7 +1315,9 @@ 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 = ""; }; + 46F871551839802100BC149B /* WordPress 13.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 13.xcdatamodel"; sourceTree = ""; }; + 46F8D7F9183C293200E10A38 /* ReaderPostView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReaderPostView.h; sourceTree = ""; }; + 46F8D7FA183C293200E10A38 /* ReaderPostView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReaderPostView.m; 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 = ""; }; @@ -2954,8 +2957,6 @@ 85EC44D31739826A00686604 /* CreateAccountAndBlogViewController.m */, 858DE40D1730384F000AC628 /* LoginViewController.h */, 858DE40E1730384F000AC628 /* LoginViewController.m */, - 85E1058F1731D066001071A3 /* LoginCompletedWalkthroughViewController.h */, - 85E105901731D066001071A3 /* LoginCompletedWalkthroughViewController.m */, 85D08A5C17332C4A00E2BBCA /* NewAddUsersBlogViewController.h */, 85D08A5D17332C4A00E2BBCA /* NewAddUsersBlogViewController.m */, 85B6F7501742DAE800CE7F3A /* WPNUXBackButton.h */, @@ -3835,6 +3836,8 @@ 5D42A3EA175E75EE005CFF05 /* ReaderPostDetailView.m */, 5D42A3EB175E75EE005CFF05 /* ReaderPostDetailViewController.h */, 5D42A3EC175E75EE005CFF05 /* ReaderPostDetailViewController.m */, + 46F8D7F9183C293200E10A38 /* ReaderPostView.h */, + 46F8D7FA183C293200E10A38 /* ReaderPostView.m */, 5D42A3F1175E75EE005CFF05 /* ReaderTableViewCell.h */, 5D42A3F2175E75EE005CFF05 /* ReaderTableViewCell.m */, 5D42A3EF175E75EE005CFF05 /* ReaderPostTableViewCell.h */, @@ -5204,6 +5207,7 @@ 5D0077A7182AE9DF00F865DB /* ReaderMediaQueue.m in Sources */, 462F4E0B18369F0B0028D2F8 /* BlogListViewController.m in Sources */, 5D42A3F9175E75EE005CFF05 /* ReaderMediaView.m in Sources */, + 46F8D7FB183C293200E10A38 /* ReaderPostView.m in Sources */, 5D42A3FA175E75EE005CFF05 /* ReaderPostDetailView.m in Sources */, 5D42A3FB175E75EE005CFF05 /* ReaderPostDetailViewController.m in Sources */, 5D42A3FC175E75EE005CFF05 /* ReaderPostsViewController.m in Sources */, From 05b42a6e64a39a5ecbc9ddb2cc2a1e2bcc778144 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Thu, 21 Nov 2013 23:53:52 -0800 Subject: [PATCH 02/41] Start of major refactoring of Reader's detail view --- .../Classes/ReaderPostDetailViewController.h | 5 +- .../Classes/ReaderPostDetailViewController.m | 170 +++---- WordPress/Classes/ReaderPostTableViewCell.m | 7 +- WordPress/Classes/ReaderPostView.h | 8 +- WordPress/Classes/ReaderPostView.m | 456 +++++++++++++++--- WordPress/Classes/ReaderPostsViewController.m | 42 +- 6 files changed, 514 insertions(+), 174 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.h b/WordPress/Classes/ReaderPostDetailViewController.h index 01ef34533fd2..2e251fb868dc 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.h +++ b/WordPress/Classes/ReaderPostDetailViewController.h @@ -10,7 +10,10 @@ #import "ReaderPost.h" @interface ReaderPostDetailViewController : UIViewController +@property (nonatomic, strong) ReaderPost *post; +@property (nonatomic, assign) BOOL showInlineActionBar; -- (id)initWithPost:(ReaderPost *)apost; +- (id)initWithPost:(ReaderPost *)post featuredImage:(UIImage *)image; +- (void)updateFeaturedImage:(UIImage *)image; @end diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 8aeffbde506f..53b9f1f6271c 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -17,15 +17,22 @@ #import "WordPressComApi.h" #import "ReaderComment.h" #import "ReaderCommentTableViewCell.h" -#import "ReaderPostDetailView.h" #import "ReaderCommentFormView.h" #import "ReaderReblogFormView.h" #import "IOS7CorrectedTextView.h" +#import "ReaderPostView.h" NSInteger const ReaderCommentsToSync = 100; NSTimeInterval const ReaderPostDetailViewControllerRefreshTimeout = 300; // 5 minutes -@interface ReaderPostDetailViewController () { +typedef enum { + ReaderDetailContentSection = 0, + ReaderDetailCommentsSection, + ReaderDetailSectionCount +} ReaderDetailSection; + + +@interface ReaderPostDetailViewController () { BOOL _hasMoreContent; BOOL _loadingMore; CGPoint savedScrollOffset; @@ -34,10 +41,10 @@ @interface ReaderPostDetailViewController () #import "ReaderPost.h" +#import "DTAttributedTextContentView.h" +#import "ReaderMediaQueue.h" -@interface ReaderPostView : UIView +@interface ReaderPostView : UIView @property (nonatomic, strong) ReaderPost *post; @property (nonatomic, strong) UIImageView *cellImageView; @@ -22,10 +24,12 @@ @property (nonatomic, strong) UIButton *timeButton; + (CGFloat)heightForPost:(ReaderPost *)post withWidth:(CGFloat)width; -- (void)configure:(ReaderPost *)post; +- (id)initWithFrame:(CGRect)frame showFullContent:(BOOL)showFullContent; - (void)setFeaturedImage:(UIImage *)image; - (void)setAvatar:(UIImage *)avatar; - (void)updateControlBar; - (void)reset; +- (void)configurePost:(ReaderPost *)post; +- (void)updateLayout; @end diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index ed483abb1328..381873bfe805 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -20,6 +20,10 @@ #import "NSDate+StringFormatting.h" #import "UIColor+Helpers.h" #import "WPTableViewCell.h" +#import "DTTiledLayerWithoutFade.h" +#import "ReaderMediaView.h" +#import "ReaderImageView.h" +#import "ReaderVideoView.h" const CGFloat RPVAuthorPadding = 8.0f; const CGFloat RPVHorizontalInnerPadding = 12.0f; @@ -44,6 +48,7 @@ @interface ReaderPostView() @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) CALayer *titleBorder; @property (nonatomic, strong) UILabel *snippetLabel; +@property (nonatomic, strong) DTAttributedTextContentView *textContentView; @property (nonatomic, strong) UIView *metaView; @property (nonatomic, strong) CALayer *metaBorder; @@ -52,6 +57,9 @@ @interface ReaderPostView() @property (nonatomic, strong) UIView *controlView; @property (nonatomic, assign) BOOL showImage; +@property (nonatomic, assign) BOOL showFullContent; +@property (nonatomic, strong) NSMutableArray *mediaArray; +@property (nonatomic, strong) ReaderMediaQueue *mediaQueue; @end @@ -148,12 +156,15 @@ + (UIFont *)summaryFont { #pragma mark - Lifecycle Methods -- (id)initWithFrame:(CGRect)frame -{ +- (id)initWithFrame:(CGRect)frame showFullContent:(BOOL)showFullContent { self = [super initWithFrame:frame]; if (self) { + self.mediaArray = [NSMutableArray array]; + self.mediaQueue = [[ReaderMediaQueue alloc] initWithDelegate:self]; + self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.opaque = YES; + self.showFullContent = showFullContent; self.cellImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 44.0f, 44.0f)]; // arbitrary size. _cellImageView.backgroundColor = [WPStyleGuide readGrey]; @@ -166,12 +177,66 @@ - (id)initWithFrame:(CGRect)frame return self; } - - - (void)dealloc { self.post = nil; } +- (void)configurePost:(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.attributedText = [ReaderPostView titleAttributedStringForPost:post]; + + if (self.showFullContent) { + NSString *contentString = [NSString stringWithFormat:@"

%@", self.post.content]; + NSData *data = [contentString dataUsingEncoding:NSUTF8StringEncoding]; + _textContentView.attributedString = [[NSAttributedString alloc] initWithHTMLData:data + options:[WPStyleGuide defaultDTCoreTextOptions] + documentAttributes:nil]; + [_textContentView relayoutText]; + } else { + _snippetLabel.attributedText = [ReaderPostView summaryAttributedStringForPost:post]; + } + + _bylineLabel.text = [post authorString]; + + [_timeButton setTitle:[post.dateCreated shortString] forState:UIControlStateNormal]; + + self.showImage = NO; + self.cellImageView.hidden = YES; + self.cellImageView.contentMode = UIViewContentModeCenter; + self.cellImageView.image = [UIImage imageNamed:@"wp_img_placeholder"]; + if (post.featuredImageURL) { + 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]; + + [self updateControlBar]; + +} + - (void)setPost:(ReaderPost *)post { if ([post isEqual:_post]) return; @@ -184,6 +249,34 @@ - (void)setPost:(ReaderPost *)post { [_post addObserver:self forKeyPath:@"isReblogged" options:NSKeyValueObservingOptionNew context:@"reblogging"]; } +- (UIView *)buildContentView { + UIView *contentView; + + if (self.showFullContent) { + [DTAttributedTextContentView setLayerClass:[DTTiledLayerWithoutFade class]]; + + // Needs an initial frame + self.textContentView = [[DTAttributedTextContentView alloc] initWithFrame:self.frame]; + _textContentView.delegate = self; + _textContentView.autoresizingMask = UIViewAutoresizingFlexibleWidth; + _textContentView.backgroundColor = [UIColor whiteColor]; + _textContentView.edgeInsets = UIEdgeInsetsMake(0.0f, RPVHorizontalInnerPadding, 0.0f, RPVHorizontalInnerPadding); + _textContentView.shouldDrawImages = NO; + _textContentView.shouldDrawLinks = NO; + contentView = _textContentView; + } else { + self.snippetLabel = [[UILabel alloc] init]; + _snippetLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; + _snippetLabel.backgroundColor = [UIColor clearColor]; + _snippetLabel.textColor = [UIColor colorWithHexString:@"333"]; + _snippetLabel.lineBreakMode = NSLineBreakByTruncatingTail; + _snippetLabel.numberOfLines = 4; + contentView = _snippetLabel; + } + + return contentView; +} + - (void)buildPostContent { self.cellImageView.contentMode = UIViewContentModeScaleAspectFill; [self addSubview:self.cellImageView]; @@ -200,13 +293,7 @@ - (void)buildPostContent { _titleBorder.backgroundColor = [[UIColor colorWithHexString:@"f1f1f1"] CGColor]; [self.layer addSublayer:_titleBorder]; - self.snippetLabel = [[UILabel alloc] init]; - _snippetLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _snippetLabel.backgroundColor = [UIColor clearColor]; - _snippetLabel.textColor = [UIColor colorWithHexString:@"333"]; - _snippetLabel.lineBreakMode = NSLineBreakByTruncatingTail; - _snippetLabel.numberOfLines = 4; - [self addSubview:_snippetLabel]; + [self addSubview:[self buildContentView]]; self.byView = [[UIView alloc] init]; _byView.autoresizingMask = UIViewAutoresizingFlexibleWidth; @@ -334,12 +421,22 @@ - (void)layoutSubviews { _titleLabel.frame = CGRectMake(RPVHorizontalInnerPadding, nextY, innerContentWidth, height); nextY += height + RPVVerticalPadding; - // Position the snippet + // Position the snippet / content if ([self.post.summary length] > 0) { - height = ceil([_snippetLabel suggestedSizeForWidth:innerContentWidth].height); - height = MIN(height, RPVMaxSummaryHeight); - _snippetLabel.frame = CGRectMake(RPVHorizontalInnerPadding, nextY, innerContentWidth, height); - nextY += ceilf(height + RPVVerticalPadding); + if (self.showFullContent) { + [self.textContentView relayoutText]; + height = [self.textContentView suggestedFrameSizeToFitEntireStringConstraintedToWidth:contentWidth].height; + CGRect textContainerFrame = _textContentView.frame; + textContainerFrame.size.height = height; + textContainerFrame.origin.y = nextY; + self.textContentView.frame = textContainerFrame; + nextY += textContainerFrame.size.height + RPVVerticalPadding; + } else { + height = ceil([_snippetLabel suggestedSizeForWidth:innerContentWidth].height); + height = MIN(height, RPVMaxSummaryHeight); + _snippetLabel.frame = CGRectMake(RPVHorizontalInnerPadding, nextY, innerContentWidth, height); + nextY += ceilf(height + RPVVerticalPadding); + } } // Tag @@ -375,7 +472,12 @@ - (void)layoutSubviews { _reblogButton.frame = CGRectMake(buttonX, buttonY, buttonWidth - RPVControlButtonBorderSize, RPVControlButtonHeight); CGFloat timeWidth = contentWidth - _reblogButton.frame.origin.x; - _timeButton.frame = CGRectMake(RPVHorizontalInnerPadding, RPVBorderHeight, timeWidth, RPVControlButtonHeight); + _timeButton.frame = CGRectMake(RPVHorizontalInnerPadding, RPVBorderHeight, timeWidth, RPVControlButtonHeight); + + // Update own frame + CGRect ownFrame = self.frame; + ownFrame.size.height = nextY + RPVMetaViewHeight + 1; + self.frame = ownFrame; } - (void)reset { @@ -397,51 +499,6 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N [self updateControlBar]; } -- (void)configure:(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.attributedText = [ReaderPostView titleAttributedStringForPost:post]; - _snippetLabel.attributedText = [ReaderPostView summaryAttributedStringForPost:post]; - - _bylineLabel.text = [post authorString]; - - [_timeButton setTitle:[post.dateCreated shortString] forState:UIControlStateNormal]; - - self.showImage = NO; - self.cellImageView.hidden = YES; - self.cellImageView.contentMode = UIViewContentModeCenter; - self.cellImageView.image = [UIImage imageNamed:@"wp_img_placeholder"]; - if (post.featuredImageURL) { - 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]; - - [self updateControlBar]; -} - - (void)setAvatar:(UIImage *)avatar { if (_avatarIsSet) return; @@ -478,4 +535,279 @@ - (void)updateControlBar { _reblogButton.userInteractionEnabled = !_reblogButton.selected; } +- (BOOL)isEmoji:(NSURL *)url { + return ([[url absoluteString] rangeOfString:@"wp.com/wp-includes/images/smilies"].location != NSNotFound); +} + +- (void)handleMediaViewLoaded:(ReaderMediaView *)mediaView { + + BOOL frameChanged = [self updateMediaLayout:mediaView]; + + if (frameChanged) { + // need to reset the layouter because otherwise we get the old framesetter or cached layout frames + self.textContentView.layouter = nil; + + // layout might have changed due to image sizes + [self.textContentView relayoutText]; + + [self updateLayout]; + } +} + +- (void)updateLayout { + // Size the textContentView + CGRect frame = _textContentView.frame; + CGFloat height = [_textContentView suggestedFrameSizeToFitEntireStringConstraintedToWidth:frame.size.width].height; + frame.size.height = height; + _textContentView.frame = frame; + + frame = self.frame; + frame.size.height = height + _textContentView.frame.origin.y + 10.0f; // + bottom padding + self.frame = frame; + + //[self.delegate readerPostDetailViewLayoutChanged]; +} + + +- (BOOL)updateMediaLayout:(ReaderMediaView *)imageView { + BOOL frameChanged = NO; + NSURL *url = imageView.contentURL; + + CGSize originalSize = imageView.frame.size; + CGSize viewSize = imageView.image.size; + + if ([self isEmoji:url]) { + CGFloat scale = [UIScreen mainScreen].scale; + viewSize.width *= scale; + viewSize.height *= scale; + } else { + CGFloat ratio = viewSize.width / viewSize.height; + CGFloat width = _textContentView.frame.size.width; + CGFloat availableWidth = _textContentView.frame.size.width - (_textContentView.edgeInsets.left + _textContentView.edgeInsets.right); + + viewSize.width = availableWidth; + + if (imageView.isShowingPlaceholder) { + viewSize.height = roundf(width / imageView.placeholderRatio); + } else { + viewSize.height = roundf(width / ratio); + } + + viewSize.height += imageView.edgeInsets.top; // account for the top edge inset. + } + + // Widths should always match + if (viewSize.height != originalSize.height) { + frameChanged = YES; + } + + NSPredicate *pred = [NSPredicate predicateWithFormat:@"contentURL == %@", url]; + + // update all attachments that matchin this URL (possibly multiple images with same size) + for (DTTextAttachment *attachment in [self.textContentView.layoutFrame textAttachmentsWithPredicate:pred]) { + attachment.originalSize = originalSize; + attachment.displaySize = viewSize; + } + + return frameChanged; +} + + +#pragma mark ReaderMediaQueueDelegate methods + +- (void)readerMediaQueue:(ReaderMediaQueue *)mediaQueue didLoadBatch:(NSArray *)batch { + BOOL frameChanged = NO; + + for (NSInteger i = 0; i < [batch count]; i++) { + ReaderMediaView *mediaView = [batch objectAtIndex:i]; + if ([self updateMediaLayout:mediaView]) { + frameChanged = YES; + } + } + + if (frameChanged) { + // need to reset the layouter because otherwise we get the old framesetter or cached layout frames + self.textContentView.layouter = nil; + + // layout might have changed due to image sizes + [self.textContentView relayoutText]; + [self setNeedsLayout]; + //[self _updateLayout]; + } +} + +#pragma mark - DTCoreAttributedTextContentView Delegate Methods + +- (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView viewForAttributedString:(NSAttributedString *)string frame:(CGRect)frame { + NSDictionary *attributes = [string attributesAtIndex:0 effectiveRange:nil]; + + NSURL *URL = [attributes objectForKey:DTLinkAttribute]; + NSString *identifier = [attributes objectForKey:DTGUIDAttribute]; + + DTLinkButton *button = [[DTLinkButton alloc] initWithFrame:frame]; + button.URL = URL; + button.minimumHitSize = CGSizeMake(25, 25); // adjusts it's bounds so that button is always large enough + button.GUID = identifier; + + // get image with normal link text + UIImage *normalImage = [attributedTextContentView contentImageWithBounds:frame options:DTCoreTextLayoutFrameDrawingDefault]; + [button setImage:normalImage forState:UIControlStateNormal]; + + // get image for highlighted link text + UIImage *highlightImage = [attributedTextContentView contentImageWithBounds:frame options:DTCoreTextLayoutFrameDrawingDrawLinksHighlighted]; + [button setImage:highlightImage forState:UIControlStateHighlighted]; + + // use normal push action for opening URL + [button addTarget:self action:@selector(handleLinkTapped:) forControlEvents:UIControlEventTouchUpInside]; + + return button; +} + + +- (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView viewForAttachment:(DTTextAttachment *)attachment frame:(CGRect)frame { + + if (!attachment.contentURL) + return nil; + + // If it's the same as the featured image, don't display that image again +// BOOL sameImage = [[attachment.contentURL absoluteString] rangeOfString: [self.post.featuredImageURL absoluteString] +// ].location != NSNotFound; +// if (sameImage) { +// ReaderImageView *emptyView = [[ReaderImageView alloc] initWithFrame:CGRectZero]; +// [self handleMediaViewLoaded:emptyView]; +// [self setNeedsLayout]; +// return emptyView; +// } + + CGFloat width = _textContentView.frame.size.width; + CGFloat availableWidth = _textContentView.frame.size.width - (_textContentView.edgeInsets.left + _textContentView.edgeInsets.right); + + // The ReaderImageView view will conform to the width constraints of the _textContentView. We want the image itself to run out to the edges, + // so position it offset by the inverse of _textContentView's edgeInsets. Also add top padding so we don't bump into a line of text. + // Remeber to add an extra 10px to the frame to preserve aspect ratio. + UIEdgeInsets edgeInsets = _textContentView.edgeInsets; + edgeInsets.left = 0.0f - edgeInsets.left; + edgeInsets.top = 15.0f; + edgeInsets.right = 0.0f - edgeInsets.right; + edgeInsets.bottom = 0.0f; + + if ([attachment isKindOfClass:[DTImageTextAttachment class]]) { + if ([self isEmoji:attachment.contentURL]) { + // minimal frame to suppress drawing context errors with 0 height or width. + frame.size.width = MAX(frame.size.width, 1.0f); + frame.size.height = MAX(frame.size.height, 1.0f); + ReaderImageView *imageView = [[ReaderImageView alloc] initWithFrame:frame]; + [_mediaArray addObject:imageView]; + [self.mediaQueue enqueueMedia:imageView + withURL:attachment.contentURL + placeholderImage:nil + size:CGSizeMake(15.0f, 15.0f) + isPrivate:self.post.isPrivate + success:nil + failure:nil]; + return imageView; + } + + DTImageTextAttachment *imageAttachment = (DTImageTextAttachment *)attachment; + UIImage *image; + + if( [imageAttachment.image isKindOfClass:[UIImage class]] ) { + image = imageAttachment.image; + + CGFloat ratio = image.size.width / image.size.height; + frame.size.width = availableWidth; + frame.size.height = roundf(width / ratio); + } else { + image = [UIImage imageNamed:@"wp_img_placeholder.png"]; + + if (frame.size.width > 1.0f && frame.size.height > 1.0f) { + CGFloat ratio = frame.size.width / frame.size.height; + frame.size.width = availableWidth; + frame.size.height = roundf(width / ratio); + } else { + frame.size.width = availableWidth; + frame.size.height = roundf(width * 0.66f); + } + } + + // offset the top edge inset keeping the image from bumping the text above it. + frame.size.height += edgeInsets.top; + + ReaderImageView *imageView = [[ReaderImageView alloc] initWithFrame:frame]; + imageView.contentMode = UIViewContentModeScaleAspectFit; + imageView.edgeInsets = edgeInsets; + + [_mediaArray addObject:imageView]; + imageView.linkURL = attachment.hyperLinkURL; + [imageView addTarget:self action:@selector(handleImageLinkTapped:) forControlEvents:UIControlEventTouchUpInside]; + + if ([imageAttachment.image isKindOfClass:[UIImage class]]) { + [imageView setImage:image]; + } else { + //imageView.contentMode = UIViewContentModeCenter; + imageView.backgroundColor = [UIColor colorWithRed:192.0f/255.0f green:192.0f/255.0f blue:192.0f/255.0f alpha:1.0]; + + [self.mediaQueue enqueueMedia:imageView + withURL:attachment.contentURL + placeholderImage:image + size:CGSizeMake(width, 0) + isPrivate:self.post.isPrivate + success:^(ReaderMediaView *readerMediaView) { + ReaderImageView *imageView = (ReaderImageView *)readerMediaView; + imageView.contentMode = UIViewContentModeScaleAspectFit; + imageView.backgroundColor = [UIColor clearColor]; + } + failure:nil]; + } + + return imageView; + + } else { + + ReaderVideoContentType videoType; + + if ([attachment isKindOfClass:[DTVideoTextAttachment class]]) { + videoType = ReaderVideoContentTypeVideo; + } else if ([attachment isKindOfClass:[DTIframeTextAttachment class]]) { + videoType = ReaderVideoContentTypeIFrame; + } else if ([attachment isKindOfClass:[DTObjectTextAttachment class]]) { + videoType = ReaderVideoContentTypeEmbed; + } else { + return nil; // Can't handle whatever this is :P + } + + // make sure we have a reasonable size. + if (frame.size.width > width) { + if (frame.size.height == 0) { + frame.size.height = roundf(frame.size.width * 0.66f); + } + CGFloat ratio = frame.size.width / frame.size.height; + frame.size.width = availableWidth; + frame.size.height = roundf(width / ratio); + } + + // offset the top edge inset keeping the image from bumping the text above it. + frame.size.height += edgeInsets.top; + + ReaderVideoView *videoView = [[ReaderVideoView alloc] initWithFrame:frame]; + videoView.contentMode = UIViewContentModeCenter; + videoView.backgroundColor = [UIColor colorWithRed:192.0f/255.0f green:192.0f/255.0f blue:192.0f/255.0f alpha:1.0]; + videoView.edgeInsets = edgeInsets; + + [_mediaArray addObject:videoView]; + [videoView setContentURL:attachment.contentURL ofType:videoType success:^(id readerVideoView) { + [(ReaderVideoView *)readerVideoView setContentMode:UIViewContentModeScaleAspectFit]; + [self handleMediaViewLoaded:readerVideoView]; + } failure:^(id readerVideoView, NSError *error) { + [self handleMediaViewLoaded:readerVideoView]; + + }]; + + [videoView addTarget:self action:@selector(handleVideoTapped:) forControlEvents:UIControlEventTouchUpInside]; + + return videoView; + } +} + + @end diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index ec49baf3d79f..9ff95fb5bc6b 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -28,7 +28,7 @@ #import "NSString+Helpers.h" #import "WPPopoverBackgroundView.h" #import "IOS7CorrectedTextView.h" -#import "readerPostView.h" +#import "ReaderPostView.h" static CGFloat const RPVCScrollingFastVelocityThreshold = 30.f; static CGFloat const RPVCHeaderHeightPhone = 10.f; @@ -47,6 +47,7 @@ @interface ReaderPostsViewController () Date: Fri, 22 Nov 2013 15:14:20 -0800 Subject: [PATCH 03/41] Refactor button actions as delegate methods --- WordPress/Classes/ReaderPostView.h | 24 +++-- WordPress/Classes/ReaderPostView.m | 58 ++++++++++++ WordPress/Classes/ReaderPostsViewController.h | 3 +- WordPress/Classes/ReaderPostsViewController.m | 94 +++++++++---------- 4 files changed, 123 insertions(+), 56 deletions(-) diff --git a/WordPress/Classes/ReaderPostView.h b/WordPress/Classes/ReaderPostView.h index e8c5d3eafb44..c12079e03ece 100644 --- a/WordPress/Classes/ReaderPostView.h +++ b/WordPress/Classes/ReaderPostView.h @@ -11,17 +11,27 @@ #import "DTAttributedTextContentView.h" #import "ReaderMediaQueue.h" -@interface ReaderPostView : UIView +@class ReaderPostView; +@protocol ReaderPostViewDelegate +@optional +- (void)postView:(ReaderPostView *)postView didReceiveFollowAction:(id)sender; +- (void)postView:(ReaderPostView *)postView didReceiveTagAction:(id)sender; +- (void)postView:(ReaderPostView *)postView didReceiveLikeAction:(id)sender; +- (void)postView:(ReaderPostView *)postView didReceiveReblogAction:(id)sender; +- (void)postView:(ReaderPostView *)postView didReceiveCommentAction:(id)sender; +- (void)postView:(ReaderPostView *)postView didReceiveLinkAction:(id)sender; +- (void)postView:(ReaderPostView *)postView didReceiveImageLinkAction:(id)sender; +@end + +@interface ReaderPostView : UIView { + +} + +@property (nonatomic, weak) id delegate; @property (nonatomic, strong) ReaderPost *post; @property (nonatomic, strong) UIImageView *cellImageView; @property (nonatomic, strong) UIImageView *avatarImageView; -@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; + (CGFloat)heightForPost:(ReaderPost *)post withWidth:(CGFloat)width; - (id)initWithFrame:(CGRect)frame showFullContent:(BOOL)showFullContent; diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index 381873bfe805..8eed4f1f7973 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -48,6 +48,12 @@ @interface ReaderPostView() @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) CALayer *titleBorder; @property (nonatomic, strong) UILabel *snippetLabel; +@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; @property (nonatomic, strong) DTAttributedTextContentView *textContentView; @property (nonatomic, strong) UIView *metaView; @@ -327,6 +333,7 @@ - (void)buildPostContent { [_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]; + [_followButton addTarget:self action:@selector(followAction:) forControlEvents:UIControlEventTouchUpInside]; [_byView addSubview:_followButton]; self.tagButton = [ReaderButton buttonWithType:UIButtonTypeCustom]; @@ -336,6 +343,7 @@ - (void)buildPostContent { [_tagButton setTitleEdgeInsets: UIEdgeInsetsMake(0, RPVSmallButtonLeftPadding, 0, 0)]; [_tagButton setImage:[UIImage imageNamed:@"reader-postaction-tag"] forState:UIControlStateNormal]; [_tagButton setTitleColor:[UIColor colorWithHexString:@"aaa"] forState:UIControlStateNormal]; + [_tagButton addTarget:self action:@selector(tagAction:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:_tagButton]; } @@ -363,6 +371,7 @@ - (void)buildMetaContent { _likeButton.backgroundColor = [UIColor whiteColor]; [_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(likeAction:) forControlEvents:UIControlEventTouchUpInside]; [_metaView addSubview:_likeButton]; self.reblogButton = [ReaderButton buttonWithType:UIButtonTypeCustom]; @@ -370,6 +379,7 @@ - (void)buildMetaContent { _reblogButton.backgroundColor = [UIColor whiteColor]; [_reblogButton setImage:[UIImage imageNamed:@"reader-postaction-reblog-blue"] forState:UIControlStateNormal]; [_reblogButton setImage:[UIImage imageNamed:@"reader-postaction-reblog-done"] forState:UIControlStateSelected]; + [_reblogButton addTarget:self action:@selector(reblogAction:) forControlEvents:UIControlEventTouchUpInside]; [_metaView addSubview:_reblogButton]; self.commentButton = [ReaderButton buttonWithType:UIButtonTypeCustom]; @@ -377,6 +387,7 @@ - (void)buildMetaContent { _commentButton.backgroundColor = [UIColor whiteColor]; [_commentButton setImage:[UIImage imageNamed:@"reader-postaction-comment-blue"] forState:UIControlStateNormal]; [_commentButton setImage:[UIImage imageNamed:@"reader-postaction-comment-active"] forState:UIControlStateSelected]; + [_commentButton addTarget:self action:@selector(commentAction:) forControlEvents:UIControlEventTouchUpInside]; [_metaView addSubview:_commentButton]; } @@ -493,6 +504,53 @@ - (void)reset { } +#pragma mark - Actions + +// Forward the actions to the delegate; do it this way instead of exposing buttons as properties +// because the view can have dynamically generated buttons (e.g. links) +- (void)followAction:(id)sender { + if ([self.delegate respondsToSelector:@selector(postView:didReceiveFollowAction:)]) { + [self.delegate postView:self didReceiveFollowAction:sender]; + } +} + +- (void)tagAction:(id)sender { + if ([self.delegate respondsToSelector:@selector(postView:didReceiveTagAction:)]) { + [self.delegate postView:self didReceiveTagAction:sender]; + } +} + +- (void)reblogAction:(id)sender { + if ([self.delegate respondsToSelector:@selector(postView:didReceiveReblogAction:)]) { + [self.delegate postView:self didReceiveReblogAction:sender]; + } +} + +- (void)commentAction:(id)sender { + if ([self.delegate respondsToSelector:@selector(postView:didReceiveCommentAction:)]) { + [self.delegate postView:self didReceiveCommentAction:sender]; + } +} + +- (void)likeAction:(id)sender { + if ([self.delegate respondsToSelector:@selector(postView:didReceiveLikeAction:)]) { + [self.delegate postView:self didReceiveLikeAction:sender]; + } +} + +- (void)linkAction:(id)sender { + if ([self.delegate respondsToSelector:@selector(postView:didReceiveLinkAction:)]) { + [self.delegate postView:self didReceiveLinkAction:sender]; + } +} + +- (void)linkImageAction:(id)sender { + if ([self.delegate respondsToSelector:@selector(postView:didReceiveImageLinkAction:)]) { + [self.delegate postView:self didReceiveImageLinkAction:sender]; + } +} + + #pragma mark - Instance Methods - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { diff --git a/WordPress/Classes/ReaderPostsViewController.h b/WordPress/Classes/ReaderPostsViewController.h index ff3826863860..c7d11e415005 100644 --- a/WordPress/Classes/ReaderPostsViewController.h +++ b/WordPress/Classes/ReaderPostsViewController.h @@ -8,7 +8,8 @@ #import #import "WPTableViewController.h" +#import "ReaderPostView.h" -@interface ReaderPostsViewController : WPTableViewController +@interface ReaderPostsViewController : WPTableViewController @end diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index 9ff95fb5bc6b..cf242c4d1fe4 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -28,7 +28,6 @@ #import "NSString+Helpers.h" #import "WPPopoverBackgroundView.h" #import "IOS7CorrectedTextView.h" -#import "ReaderPostView.h" static CGFloat const RPVCScrollingFastVelocityThreshold = 30.f; static CGFloat const RPVCHeaderHeightPhone = 10.f; @@ -338,10 +337,10 @@ - (void)loadImagesForVisibleRows { } -#pragma mark - Actions +#pragma mark - ReaderPostView delegate methods -- (void)reblogAction:(id)sender { - NSIndexPath *selectedPath = [self.tableView indexPathForSelectedRow]; +- (void)postView:(ReaderPostView *)postView didReceiveReblogAction:(id)sender { + NSIndexPath *selectedPath = [self.tableView indexPathForSelectedRow]; UITableViewCell *cell = [ReaderPostTableViewCell cellForSubview:sender]; NSIndexPath *path = [self.tableView indexPathForCell:cell]; @@ -360,9 +359,8 @@ - (void)reblogAction:(id)sender { } } -- (void)likeAction:(id)sender { - ReaderPostTableViewCell *cell = [ReaderPostTableViewCell cellForSubview:sender]; - ReaderPost *post = cell.post; +- (void)postView:(ReaderPostView *)postView didReceiveLikeAction:(id)sender { + ReaderPost *post = postView.post; [post toggleLikedWithSuccess:^{ if ([post.isLiked boolValue]) { [WPMobileStats trackEventForWPCom:StatsEventReaderLikedPost]; @@ -371,43 +369,16 @@ - (void)likeAction:(id)sender { } } failure:^(NSError *error) { DDLogError(@"Error Liking Post : %@", [error localizedDescription]); - [cell.postView updateControlBar]; + [postView updateControlBar]; }]; - [cell.postView updateControlBar]; -} - -- (void)topicsAction:(id)sender { - ReaderTopicsViewController *controller = [[ReaderTopicsViewController alloc] initWithStyle:UITableViewStyleGrouped]; - controller.delegate = self; - if (IS_IPAD) { - if (_popover) { - [self dismissPopover]; - return; - } - - _popover = [[UIPopoverController alloc] initWithContentViewController:controller]; - _popover.popoverBackgroundViewClass = [WPPopoverBackgroundView class]; - - UIBarButtonItem *shareButton; - if (IS_IOS7) { - // For iOS7 there is an added spacing element inserted before the share button to adjust the position of the button. - shareButton = [self.navigationItem.rightBarButtonItems objectAtIndex:1]; - } else { - shareButton = self.navigationItem.rightBarButtonItem; - } - [_popover presentPopoverFromBarButtonItem:shareButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; - } else { - UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller]; - navController.navigationBar.translucent = NO; - [self presentViewController:navController animated:YES completion:nil]; - } + [postView updateControlBar]; } -- (void)followAction:(id)sender { +- (void)postView:(ReaderPostView *)postView didReceiveFollowAction:(id)sender { UIButton *followButton = (UIButton *)sender; ReaderPostTableViewCell *cell = [ReaderPostTableViewCell cellForSubview:sender]; - ReaderPost *post = cell.post; + ReaderPost *post = postView.post; if (![post isFollowable]) return; @@ -422,13 +393,12 @@ - (void)followAction:(id)sender { }]; } -- (void)commentAction:(id)sender { +- (void)postView:(ReaderPostView *)postView didReceiveCommentAction:(id)sender { // TODO: allow commenting } -- (void)tagAction:(id)sender { - ReaderPostTableViewCell *cell = [ReaderPostTableViewCell cellForSubview:sender]; - ReaderPost *post = cell.post; +- (void)postView:(ReaderPostView *)postView didReceiveTagAction:(id)sender { + ReaderPost *post = postView.post; NSString *endpoint = [NSString stringWithFormat:@"read/tags/%@/posts", post.primaryTagSlug]; NSDictionary *dict = @{@"endpoint" : endpoint, @@ -439,6 +409,37 @@ - (void)tagAction:(id)sender { [self readerTopicChanged]; } + +#pragma mark - Actions + +- (void)topicsAction:(id)sender { + ReaderTopicsViewController *controller = [[ReaderTopicsViewController alloc] initWithStyle:UITableViewStyleGrouped]; + controller.delegate = self; + if (IS_IPAD) { + if (_popover) { + [self dismissPopover]; + return; + } + + _popover = [[UIPopoverController alloc] initWithContentViewController:controller]; + _popover.popoverBackgroundViewClass = [WPPopoverBackgroundView class]; + + UIBarButtonItem *shareButton; + if (IS_IOS7) { + // For iOS7 there is an added spacing element inserted before the share button to adjust the position of the button. + shareButton = [self.navigationItem.rightBarButtonItems objectAtIndex:1]; + } else { + shareButton = self.navigationItem.rightBarButtonItem; + } + [_popover presentPopoverFromBarButtonItem:shareButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; + } else { + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller]; + navController.navigationBar.translucent = NO; + [self presentViewController:navController animated:YES completion:nil]; + } +} + + #pragma mark - ReaderTextForm Delegate Methods - (void)readerTextFormDidSend:(ReaderTextFormView *)readerTextForm { @@ -492,7 +493,6 @@ - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { #pragma mark - WPTableViewSublass methods - - (NSString *)noResultsPrompt { NSString *prompt; NSString *endpoint = [ReaderPost currentEndpoint]; @@ -568,12 +568,8 @@ - (UITableViewCell *)newCell { ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:cellIdentifier]; if (cell == nil) { cell = [[ReaderPostTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; - [cell.postView.reblogButton addTarget:self action:@selector(reblogAction:) forControlEvents:UIControlEventTouchUpInside]; - [cell.postView.likeButton addTarget:self action:@selector(likeAction:) forControlEvents:UIControlEventTouchUpInside]; - [cell.postView.followButton addTarget:self action:@selector(followAction:) forControlEvents:UIControlEventTouchUpInside]; - [cell.postView.commentButton addTarget:self action:@selector(commentAction:) forControlEvents:UIControlEventTouchUpInside]; - [cell.postView.tagButton addTarget:self action:@selector(tagAction:) forControlEvents:UIControlEventTouchUpInside]; } + return cell; } @@ -588,6 +584,8 @@ - (void)configureCell:(UITableViewCell *)aCell atIndexPath:(NSIndexPath *)indexP ReaderPost *post = (ReaderPost *)[self.resultsController objectAtIndexPath:indexPath]; [cell configureCell:post]; [self setImageForPost:post forCell:cell indexPath:indexPath]; + + cell.postView.delegate = self; CGSize imageSize = cell.postView.avatarImageView.bounds.size; UIImage *image = [post cachedAvatarWithSize:imageSize]; From c78a31a47b7107042d7aea0b66b19a18d0d6ced6 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Fri, 22 Nov 2013 15:21:29 -0800 Subject: [PATCH 04/41] Make detail view use new delegate methods --- .../Classes/ReaderPostDetailViewController.m | 96 +++++++++++++------ WordPress/Classes/ReaderPostView.h | 2 +- WordPress/Classes/ReaderPostView.m | 6 +- WordPress/Classes/ReaderPostsViewController.m | 4 +- 4 files changed, 71 insertions(+), 37 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 53b9f1f6271c..054bb17e8836 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -419,37 +419,6 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N //[self updateToolbar]; } - -- (void)handleCommentButtonTapped:(id)sender { - if (_readerCommentFormView.window != nil) { - [self hideCommentForm]; - return; - } - - [self showCommentForm]; -} - - -- (void)handleLikeButtonTapped:(id)sender { - [self.post toggleLikedWithSuccess:^{ - - } failure:^(NSError *error) { - DDLogError(@"Error Liking Post : %@", [error localizedDescription]); - [self updateActionBar]; - }]; - [self updateActionBar]; -} - -- (void)handleReblogButtonTapped:(id)sender { - if (_isShowingReblogForm) { - [self hideReblogForm]; - return; - } - - [self showReblogForm]; -} - - - (void)handleShareButtonTapped:(id)sender { if (self.linkOptionsActionSheet) { @@ -653,6 +622,71 @@ - (void)handleKeyboardWillHide:(NSNotification *)notification { } +#pragma mark - ReaderPostView delegate methods + +- (void)postView:(ReaderPostView *)postView didReceiveReblogAction:(id)sender { + if (_isShowingReblogForm) { + [self hideReblogForm]; + return; + } + + [self showReblogForm]; +} + +- (void)postView:(ReaderPostView *)postView didReceiveLikeAction:(id)sender { + ReaderPost *post = postView.post; + [post toggleLikedWithSuccess:^{ + if ([post.isLiked boolValue]) { + [WPMobileStats trackEventForWPCom:StatsEventReaderLikedPost]; + } else { + [WPMobileStats trackEventForWPCom:StatsEventReaderUnlikedPost]; + } + } failure:^(NSError *error) { + DDLogError(@"Error Liking Post : %@", [error localizedDescription]); + [postView updateActionButtons]; + }]; + + [postView updateActionButtons]; +} + +- (void)postView:(ReaderPostView *)postView didReceiveFollowAction:(id)sender { + UIButton *followButton = (UIButton *)sender; + ReaderPost *post = postView.post; + + if (![post isFollowable]) + return; + + followButton.selected = ![post.isFollowing boolValue]; // Set it optimistically + [post toggleFollowingWithSuccess:^{ + } failure:^(NSError *error) { + DDLogError(@"Error Following Blog : %@", [error localizedDescription]); + [followButton setSelected:[post.isFollowing boolValue]]; + }]; +} + +- (void)postView:(ReaderPostView *)postView didReceiveCommentAction:(id)sender { + if (_readerCommentFormView.window != nil) { + [self hideCommentForm]; + return; + } + + [self showCommentForm]; +} + +- (void)postView:(ReaderPostView *)postView didReceiveTagAction:(id)sender { + // TODO: decide how to browse from the Reader detail view +// ReaderPost *post = postView.post; +// +// NSString *endpoint = [NSString stringWithFormat:@"read/tags/%@/posts", post.primaryTagSlug]; +// NSDictionary *dict = @{@"endpoint" : endpoint, +// @"title" : post.primaryTagName}; +// +// [[NSUserDefaults standardUserDefaults] setObject:dict forKey:ReaderCurrentTopicKey]; +// [[NSUserDefaults standardUserDefaults] synchronize]; +// [self readerTopicChanged]; +} + + #pragma mark - Sync methods - (NSDate *)lastSyncDate { diff --git a/WordPress/Classes/ReaderPostView.h b/WordPress/Classes/ReaderPostView.h index c12079e03ece..32158d6f3c69 100644 --- a/WordPress/Classes/ReaderPostView.h +++ b/WordPress/Classes/ReaderPostView.h @@ -37,7 +37,7 @@ - (id)initWithFrame:(CGRect)frame showFullContent:(BOOL)showFullContent; - (void)setFeaturedImage:(UIImage *)image; - (void)setAvatar:(UIImage *)avatar; -- (void)updateControlBar; +- (void)updateActionButtons; - (void)reset; - (void)configurePost:(ReaderPost *)post; - (void)updateLayout; diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index 8eed4f1f7973..859482273826 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -239,7 +239,7 @@ - (void)configurePost:(ReaderPost *)post { _reblogButton.userInteractionEnabled = ![post.isReblogged boolValue]; - [self updateControlBar]; + [self updateActionButtons]; } @@ -554,7 +554,7 @@ - (void)linkImageAction:(id)sender { #pragma mark - Instance Methods - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - [self updateControlBar]; + [self updateActionButtons]; } - (void)setAvatar:(UIImage *)avatar { @@ -584,7 +584,7 @@ - (void)setFeaturedImage:(UIImage *)image { self.cellImageView.image = image; } -- (void)updateControlBar { +- (void)updateActionButtons { if (!_post) return; diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index cf242c4d1fe4..d791e3fa895a 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -369,10 +369,10 @@ - (void)postView:(ReaderPostView *)postView didReceiveLikeAction:(id)sender { } } failure:^(NSError *error) { DDLogError(@"Error Liking Post : %@", [error localizedDescription]); - [postView updateControlBar]; + [postView updateActionButtons]; }]; - [postView updateControlBar]; + [postView updateActionButtons]; } - (void)postView:(ReaderPostView *)postView didReceiveFollowAction:(id)sender { From e11dbd56949f406847a0d6189c845f501b4cfb7f Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Fri, 22 Nov 2013 16:06:19 -0800 Subject: [PATCH 05/41] Move reader tap actions to delegate methods --- .../Classes/ReaderPostDetailViewController.h | 3 +- .../Classes/ReaderPostDetailViewController.m | 93 ++++++++++++++++++- WordPress/Classes/ReaderPostView.h | 1 + WordPress/Classes/ReaderPostView.m | 18 +++- 4 files changed, 109 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.h b/WordPress/Classes/ReaderPostDetailViewController.h index 2e251fb868dc..e0857737e0b9 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.h +++ b/WordPress/Classes/ReaderPostDetailViewController.h @@ -8,8 +8,9 @@ #import #import "ReaderPost.h" +#import "ReaderPostView.h" -@interface ReaderPostDetailViewController : UIViewController +@interface ReaderPostDetailViewController : UIViewController @property (nonatomic, strong) ReaderPost *post; @property (nonatomic, assign) BOOL showInlineActionBar; diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 054bb17e8836..258561520bb9 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -9,6 +9,7 @@ #import "ReaderPostDetailViewController.h" #import #import +#import #import #import "UIImageView+Gravatar.h" #import "WPActivityDefaults.h" @@ -20,7 +21,10 @@ #import "ReaderCommentFormView.h" #import "ReaderReblogFormView.h" #import "IOS7CorrectedTextView.h" -#import "ReaderPostView.h" +#import "ReaderImageView.h" +#import "ReaderVideoView.h" +#import "WPImageViewController.h" +#import "WPWebVideoViewController.h" NSInteger const ReaderCommentsToSync = 100; NSTimeInterval const ReaderPostDetailViewControllerRefreshTimeout = 300; // 5 minutes @@ -68,6 +72,7 @@ @implementation ReaderPostDetailViewController - (void)dealloc { _resultsController.delegate = nil; _tableView.delegate = nil; + _postView.delegate = nil; } @@ -227,6 +232,7 @@ - (void)buildHeader { CGFloat postHeight = [ReaderPostView heightForPost:self.post withWidth:self.view.frame.size.width]; self.postView = [[ReaderPostView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.tableView.frame.size.width, postHeight) showFullContent:YES]; + self.postView.delegate = self; [self.postView configurePost:self.post]; self.postView.backgroundColor = [UIColor whiteColor]; if (self.featuredImage) { @@ -621,6 +627,24 @@ - (void)handleKeyboardWillHide:(NSNotification *)notification { self.view.frame = frame; } +- (void)moviePlaybackDidFinish:(NSNotification *)notification { + // Obtain the reason why the movie playback finished + NSNumber *finishReason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey]; + + // Dismiss the view controller ONLY when the reason is not "playback ended" + if ([finishReason intValue] != MPMovieFinishReasonPlaybackEnded) { + MPMoviePlayerController *moviePlayer = [notification object]; + + // Remove this class from the observers + [[NSNotificationCenter defaultCenter] removeObserver:self + name:MPMoviePlayerPlaybackDidFinishNotification + object:moviePlayer]; + + // Dismiss the view controller + [[[WordPressAppDelegate sharedWordPressApplicationDelegate].window rootViewController] dismissViewControllerAnimated:YES completion:nil]; + } +} + #pragma mark - ReaderPostView delegate methods @@ -673,6 +697,73 @@ - (void)postView:(ReaderPostView *)postView didReceiveCommentAction:(id)sender { [self showCommentForm]; } +- (void)postView:(ReaderPostView *)postView didReceiveLinkAction:(id)sender { + WPWebViewController *controller = [[WPWebViewController alloc] init]; + [controller setUrl:((DTLinkButton *)sender).URL]; + [self.navigationController pushViewController:controller animated:YES]; +} + +- (void)postView:(ReaderPostView *)postView didReceiveImageLinkAction:(id)sender { + ReaderImageView *imageView = (ReaderImageView *)sender; + + if(imageView.linkURL) { + NSString *url = [imageView.linkURL absoluteString]; + + BOOL matched = NO; + NSArray *types = @[@".png", @".jpg", @".gif", @".jpeg"]; + for (NSString *type in types) { + if (NSNotFound != [url rangeOfString:type].location) { + matched = YES; + break; + } + } + + if (matched) { + UIViewController *controller = [[WPImageViewController alloc] initWithImage:imageView.image andURL:imageView.linkURL]; + controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + controller.modalPresentationStyle = UIModalPresentationFullScreen; + [self.navigationController presentViewController:controller animated:YES completion:nil]; + + //[WPImageViewController presentAsModalWithImage:imageView.image andURL:((ReaderImageView *)sender).linkURL]; + // [WPImageViewController presentAsModalWithURL:((ReaderImageView *)sender).linkURL]; + } else { + WPWebViewController *controller = [[WPWebViewController alloc] init]; + [controller setUrl:((ReaderImageView *)sender).linkURL]; + [self.navigationController pushViewController:controller animated:YES]; + } + } else { + [WPImageViewController presentAsModalWithImage:imageView.image]; + } +} + +- (void)postView:(ReaderPostView *)postView didReceiveVideoLinkAction:(id)sender { + ReaderVideoView *videoView = (ReaderVideoView *)sender; + if(videoView.contentType == ReaderVideoContentTypeVideo) { + + MPMoviePlayerViewController *controller = [[MPMoviePlayerViewController alloc] initWithContentURL:videoView.contentURL]; + // Remove the movie player view controller from the "playback did finish" notification observers + [[NSNotificationCenter defaultCenter] removeObserver:controller + name:MPMoviePlayerPlaybackDidFinishNotification + object:controller.moviePlayer]; + + // Register this class as an observer instead + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(moviePlaybackDidFinish:) + name:MPMoviePlayerPlaybackDidFinishNotification + object:controller.moviePlayer]; + + controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + controller.modalPresentationStyle = UIModalPresentationFormSheet; + [self.navigationController presentViewController:controller animated:YES completion:nil]; + + } else { + // Should either be an iframe, or an object embed. In either case a src attribute should have been parsed for the contentURL. + // Assume this is content we can show and try to load it. + WPWebVideoViewController *controller = [WPWebVideoViewController presentAsModalWithURL:videoView.contentURL]; + controller.title = (videoView.title != nil) ? videoView.title : @"Video"; + } +} + - (void)postView:(ReaderPostView *)postView didReceiveTagAction:(id)sender { // TODO: decide how to browse from the Reader detail view // ReaderPost *post = postView.post; diff --git a/WordPress/Classes/ReaderPostView.h b/WordPress/Classes/ReaderPostView.h index 32158d6f3c69..93ac0f557a25 100644 --- a/WordPress/Classes/ReaderPostView.h +++ b/WordPress/Classes/ReaderPostView.h @@ -22,6 +22,7 @@ - (void)postView:(ReaderPostView *)postView didReceiveCommentAction:(id)sender; - (void)postView:(ReaderPostView *)postView didReceiveLinkAction:(id)sender; - (void)postView:(ReaderPostView *)postView didReceiveImageLinkAction:(id)sender; +- (void)postView:(ReaderPostView *)postView didReceiveVideoLinkAction:(id)sender; @end @interface ReaderPostView : UIView { diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index 859482273826..b502c9497695 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -185,6 +185,10 @@ - (id)initWithFrame:(CGRect)frame showFullContent:(BOOL)showFullContent { - (void)dealloc { self.post = nil; + self.delegate = nil; + _textContentView.delegate = nil; + _mediaQueue.delegate = nil; + [_mediaQueue discardQueuedItems]; } - (void)configurePost:(ReaderPost *)post { @@ -544,12 +548,18 @@ - (void)linkAction:(id)sender { } } -- (void)linkImageAction:(id)sender { +- (void)imageLinkAction:(id)sender { if ([self.delegate respondsToSelector:@selector(postView:didReceiveImageLinkAction:)]) { [self.delegate postView:self didReceiveImageLinkAction:sender]; } } +- (void)videoLinkAction:(id)sender { + if ([self.delegate respondsToSelector:@selector(postView:didReceiveVideoLinkAction:)]) { + [self.delegate postView:self didReceiveVideoLinkAction:sender]; + } +} + #pragma mark - Instance Methods @@ -716,7 +726,7 @@ - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedT [button setImage:highlightImage forState:UIControlStateHighlighted]; // use normal push action for opening URL - [button addTarget:self action:@selector(handleLinkTapped:) forControlEvents:UIControlEventTouchUpInside]; + [button addTarget:self action:@selector(linkAction:) forControlEvents:UIControlEventTouchUpInside]; return button; } @@ -797,7 +807,7 @@ - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedT [_mediaArray addObject:imageView]; imageView.linkURL = attachment.hyperLinkURL; - [imageView addTarget:self action:@selector(handleImageLinkTapped:) forControlEvents:UIControlEventTouchUpInside]; + [imageView addTarget:self action:@selector(imageLinkAction:) forControlEvents:UIControlEventTouchUpInside]; if ([imageAttachment.image isKindOfClass:[UIImage class]]) { [imageView setImage:image]; @@ -861,7 +871,7 @@ - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedT }]; - [videoView addTarget:self action:@selector(handleVideoTapped:) forControlEvents:UIControlEventTouchUpInside]; + [videoView addTarget:self action:@selector(videoLinkAction:) forControlEvents:UIControlEventTouchUpInside]; return videoView; } From 12be3eaaea5b72e4c1a55a490749f1b127d6abfd Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Fri, 22 Nov 2013 16:07:44 -0800 Subject: [PATCH 06/41] Remove ReaderDetailView now that it has been generalized away --- WordPress/Classes/ReaderPostDetailView.h | 23 - WordPress/Classes/ReaderPostDetailView.m | 669 ------------------ WordPress/WordPress.xcodeproj/project.pbxproj | 6 - 3 files changed, 698 deletions(-) delete mode 100644 WordPress/Classes/ReaderPostDetailView.h delete mode 100644 WordPress/Classes/ReaderPostDetailView.m diff --git a/WordPress/Classes/ReaderPostDetailView.h b/WordPress/Classes/ReaderPostDetailView.h deleted file mode 100644 index 57caa02a24d6..000000000000 --- a/WordPress/Classes/ReaderPostDetailView.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// ReaderPostDetailView.h -// WordPress -// -// Created by Eric J on 5/24/13. -// Copyright (c) 2013 WordPress. All rights reserved. -// - -#import -#import "ReaderPost.h" - -@protocol ReaderPostDetailViewDelegate - -- (void)readerPostDetailViewLayoutChanged; - -@end - -@interface ReaderPostDetailView : UIView - -- (id)initWithFrame:(CGRect)frame post:(ReaderPost *)post delegate:(id)delegate; -- (void)updateLayout; - -@end diff --git a/WordPress/Classes/ReaderPostDetailView.m b/WordPress/Classes/ReaderPostDetailView.m deleted file mode 100644 index 72c0e3a4c6fc..000000000000 --- a/WordPress/Classes/ReaderPostDetailView.m +++ /dev/null @@ -1,669 +0,0 @@ -// -// ReaderPostDetailView.m -// WordPress -// -// Created by Eric J on 5/24/13. -// Copyright (c) 2013 WordPress. All rights reserved. -// - -#import "ReaderPostDetailView.h" -#import -#import -#import -#import "DTTiledLayerWithoutFade.h" -#import "ReaderMediaView.h" -#import "ReaderImageView.h" -#import "ReaderVideoView.h" -#import "WPImageViewController.h" -#import "WordPressAppDelegate.h" -#import "WPWebViewController.h" -#import "WPWebVideoViewController.h" -#import "UIImageView+Gravatar.h" -#import "UILabel+SuggestSize.h" -#import "ReaderPostsViewController.h" -#import "ReaderMediaQueue.h" - -#define ContentTextViewYOffset -32 - -@interface ReaderPostDetailView() { - BOOL _relayoutTextFlag; -} - -@property (nonatomic, strong) ReaderPost *post; -@property (nonatomic, strong) UIView *authorView; -@property (nonatomic, strong) UIImageView *avatarImageView; -@property (nonatomic, strong) UILabel *authorLabel; -@property (nonatomic, strong) UILabel *dateLabel; -@property (nonatomic, strong) UILabel *blogLabel; -@property (nonatomic, strong) UILabel *titleLabel; -@property (nonatomic, strong) UIButton *followButton; -@property (nonatomic, strong) DTAttributedTextContentView *textContentView; -@property (nonatomic, strong) NSMutableArray *mediaArray; -@property (nonatomic, strong) ReaderMediaQueue *mediaQueue; -@property (nonatomic, weak) iddelegate; - -- (void)_updateLayout; -- (void)updateAttributedString:(NSAttributedString *)attrString; -- (BOOL)updateMediaLayout:(ReaderMediaView *)mediaView; -- (void)handleAuthorViewTapped:(id)sender; -- (void)handleImageLinkTapped:(id)sender; -- (void)handleLinkTapped:(id)sender; -- (void)handleVideoTapped:(id)sender; -- (void)handleMediaViewLoaded:(ReaderMediaView *)mediaView; -- (void)handleFollowButtonTapped:(id)sender; -- (void)handleFollowButtonInteraction:(id)sender; -- (BOOL)isEmoji:(NSURL *)url; - -@end - -@implementation ReaderPostDetailView - -- (void)dealloc -{ - _textContentView.delegate = nil; - _mediaQueue.delegate = nil; - [_mediaQueue discardQueuedItems]; - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (id)initWithFrame:(CGRect)frame post:(ReaderPost *)post delegate:(id)delegate { - self = [super initWithFrame:frame]; - if (self) { - - self.post = post; - self.delegate = delegate; - - self.mediaArray = [NSMutableArray array]; - self.mediaQueue = [[ReaderMediaQueue alloc] initWithDelegate:self]; - - CGFloat width = frame.size.width; - CGFloat padding = 20.0f; - CGFloat labelWidth = width - 100.0f; - CGFloat labelHeight = 20.0f; - CGFloat avatarSize = 60.0f; - - self.authorView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, width, 80.0f)]; - _authorView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - [self addSubview:_authorView]; - - - UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; - button.frame = _authorView.frame; - [button addTarget:self action:@selector(handleAuthorViewTapped:) forControlEvents:UIControlEventTouchUpInside]; - [_authorView addSubview:button]; - - self.avatarImageView = [[UIImageView alloc] initWithFrame:CGRectMake(padding, padding, avatarSize, avatarSize)]; - _avatarImageView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin; - - if ([post avatar] != nil) { - [self.avatarImageView setImageWithURL:[NSURL URLWithString:[post avatar]] placeholderImage:[UIImage imageNamed:@"gravatar.jpg"]]; - } else { - NSString *img = ([post isWPCom]) ? @"wpcom_blavatar.png" : @"wporg_blavatar.png"; - [self.avatarImageView setImageWithURL:[self.avatarImageView blavatarURLForHost:[[NSURL URLWithString:post.blogURL] host]] placeholderImage:[UIImage imageNamed:img]]; - } - - [_authorView addSubview:_avatarImageView]; - - self.authorLabel = [[UILabel alloc] initWithFrame:CGRectMake(avatarSize + padding + 10.0f, padding, labelWidth, labelHeight)]; - _authorLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _authorLabel.backgroundColor = [UIColor clearColor]; - _authorLabel.font = [UIFont fontWithName:@"OpenSans" size:13.0f]; - _authorLabel.text = (self.post.author != nil) ? self.post.author : self.post.authorDisplayName; - _authorLabel.textColor = DTColorCreateWithHexString(@"404040"); - [_authorView addSubview:_authorLabel]; - - self.dateLabel = [[UILabel alloc] initWithFrame:CGRectMake(avatarSize + padding + 10.0f, padding + labelHeight, labelWidth, labelHeight)]; - _dateLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _dateLabel.backgroundColor = [UIColor clearColor]; - _dateLabel.font = [UIFont fontWithName:@"OpenSans" size:13.0f]; - _dateLabel.text = [NSString stringWithFormat:@"%@ on", [self.post prettyDateString]]; - _dateLabel.textColor = DTColorCreateWithHexString(@"404040"); - [_authorView addSubview:_dateLabel]; - - self.blogLabel = [[UILabel alloc] initWithFrame:CGRectMake(avatarSize + padding + 10.0f, padding + labelHeight * 2, labelWidth, labelHeight)]; - _blogLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _blogLabel.backgroundColor = [UIColor clearColor]; - _blogLabel.font = [UIFont fontWithName:@"OpenSans" size:13.0f]; - _blogLabel.text = self.post.blogName; - _blogLabel.textColor = DTColorCreateWithHexString(@"278dbc"); - [_authorView addSubview:_blogLabel]; - - CGRect followFrame = _blogLabel.frame; - followFrame.origin.y += 2.0f; - followFrame.size.height += 4.0f; - self.followButton = [UIButton buttonWithType:UIButtonTypeCustom]; - _followButton.frame = followFrame; // Arbitrary width and x. The height and y are correct. - [_followButton setSelected:[post.isFollowing boolValue]]; - _followButton.layer.cornerRadius = 3.0f; - _followButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; - _followButton.backgroundColor = [UIColor colorWithRed:234.0f/255.0f green:234.0f/255.0f blue:234.0f/255.0f alpha:1.0f]; - _followButton.titleLabel.font = [UIFont fontWithName:@"OpenSans-Bold" size:10.0f]; - NSString *followString = NSLocalizedString(@"Follow", @"Prompt to follow a blog."); - NSString *followedString = NSLocalizedString(@"Following", @"User is following the blog."); - // -[NSString uppercaseStringWithLocale:] available since iOS6 - if ([followString respondsToSelector:@selector(uppercaseStringWithLocale:)]) { - followString = [followString uppercaseStringWithLocale:[NSLocale currentLocale]]; - followedString = [followedString uppercaseStringWithLocale:[NSLocale currentLocale]]; - } else { - followString = [followString uppercaseString]; - followedString = [followedString uppercaseString]; - } - [_followButton setTitle:followString forState:UIControlStateNormal]; - [_followButton setTitle:followedString forState:UIControlStateSelected]; - [_followButton setImage:[UIImage imageNamed:@"reader-postaction-follow"] forState:UIControlStateNormal]; - [_followButton setImage:[UIImage imageNamed:@"reader-postaction-following"] forState:UIControlStateSelected]; - [_followButton setTitleColor:[UIColor colorWithRed:116.0f/255.0f green:116.0f/255.0f blue:116.0f/255.0f alpha:1.0f] forState:UIControlStateNormal]; - [_followButton addTarget:self action:@selector(handleFollowButtonInteraction:) forControlEvents:UIControlEventAllTouchEvents]; - [_followButton addTarget:self action:@selector(handleFollowButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; - - [_authorView addSubview:_followButton]; - - CGFloat contentY = _authorView.frame.size.height; - - if ([self.post.postTitle length]) { - CGRect titleFrame = CGRectMake(padding, contentY + padding, width - (padding * 2), 44.0f); - self.titleLabel = [[UILabel alloc] initWithFrame:titleFrame]; - _titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _titleLabel.backgroundColor = [UIColor whiteColor]; - _titleLabel.font = [WPStyleGuide largePostTitleFont]; - _titleLabel.textColor = [WPStyleGuide littleEddieGrey]; - _titleLabel.lineBreakMode = NSLineBreakByWordWrapping; - _titleLabel.numberOfLines = 0; - if (IS_IOS7) { - _titleLabel.attributedText = [[NSAttributedString alloc] initWithString:self.post.postTitle attributes:[WPStyleGuide largePostTitleAttributes]]; - } else { - _titleLabel.text = self.post.postTitle; - } - [self addSubview:_titleLabel]; - titleFrame.size.height = [_titleLabel suggestedSizeForWidth:_titleLabel.frame.size.width].height; - _titleLabel.frame = titleFrame; - contentY = titleFrame.origin.y + titleFrame.size.height; - } - - [DTAttributedTextContentView setLayerClass:[DTTiledLayerWithoutFade class]]; - self.textContentView = [[DTAttributedTextContentView alloc] initWithFrame:CGRectMake(0.0f, contentY + ContentTextViewYOffset, width, 100.0f)]; // Starting height is arbitrary - _textContentView.delegate = self; - _textContentView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _textContentView.backgroundColor = [UIColor whiteColor]; - _textContentView.edgeInsets = UIEdgeInsetsMake(0.0f, padding, 0.0f, padding); - _textContentView.shouldDrawImages = NO; - _textContentView.shouldDrawLinks = NO; - [self addSubview:_textContentView]; - - // There seems to be a bug with DTCoreText causing images on the first line to have a negative y origin. - // As a work around, let the first line always be empty. We shift the text view's origin to compensate. - NSString *str = [NSString stringWithFormat:@"

%@", self.post.content]; - [self updateAttributedString: [[NSAttributedString alloc] initWithHTMLData:[str dataUsingEncoding:NSUTF8StringEncoding] - options:[WPStyleGuide defaultDTCoreTextOptions] - documentAttributes:nil]]; - [self sendSubviewToBack:_textContentView]; - } - return self; -} - - -- (void)updateAttributedString:(NSAttributedString *)attrString { - _textContentView.attributedString = attrString; -} - - -- (void)layoutSubviews { - [super layoutSubviews]; - - NSString *str = _followButton.currentTitle; - CGSize sz = [str sizeWithFont:_followButton.titleLabel.font]; - [_followButton sizeToFit]; - sz = _followButton.frame.size; - sz.width += 5.0f; // just a little extra width so the text has better padding on the right. - - CGFloat desiredWidth = [_blogLabel.text sizeWithFont:_blogLabel.font].width; - CGFloat availableWidth = (_authorView.frame.size.width - _blogLabel.frame.origin.x) - 20.0f; - availableWidth -= (sz.width + 10.0f); - - CGRect frame = _blogLabel.frame; - frame.size.width = MIN(availableWidth, desiredWidth); - _blogLabel.frame = frame; - - frame = _followButton.frame; - frame.origin.x = _blogLabel.frame.origin.x + _blogLabel.frame.size.width + 5.0f; - frame.size.width = sz.width; - _followButton.frame = frame; - - // The first time layoutSubviews is called our text control will build all its custom attachments. We're - // rejecting the attachment frame desired by the text control and substituting our own. Because expected - // and actual frames differ, DTCoreText can end up redrawing text on top of the DTLinkButtons. A work - // around is to call updateLayout once after all custom attachments are created. - if (!_relayoutTextFlag) { - _relayoutTextFlag = YES; - [self performSelector:@selector(updateLayout) withObject:self afterDelay:.1]; - } -} - - -- (void)updateLayout { - // Figure out image sizes after orientation change. - for (ReaderMediaView *mediaView in _mediaArray) { - [self updateMediaLayout:mediaView]; - } - - if (_titleLabel) { - CGRect titleFrame = _titleLabel.frame; - titleFrame.size.height = [_titleLabel suggestedSizeForWidth:titleFrame.size.width].height; - titleFrame = CGRectIntegral(titleFrame); - _titleLabel.frame = titleFrame; - - CGRect contentFrame = _textContentView.frame; - contentFrame.origin.y = titleFrame.origin.y + titleFrame.size.height + ContentTextViewYOffset; - _textContentView.frame = contentFrame; - } - - // Then update the layout - // need to reset the layouter because otherwise we get the old framesetter or cached layout frames - _textContentView.layouter = nil; - - // layout might have changed due to image sizes - [_textContentView relayoutText]; - - [self _updateLayout]; -} - - -- (void)_updateLayout { - // Size the textContentView - CGRect frame = _textContentView.frame; - CGFloat height = [_textContentView suggestedFrameSizeToFitEntireStringConstraintedToWidth:frame.size.width].height; - frame.size.height = height; - _textContentView.frame = frame; - - frame = self.frame; - frame.size.height = height + _textContentView.frame.origin.y + 10.0f; // + bottom padding - self.frame = frame; - - [self.delegate readerPostDetailViewLayoutChanged]; -} - - -- (BOOL)updateMediaLayout:(ReaderMediaView *)imageView { - BOOL frameChanged = NO; - NSURL *url = imageView.contentURL; - - CGSize originalSize = imageView.frame.size; - CGSize viewSize = imageView.image.size; - - if ([self isEmoji:url]) { - CGFloat scale = [UIScreen mainScreen].scale; - viewSize.width *= scale; - viewSize.height *= scale; - } else { - CGFloat ratio = viewSize.width / viewSize.height; - CGFloat width = _textContentView.frame.size.width; - CGFloat availableWidth = _textContentView.frame.size.width - (_textContentView.edgeInsets.left + _textContentView.edgeInsets.right); - - viewSize.width = availableWidth; - - if (imageView.isShowingPlaceholder) { - viewSize.height = roundf(width / imageView.placeholderRatio); - } else { - viewSize.height = roundf(width / ratio); - } - - viewSize.height += imageView.edgeInsets.top; // account for the top edge inset. - } - - // Widths should always match - if (viewSize.height != originalSize.height) { - frameChanged = YES; - } - - NSPredicate *pred = [NSPredicate predicateWithFormat:@"contentURL == %@", url]; - - // update all attachments that matchin this URL (possibly multiple images with same size) - for (DTTextAttachment *attachment in [self.textContentView.layoutFrame textAttachmentsWithPredicate:pred]) { - attachment.originalSize = originalSize; - attachment.displaySize = viewSize; - } - - return frameChanged; -} - - -- (BOOL)isEmoji:(NSURL *)url { - return ([[url absoluteString] rangeOfString:@"wp.com/wp-includes/images/smilies"].location != NSNotFound); -} - -- (UINavigationController *)detailNavigationController { - return [[[WordPressAppDelegate sharedWordPressApplicationDelegate] readerPostsViewController] navigationController]; -} - - -- (void)handleFollowButtonInteraction:(id)sender { - [self setNeedsLayout]; -} - - -- (void)handleFollowButtonTapped:(id)sender { - self.followButton.selected = ![self.post.isFollowing boolValue]; // to fake the call. - [self setNeedsLayout]; - [self.post toggleFollowingWithSuccess:^{ - self.followButton.selected = [self.post.isFollowing boolValue]; // for good measure! - [self setNeedsLayout]; - } failure:^(NSError *error) { - DDLogError(@"Error Following Blog : %@", [error localizedDescription]); - [_followButton setSelected:self.post.isFollowing]; - [self setNeedsLayout]; - - NSString *title; - NSString *description; - if (self.post.isFollowing) { - title = NSLocalizedString(@"Could Not Unfollow Blog", @"Title of prompt. Says a blog could not be unfollowed."); - description = NSLocalizedString(@"There was a problem unfollowing this blog.", @"Prompts the user that there was a problem unfollowing a blog."); - } else { - title = NSLocalizedString(@"Could Not Follow Blog", @"Title of prompt. Says a blog could not be followed."); - description = NSLocalizedString(@"There was a problem following this blog.", @"Prompts the user there was a problem following a blog."); - } - - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title - message:description - delegate:nil - cancelButtonTitle:NSLocalizedString(@"OK", @"") - otherButtonTitles:nil]; - [alertView show]; - - }]; - [_followButton setSelected:self.post.isFollowing]; - [self setNeedsLayout]; -} - - -- (void)handleAuthorViewTapped:(id)sender { - WPWebViewController *controller = [[WPWebViewController alloc] init]; - [controller setUrl:[NSURL URLWithString:self.post.permaLink]]; - [[self detailNavigationController] pushViewController:controller animated:YES]; -} - - -- (void)handleImageLinkTapped:(id)sender { - ReaderImageView *imageView = (ReaderImageView *)sender; - - if(imageView.linkURL) { - NSString *url = [imageView.linkURL absoluteString]; - - BOOL matched = NO; - NSArray *types = @[@".png", @".jpg", @".gif", @".jpeg"]; - for (NSString *type in types) { - if (NSNotFound != [url rangeOfString:type].location) { - matched = YES; - break; - } - } - - if (matched) { - [WPImageViewController presentAsModalWithImage:imageView.image andURL:((ReaderImageView *)sender).linkURL]; -// [WPImageViewController presentAsModalWithURL:((ReaderImageView *)sender).linkURL]; - } else { - WPWebViewController *controller = [[WPWebViewController alloc] init]; - [controller setUrl:((ReaderImageView *)sender).linkURL]; - [[self detailNavigationController] pushViewController:controller animated:YES]; - } - } else { - [WPImageViewController presentAsModalWithImage:imageView.image]; - } -} - - -- (void)handleLinkTapped:(id)sender { - WPWebViewController *controller = [[WPWebViewController alloc] init]; - [controller setUrl:((DTLinkButton *)sender).URL]; - [[self detailNavigationController] pushViewController:controller animated:YES]; -} - - -- (void)handleVideoTapped:(id)sender { - ReaderVideoView *videoView = (ReaderVideoView *)sender; - if(videoView.contentType == ReaderVideoContentTypeVideo) { - - MPMoviePlayerViewController *controller = [[MPMoviePlayerViewController alloc] initWithContentURL:videoView.contentURL]; - // Remove the movie player view controller from the "playback did finish" notification observers - [[NSNotificationCenter defaultCenter] removeObserver:controller - name:MPMoviePlayerPlaybackDidFinishNotification - object:controller.moviePlayer]; - - // Register this class as an observer instead - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(handleMoviePlaybackFinishedNotification:) - name:MPMoviePlayerPlaybackDidFinishNotification - object:controller.moviePlayer]; - - controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; - controller.modalPresentationStyle = UIModalPresentationFormSheet; - [[[WordPressAppDelegate sharedWordPressApplicationDelegate].window rootViewController] presentViewController:controller animated:YES completion:nil]; - - } else { - // Should either be an iframe, or an object embed. In either case a src attribute should have been parsed for the contentURL. - // Assume this is content we can show and try to load it. - WPWebVideoViewController *controller = [WPWebVideoViewController presentAsModalWithURL:videoView.contentURL]; - controller.title = (videoView.title != nil) ? videoView.title : @"Video"; - } -} - - -- (void)handleMediaViewLoaded:(ReaderMediaView *)mediaView { - - BOOL frameChanged = [self updateMediaLayout:mediaView]; - - if (frameChanged) { - // need to reset the layouter because otherwise we get the old framesetter or cached layout frames - self.textContentView.layouter = nil; - - // layout might have changed due to image sizes - [self.textContentView relayoutText]; - - [self _updateLayout]; - } -} - - -- (void)handleMoviePlaybackFinishedNotification:(NSNotification *)notification { - // Obtain the reason why the movie playback finished - NSNumber *finishReason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey]; - - // Dismiss the view controller ONLY when the reason is not "playback ended" - if ([finishReason intValue] != MPMovieFinishReasonPlaybackEnded) { - MPMoviePlayerController *moviePlayer = [notification object]; - - // Remove this class from the observers - [[NSNotificationCenter defaultCenter] removeObserver:self - name:MPMoviePlayerPlaybackDidFinishNotification - object:moviePlayer]; - - // Dismiss the view controller - [[[WordPressAppDelegate sharedWordPressApplicationDelegate].window rootViewController] dismissViewControllerAnimated:YES completion:nil]; - } -} - - -#pragma mark - DTCoreAttributedTextContentView Delegate Methods - -- (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView viewForAttributedString:(NSAttributedString *)string frame:(CGRect)frame { - NSDictionary *attributes = [string attributesAtIndex:0 effectiveRange:nil]; - - NSURL *URL = [attributes objectForKey:DTLinkAttribute]; - NSString *identifier = [attributes objectForKey:DTGUIDAttribute]; - - DTLinkButton *button = [[DTLinkButton alloc] initWithFrame:frame]; - button.URL = URL; - button.minimumHitSize = CGSizeMake(25, 25); // adjusts it's bounds so that button is always large enough - button.GUID = identifier; - - // get image with normal link text - UIImage *normalImage = [attributedTextContentView contentImageWithBounds:frame options:DTCoreTextLayoutFrameDrawingDefault]; - [button setImage:normalImage forState:UIControlStateNormal]; - - // get image for highlighted link text - UIImage *highlightImage = [attributedTextContentView contentImageWithBounds:frame options:DTCoreTextLayoutFrameDrawingDrawLinksHighlighted]; - [button setImage:highlightImage forState:UIControlStateHighlighted]; - - // use normal push action for opening URL - [button addTarget:self action:@selector(handleLinkTapped:) forControlEvents:UIControlEventTouchUpInside]; - - return button; -} - - -- (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView viewForAttachment:(DTTextAttachment *)attachment frame:(CGRect)frame { - - CGFloat width = _textContentView.frame.size.width; - CGFloat availableWidth = _textContentView.frame.size.width - (_textContentView.edgeInsets.left + _textContentView.edgeInsets.right); - - // The ReaderImageView view will conform to the width constraints of the _textContentView. We want the image itself to run out to the edges, - // so position it offset by the inverse of _textContentView's edgeInsets. Also add top padding so we don't bump into a line of text. - // Remeber to add an extra 10px to the frame to preserve aspect ratio. - UIEdgeInsets edgeInsets = _textContentView.edgeInsets; - edgeInsets.left = 0.0f - edgeInsets.left; - edgeInsets.top = 15.0f; - edgeInsets.right = 0.0f - edgeInsets.right; - edgeInsets.bottom = 0.0f; - - if ([attachment isKindOfClass:[DTImageTextAttachment class]]) { - if ([self isEmoji:attachment.contentURL]) { - // minimal frame to suppress drawing context errors with 0 height or width. - frame.size.width = MAX(frame.size.width, 1.0f); - frame.size.height = MAX(frame.size.height, 1.0f); - ReaderImageView *imageView = [[ReaderImageView alloc] initWithFrame:frame]; - [_mediaArray addObject:imageView]; - [self.mediaQueue enqueueMedia:imageView - withURL:attachment.contentURL - placeholderImage:nil - size:CGSizeMake(15.0f, 15.0f) - isPrivate:self.post.isPrivate - success:nil - failure:nil]; - return imageView; - } - - DTImageTextAttachment *imageAttachment = (DTImageTextAttachment *)attachment; - UIImage *image; - - if( [imageAttachment.image isKindOfClass:[UIImage class]] ) { - image = imageAttachment.image; - - CGFloat ratio = image.size.width / image.size.height; - frame.size.width = availableWidth; - frame.size.height = roundf(width / ratio); - } else { - image = [UIImage imageNamed:@"wp_img_placeholder.png"]; - - if (frame.size.width > 1.0f && frame.size.height > 1.0f) { - CGFloat ratio = frame.size.width / frame.size.height; - frame.size.width = availableWidth; - frame.size.height = roundf(width / ratio); - } else { - frame.size.width = availableWidth; - frame.size.height = roundf(width * 0.66f); - } - } - - // offset the top edge inset keeping the image from bumping the text above it. - frame.size.height += edgeInsets.top; - - ReaderImageView *imageView = [[ReaderImageView alloc] initWithFrame:frame]; - imageView.contentMode = UIViewContentModeScaleAspectFit; - imageView.edgeInsets = edgeInsets; - - [_mediaArray addObject:imageView]; - imageView.linkURL = attachment.hyperLinkURL; - [imageView addTarget:self action:@selector(handleImageLinkTapped:) forControlEvents:UIControlEventTouchUpInside]; - - if ([imageAttachment.image isKindOfClass:[UIImage class]]) { - [imageView setImage:image]; - } else { - imageView.contentMode = UIViewContentModeCenter; - imageView.backgroundColor = [UIColor colorWithRed:192.0f/255.0f green:192.0f/255.0f blue:192.0f/255.0f alpha:1.0]; - - [self.mediaQueue enqueueMedia:imageView - withURL:attachment.contentURL - placeholderImage:image - size:CGSizeMake(width, 0) - isPrivate:self.post.isPrivate - success:^(ReaderMediaView *readerMediaView) { - ReaderImageView *imageView = (ReaderImageView *)readerMediaView; - imageView.contentMode = UIViewContentModeScaleAspectFit; - imageView.backgroundColor = [UIColor clearColor]; - } - failure:nil]; - } - - return imageView; - - } else { - - ReaderVideoContentType videoType; - - if ([attachment isKindOfClass:[DTVideoTextAttachment class]]) { - videoType = ReaderVideoContentTypeVideo; - } else if ([attachment isKindOfClass:[DTIframeTextAttachment class]]) { - videoType = ReaderVideoContentTypeIFrame; - } else if ([attachment isKindOfClass:[DTObjectTextAttachment class]]) { - videoType = ReaderVideoContentTypeEmbed; - } else { - return nil; // Can't handle whatever this is :P - } - - // make sure we have a reasonable size. - if (frame.size.width > width) { - if (frame.size.height == 0) { - frame.size.height = roundf(frame.size.width * 0.66f); - } - CGFloat ratio = frame.size.width / frame.size.height; - frame.size.width = availableWidth; - frame.size.height = roundf(width / ratio); - } - - // offset the top edge inset keeping the image from bumping the text above it. - frame.size.height += edgeInsets.top; - - ReaderVideoView *videoView = [[ReaderVideoView alloc] initWithFrame:frame]; - videoView.contentMode = UIViewContentModeCenter; - videoView.backgroundColor = [UIColor colorWithRed:192.0f/255.0f green:192.0f/255.0f blue:192.0f/255.0f alpha:1.0]; - videoView.edgeInsets = edgeInsets; - - [_mediaArray addObject:videoView]; - [videoView setContentURL:attachment.contentURL ofType:videoType success:^(id readerVideoView) { - [(ReaderVideoView *)readerVideoView setContentMode:UIViewContentModeScaleAspectFit]; - [self handleMediaViewLoaded:readerVideoView]; - } failure:^(id readerVideoView, NSError *error) { - [self handleMediaViewLoaded:readerVideoView]; - - }]; - - [videoView addTarget:self action:@selector(handleVideoTapped:) forControlEvents:UIControlEventTouchUpInside]; - - return videoView; - } - -} - -#pragma mark ReaderMediaQueueDelegate methods - -- (void)readerMediaQueue:(ReaderMediaQueue *)mediaQueue didLoadBatch:(NSArray *)batch { - BOOL frameChanged = NO; - - for (NSInteger i = 0; i < [batch count]; i++) { - ReaderMediaView *mediaView = [batch objectAtIndex:i]; - if ([self updateMediaLayout:mediaView]) { - frameChanged = YES; - } - } - - if (frameChanged) { - // need to reset the layouter because otherwise we get the old framesetter or cached layout frames - self.textContentView.layouter = nil; - - // layout might have changed due to image sizes - [self.textContentView relayoutText]; - - [self _updateLayout]; - } -} - -@end diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index bd00052850aa..5a447f64f437 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -363,7 +363,6 @@ 5D42A3F7175E75EE005CFF05 /* ReaderCommentTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D42A3E4175E75EE005CFF05 /* ReaderCommentTableViewCell.m */; }; 5D42A3F8175E75EE005CFF05 /* ReaderImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D42A3E6175E75EE005CFF05 /* ReaderImageView.m */; }; 5D42A3F9175E75EE005CFF05 /* ReaderMediaView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D42A3E8175E75EE005CFF05 /* ReaderMediaView.m */; }; - 5D42A3FA175E75EE005CFF05 /* ReaderPostDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D42A3EA175E75EE005CFF05 /* ReaderPostDetailView.m */; }; 5D42A3FB175E75EE005CFF05 /* ReaderPostDetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D42A3EC175E75EE005CFF05 /* ReaderPostDetailViewController.m */; }; 5D42A3FC175E75EE005CFF05 /* ReaderPostsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D42A3EE175E75EE005CFF05 /* ReaderPostsViewController.m */; }; 5D42A3FD175E75EE005CFF05 /* ReaderPostTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D42A3F0175E75EE005CFF05 /* ReaderPostTableViewCell.m */; }; @@ -1399,8 +1398,6 @@ 5D42A3E6175E75EE005CFF05 /* ReaderImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReaderImageView.m; sourceTree = ""; }; 5D42A3E7175E75EE005CFF05 /* ReaderMediaView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReaderMediaView.h; sourceTree = ""; }; 5D42A3E8175E75EE005CFF05 /* ReaderMediaView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReaderMediaView.m; sourceTree = ""; }; - 5D42A3E9175E75EE005CFF05 /* ReaderPostDetailView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReaderPostDetailView.h; sourceTree = ""; }; - 5D42A3EA175E75EE005CFF05 /* ReaderPostDetailView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReaderPostDetailView.m; sourceTree = ""; }; 5D42A3EB175E75EE005CFF05 /* ReaderPostDetailViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReaderPostDetailViewController.h; sourceTree = ""; }; 5D42A3EC175E75EE005CFF05 /* ReaderPostDetailViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReaderPostDetailViewController.m; sourceTree = ""; }; 5D42A3ED175E75EE005CFF05 /* ReaderPostsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReaderPostsViewController.h; sourceTree = ""; }; @@ -3832,8 +3829,6 @@ 5D42A3F4175E75EE005CFF05 /* ReaderTopicsViewController.m */, 5D42A3ED175E75EE005CFF05 /* ReaderPostsViewController.h */, 5D42A3EE175E75EE005CFF05 /* ReaderPostsViewController.m */, - 5D42A3E9175E75EE005CFF05 /* ReaderPostDetailView.h */, - 5D42A3EA175E75EE005CFF05 /* ReaderPostDetailView.m */, 5D42A3EB175E75EE005CFF05 /* ReaderPostDetailViewController.h */, 5D42A3EC175E75EE005CFF05 /* ReaderPostDetailViewController.m */, 46F8D7F9183C293200E10A38 /* ReaderPostView.h */, @@ -5208,7 +5203,6 @@ 462F4E0B18369F0B0028D2F8 /* BlogListViewController.m in Sources */, 5D42A3F9175E75EE005CFF05 /* ReaderMediaView.m in Sources */, 46F8D7FB183C293200E10A38 /* ReaderPostView.m in Sources */, - 5D42A3FA175E75EE005CFF05 /* ReaderPostDetailView.m in Sources */, 5D42A3FB175E75EE005CFF05 /* ReaderPostDetailViewController.m in Sources */, 5D42A3FC175E75EE005CFF05 /* ReaderPostsViewController.m in Sources */, 857F55B517CEA01A00E154E1 /* WPKeyboardToolbarBase.m in Sources */, From 8da2bfbc4c656c5bfd51a2e1b66910a820b08f91 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Sun, 24 Nov 2013 15:25:17 -0800 Subject: [PATCH 07/41] Fix some videos not opening properly inline --- WordPress/Classes/ReaderPostDetailViewController.m | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 258561520bb9..fa9d6dc04bcc 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -759,8 +759,13 @@ - (void)postView:(ReaderPostView *)postView didReceiveVideoLinkAction:(id)sender } else { // Should either be an iframe, or an object embed. In either case a src attribute should have been parsed for the contentURL. // Assume this is content we can show and try to load it. - WPWebVideoViewController *controller = [WPWebVideoViewController presentAsModalWithURL:videoView.contentURL]; - controller.title = (videoView.title != nil) ? videoView.title : @"Video"; + UIViewController *controller = [[WPWebVideoViewController alloc] initWithURL:videoView.contentURL]; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller]; + navController.navigationBar.translucent = NO; + navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + navController.modalPresentationStyle = UIModalPresentationFullScreen; + navController.title = (videoView.title != nil) ? videoView.title : @"Video"; + [self.navigationController presentViewController:navController animated:YES completion:nil]; } } From 7c865fff724e15edf24e0019cce0abad8d10baf3 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Sun, 24 Nov 2013 18:55:50 -0800 Subject: [PATCH 08/41] Replaced deprecated sizeWithFont --- WordPress/Classes/ReaderPostView.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index b502c9497695..1f1856965281 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -111,7 +111,11 @@ + (CGFloat)heightForPost:(ReaderPost *)post withWidth:(CGFloat)width { // Tag NSString *tagName = post.primaryTagName; if ([tagName length] > 0) { - desiredHeight += [tagName sizeWithFont:[self summaryFont] constrainedToSize:CGSizeMake(contentWidth, CGFLOAT_MAX) lineBreakMode:NSLineBreakByClipping].height; + CGRect tagRect = [tagName boundingRectWithSize:CGSizeMake(contentWidth, CGFLOAT_MAX) + options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading + attributes:@{NSFontAttributeName : [self summaryFont]} + context:nil]; + desiredHeight += tagRect.size.height; } // Padding above and below the line From ded137e112e5b7d48140c95ce19ae2b1ffa8aecd Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Sun, 24 Nov 2013 19:00:51 -0800 Subject: [PATCH 09/41] Code format cleanup --- .../Classes/ReaderPostDetailViewController.m | 57 +++++++------------ 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 2b0f10fe139b..972d274a8d13 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -73,10 +73,9 @@ - (void)dealloc { _postView.delegate = nil; } - - (id)initWithPost:(ReaderPost *)post featuredImage:(UIImage *)image { self = [super init]; - if(self) { + if (self) { self.post = post; self.comments = [NSMutableArray array]; self.featuredImage = image; @@ -119,7 +118,7 @@ - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; CGSize contentSize = self.tableView.contentSize; - if(contentSize.height > _savedScrollOffset.y) { + if (contentSize.height > _savedScrollOffset.y) { [self.tableView scrollRectToVisible:CGRectMake(_savedScrollOffset.x, _savedScrollOffset.y, 0.0f, 0.0f) animated:NO]; } else { [self.tableView scrollRectToVisible:CGRectMake(0.0f, contentSize.height, 0.0f, 0.0f) animated:NO]; @@ -147,9 +146,8 @@ - (void)viewDidAppear:(BOOL)animated { // Do not start auto-sync if connection is down WordPressAppDelegate *appDelegate = [WordPressAppDelegate sharedWordPressApplicationDelegate]; - if (appDelegate.connectionAvailable == NO) { + if (appDelegate.connectionAvailable == NO) return; - } NSDate *lastSynced = [self lastSyncDate]; if (lastSynced == nil || ABS([lastSynced timeIntervalSinceNow]) > ReaderPostDetailViewControllerRefreshTimeout) { @@ -184,16 +182,6 @@ - (void)viewDidUnload { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - return [super shouldAutorotateToInterfaceOrientation:interfaceOrientation]; -} - - -- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; -} - - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; @@ -231,9 +219,8 @@ - (void)buildHeader { } - (UIBarButtonItem *)shareButton { - if (_shareButton) { + if (_shareButton) return _shareButton; - } // Top Navigation bar and Sharing. if (IS_IOS7) { @@ -306,7 +293,8 @@ - (void)buildActionBar { } - (void)updateToolbar { - if (!self.post) return; + if (!self.post) + return; UIButton *btn = (UIButton *)_likeButton.customView; [btn setSelected:[self.post.isLiked boolValue]]; @@ -330,9 +318,7 @@ - (void)updateToolbar { } [items addObject:placeholder]; - [self setToolbarItems:items animated:YES]; - self.navigationController.toolbarHidden = NO; } @@ -361,15 +347,16 @@ - (void)buildForms { } - (UIActivityIndicatorView *)activityFooter { - if (_activityFooter) { + if (_activityFooter) return _activityFooter; - } + CGRect rect = CGRectMake(145.0f, 10.0f, 30.0f, 30.0f); _activityFooter = [[UIActivityIndicatorView alloc] initWithFrame:rect]; _activityFooter.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray; _activityFooter.hidesWhenStopped = YES; _activityFooter.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; [_activityFooter stopAnimating]; + return _activityFooter; } @@ -400,7 +387,7 @@ __block void(__unsafe_unretained ^flattenComments)(NSArray *) = ^void (NSArray * for (ReaderComment *comment in comments) { [_comments addObject:comment]; - if([comment.childComments count] > 0) { + if ([comment.childComments count] > 0) { flattenComments([comment.childComments allObjects]); } } @@ -507,7 +494,7 @@ - (void)showStoredComment { NSUInteger idx = [_comments indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { ReaderComment *c = (ReaderComment *)obj; - if([c.commentID integerValue] == cid) { + if ([c.commentID integerValue] == cid) { return YES; } return NO; @@ -520,9 +507,8 @@ - (void)showStoredComment { - (void)showCommentForm { [self hideReblogForm]; - if (_readerCommentFormView.superview != nil) { + if (_readerCommentFormView.superview != nil) return; - } NSIndexPath *path = [self.tableView indexPathForSelectedRow]; if (path) { @@ -542,9 +528,8 @@ - (void)showCommentForm { } - (void)hideCommentForm { - if(_readerCommentFormView.superview == nil) { + if (_readerCommentFormView.superview == nil) return; - } _readerCommentFormView.comment = nil; [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:NO]; @@ -561,9 +546,8 @@ - (void)hideCommentForm { - (void)showReblogForm { [self hideCommentForm]; - if (_readerReblogFormView.superview != nil) { + if (_readerReblogFormView.superview != nil) return; - } CGFloat reblogHeight = [ReaderReblogFormView desiredHeight]; CGRect tableFrame = self.tableView.frame; @@ -578,9 +562,8 @@ - (void)showReblogForm { } - (void)hideReblogForm { - if(_readerReblogFormView.superview == nil) { + if (_readerReblogFormView.superview == nil) return; - } [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:NO]; @@ -714,7 +697,7 @@ - (void)postView:(ReaderPostView *)postView didReceiveLinkAction:(id)sender { - (void)postView:(ReaderPostView *)postView didReceiveImageLinkAction:(id)sender { ReaderImageView *imageView = (ReaderImageView *)sender; - if(imageView.linkURL) { + if (imageView.linkURL) { NSString *url = [imageView.linkURL absoluteString]; BOOL matched = NO; @@ -746,7 +729,7 @@ - (void)postView:(ReaderPostView *)postView didReceiveImageLinkAction:(id)sender - (void)postView:(ReaderPostView *)postView didReceiveVideoLinkAction:(id)sender { ReaderVideoView *videoView = (ReaderVideoView *)sender; - if(videoView.contentType == ReaderVideoContentTypeVideo) { + if (videoView.contentType == ReaderVideoContentTypeVideo) { MPMoviePlayerViewController *controller = [[MPMoviePlayerViewController alloc] initWithContentURL:videoView.contentURL]; // Remove the movie player view controller from the "playback did finish" notification observers @@ -797,7 +780,6 @@ - (NSDate *)lastSyncDate { return self.post.dateCommentsSynced; } - - (void)syncWithUserInteraction:(BOOL)userInteraction { if ([self.post.postID integerValue] == 0 ) { // Weird that this should ever happen. self.post.dateCommentsSynced = [NSDate date]; @@ -817,9 +799,8 @@ - (void)syncWithUserInteraction:(BOOL)userInteraction { } - (void)loadMoreWithSuccess:(void (^)())success failure:(void (^)(NSError *error))failure { - if ([self.resultsController.fetchedObjects count] == 0) { + if ([self.resultsController.fetchedObjects count] == 0) return; - } if (_loadingMore) return; _loadingMore = YES; @@ -849,7 +830,7 @@ - (void)onSyncSuccess:(AFHTTPRequestOperation *)operation response:(id)responseO return; } - if([commentsArr count] < ([_comments count] + ReaderCommentsToSync)) { + if ([commentsArr count] < ([_comments count] + ReaderCommentsToSync)) { _hasMoreContent = NO; } From e126c6a64891c56326b8ddacfa1e8315f854a526 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Sun, 24 Nov 2013 19:02:10 -0800 Subject: [PATCH 10/41] Removed iOS6-specific code --- .../Classes/ReaderPostDetailViewController.m | 65 +++++-------------- 1 file changed, 16 insertions(+), 49 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 972d274a8d13..8ce1f3b391e0 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -128,14 +128,9 @@ - (void)viewWillAppear:(BOOL)animated { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; UIToolbar *toolbar = self.navigationController.toolbar; - if (IS_IOS7) { - toolbar.barTintColor = [WPStyleGuide littleEddieGrey]; - toolbar.tintColor = [UIColor whiteColor]; - toolbar.translucent = NO; - } else { - [toolbar setBackgroundImage:nil forToolbarPosition:UIToolbarPositionBottom barMetrics:UIBarMetricsDefault]; - [toolbar setTintColor:DTColorCreateWithHexString(@"F1F1F1")]; - } + toolbar.barTintColor = [WPStyleGuide littleEddieGrey]; + toolbar.tintColor = [UIColor whiteColor]; + toolbar.translucent = NO; [self.post addObserver:self forKeyPath:@"isReblogged" options:NSKeyValueObservingOptionNew context:@"reblogging"]; [self showStoredComment]; @@ -222,40 +217,20 @@ - (UIBarButtonItem *)shareButton { if (_shareButton) return _shareButton; - // Top Navigation bar and Sharing. - if (IS_IOS7) { - UIImage *image = [UIImage imageNamed:@"icon-posts-share"]; - UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)]; - [button setImage:image forState:UIControlStateNormal]; - [button addTarget:self action:@selector(handleShareButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; - _shareButton = [[UIBarButtonItem alloc] initWithCustomView:button]; - } else { - UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; - - [btn setImage:[UIImage imageNamed:@"navbar_actions.png"] forState:UIControlStateNormal]; - [btn setImage:[UIImage imageNamed:@"navbar_actions.png"] forState:UIControlStateHighlighted]; - - UIImage *backgroundImage = [[UIImage imageNamed:@"navbar_button_bg"] stretchableImageWithLeftCapWidth:4 topCapHeight:0]; - [btn setBackgroundImage:backgroundImage forState:UIControlStateNormal]; - - backgroundImage = [[UIImage imageNamed:@"navbar_button_bg_active"] stretchableImageWithLeftCapWidth:4 topCapHeight:0]; - [btn setBackgroundImage:backgroundImage forState:UIControlStateHighlighted]; - btn.frame = CGRectMake(0.0f, 0.0f, 44.0f, 30.0f); - [btn addTarget:self action:@selector(handleShareButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; - - _shareButton = [[UIBarButtonItem alloc] initWithCustomView:btn]; - } - return _shareButton; + // Top Navigation bar and Sharing + UIImage *image = [UIImage imageNamed:@"icon-posts-share"]; + UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)]; + [button setImage:image forState:UIControlStateNormal]; + [button addTarget:self action:@selector(handleShareButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; + _shareButton = [[UIBarButtonItem alloc] initWithCustomView:button]; + + return _shareButton; } - (void)buildActionBar { UIButton *commentBtn = [UIButton buttonWithType:UIButtonTypeCustom]; - if (IS_IOS7) { - [commentBtn setImage:[UIImage imageNamed:@"reader-postaction-comment"] forState:UIControlStateNormal]; - [commentBtn setImage:[UIImage imageNamed:@"reader-postaction-comment-active"] forState:UIControlStateHighlighted]; - } else { - [commentBtn setImage:[UIImage imageNamed:@"reader-postaction-comment-blue"] forState:UIControlStateNormal]; - } + [commentBtn setImage:[UIImage imageNamed:@"reader-postaction-comment"] forState:UIControlStateNormal]; + [commentBtn setImage:[UIImage imageNamed:@"reader-postaction-comment-active"] forState:UIControlStateHighlighted]; commentBtn.frame = CGRectMake(0.0f, 0.0f, 40.0f, 40.0f); [commentBtn addTarget:self action:@selector(handleCommentButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; self.commentButton = [[UIBarButtonItem alloc] initWithCustomView:commentBtn]; @@ -265,11 +240,7 @@ - (void)buildActionBar { [likeBtn setTitleEdgeInsets:UIEdgeInsetsMake(0.0f, -5.0f, 0.0f, 0.0f)]; [likeBtn setTitleColor:[UIColor colorWithRed:84.0f/255.0f green:173.0f/255.0f blue:211.0f/255.0f alpha:1.0f] forState:UIControlStateNormal]; [likeBtn setTitleColor:[UIColor colorWithRed:221.0f/255.0f green:118.0f/255.0f blue:43.0f/255.0f alpha:1.0f] forState:UIControlStateSelected]; - if (IS_IOS7) { - [likeBtn setImage:[UIImage imageNamed:@"reader-postaction-like"] forState:UIControlStateNormal]; - } else { - [likeBtn setImage:[UIImage imageNamed:@"reader-postaction-like-blue"] forState:UIControlStateNormal]; - } + [likeBtn setImage:[UIImage imageNamed:@"reader-postaction-like"] forState:UIControlStateNormal]; [likeBtn setImage:[UIImage imageNamed:@"reader-postaction-like-active"] forState:UIControlStateSelected]; likeBtn.frame = CGRectMake(0.0f, 0.0f, 60.0f, 40.0f); likeBtn.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; @@ -277,12 +248,8 @@ - (void)buildActionBar { self.likeButton = [[UIBarButtonItem alloc] initWithCustomView:likeBtn]; UIButton *reblogBtn = [UIButton buttonWithType:UIButtonTypeCustom]; - if (IS_IOS7) { - [reblogBtn setImage:[UIImage imageNamed:@"reader-postaction-reblog"] forState:UIControlStateNormal]; - [reblogBtn setImage:[UIImage imageNamed:@"reader-postaction-reblog-active"] forState:UIControlStateHighlighted]; - } else { - [reblogBtn setImage:[UIImage imageNamed:@"reader-postaction-reblog-blue"] forState:UIControlStateNormal]; - } + [reblogBtn setImage:[UIImage imageNamed:@"reader-postaction-reblog"] forState:UIControlStateNormal]; + [reblogBtn setImage:[UIImage imageNamed:@"reader-postaction-reblog-active"] forState:UIControlStateHighlighted]; [reblogBtn setImage:[UIImage imageNamed:@"reader-postaction-reblog-done"] forState:UIControlStateSelected]; reblogBtn.frame = CGRectMake(0.0f, 0.0f, 40.0f, 40.0f); reblogBtn.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; From 211d61c27e2917406159fc84ef0582d0e2aa3e61 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Sun, 24 Nov 2013 21:34:04 -0800 Subject: [PATCH 11/41] Don't allow selection of content 'row' --- WordPress/Classes/ReaderPostDetailViewController.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 8ce1f3b391e0..910c9ff0d7ca 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -922,6 +922,9 @@ - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NS } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + if (indexPath.section == ReaderDetailContentSection) + return; + if (![self canComment]) { [self.tableView deselectRowAtIndexPath:indexPath animated:NO]; return; @@ -944,9 +947,8 @@ - (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPat } - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { - if (indexPath.section == ReaderDetailContentSection) { + if (indexPath.section == ReaderDetailContentSection) return; - } if (IS_IPAD) { cell.accessoryType = UITableViewCellAccessoryNone; From 551b54659fe0306ddb549797eebb18aa86885aa9 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Mon, 25 Nov 2013 17:36:48 -0800 Subject: [PATCH 12/41] Made Reader detail display at narrower width on iPad --- .../Classes/ReaderPostDetailViewController.h | 2 +- .../Classes/ReaderPostDetailViewController.m | 23 +++++-------------- WordPress/Classes/ReaderPostView.m | 4 ++-- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.h b/WordPress/Classes/ReaderPostDetailViewController.h index 1bff5e0a2372..cff797640ea9 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.h +++ b/WordPress/Classes/ReaderPostDetailViewController.h @@ -11,7 +11,7 @@ #import "ReaderPost.h" #import "ReaderPostView.h" -@interface ReaderPostDetailViewController : UIViewController +@interface ReaderPostDetailViewController : UITableViewController @property (nonatomic, strong) ReaderPost *post; @property (nonatomic, assign) BOOL showInlineActionBar; diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 910c9ff0d7ca..3e142c615bf2 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -44,7 +44,6 @@ @interface ReaderPostDetailViewController () Date: Mon, 25 Nov 2013 18:59:15 -0800 Subject: [PATCH 13/41] Format fixes for iPad --- .../Classes/ReaderPostDetailViewController.m | 16 +++++++++++++++- WordPress/Classes/ReaderPostView.m | 1 + WordPress/Classes/ReaderPostsViewController.m | 4 ++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 3e142c615bf2..e2dbfd6da65b 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -25,6 +25,7 @@ #import "WPWebVideoViewController.h" #import "WPWebViewController.h" #import "ContextManager.h" +#import "WPTableViewController.h" NSInteger const ReaderCommentsToSync = 100; NSTimeInterval const ReaderPostDetailViewControllerRefreshTimeout = 300; // 5 minutes @@ -94,7 +95,9 @@ - (void)viewDidLoad { self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; [self.tableView registerClass:[WPTableViewCell class] forCellReuseIdentifier:@"PostCell"]; - + [WPStyleGuide configureColorsForView:self.view andTableView:self.tableView]; + self.tableView.backgroundColor = [UIColor whiteColor]; + [self buildHeader]; //[self buildTopToolbar]; [WPStyleGuide setRightBarButtonItemWithCorrectSpacing:self.shareButton forNavigationItem:self.navigationItem]; @@ -838,6 +841,17 @@ - (void)disableInfiniteScrolling { #pragma mark - UITableView Delegate Methods +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { + return [[UIView alloc] initWithFrame:CGRectZero]; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + if (section == 0) + return IS_IPHONE ? 1 : WPTableViewTopMargin; + + return kSectionHeaderHight; +} + - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.section == ReaderDetailContentSection) { return self.postView.frame.size.height; diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index 15e17ce3281b..85e1f4925072 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -495,6 +495,7 @@ - (void)layoutSubviews { // Update own frame CGRect ownFrame = self.frame; + ownFrame.size.width = contentWidth; ownFrame.size.height = nextY + RPVMetaViewHeight + 1; self.frame = ownFrame; } diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index 67686d25c3c5..7037154ebddd 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -761,6 +761,10 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa return [ReaderPostTableViewCell cellHeightForPost:[self.resultsController objectAtIndexPath:indexPath] withWidth:self.tableView.bounds.size.width]; } +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { + return [[UIView alloc] initWithFrame:CGRectZero]; +} + - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { if (IS_IPHONE) return RPVCHeaderHeightPhone; From 14aa7ea8829ea29d992ff57b5358927a56768777 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Mon, 25 Nov 2013 19:11:24 -0800 Subject: [PATCH 14/41] Remove KVO for isReblogged --- WordPress/Classes/ReaderPostDetailViewController.m | 9 --------- WordPress/Classes/ReaderPostTableViewCell.m | 6 ------ WordPress/Classes/ReaderPostView.m | 11 +---------- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index e2dbfd6da65b..bcab092e57f1 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -129,7 +129,6 @@ - (void)viewWillAppear:(BOOL)animated { toolbar.tintColor = [UIColor whiteColor]; toolbar.translucent = NO; - [self.post addObserver:self forKeyPath:@"isReblogged" options:NSKeyValueObservingOptionNew context:@"reblogging"]; [self showStoredComment]; } @@ -155,7 +154,6 @@ - (void)viewWillDisappear:(BOOL)animated { } [[NSNotificationCenter defaultCenter] removeObserver:self]; - [self.post removeObserver:self forKeyPath:@"isReblogged" context:@"reblogging"]; } - (void)viewDidUnload { @@ -401,13 +399,6 @@ - (void)updateActionBar { //[self setToolbarItems:items animated:YES]; } - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if ([keyPath isEqualToString:@"isReblogged"]) { - [self updateActionBar]; - } -} - - (void)handleShareButtonTapped:(id)sender { NSString *permaLink = self.post.permaLink; NSString *title = self.post.postTitle; diff --git a/WordPress/Classes/ReaderPostTableViewCell.m b/WordPress/Classes/ReaderPostTableViewCell.m index 0970dae61d41..faa42619c908 100644 --- a/WordPress/Classes/ReaderPostTableViewCell.m +++ b/WordPress/Classes/ReaderPostTableViewCell.m @@ -97,13 +97,7 @@ - (void)setPost:(ReaderPost *)post { return; self.postView.post = post; - - if (_post) { - [_post removeObserver:self forKeyPath:@"isReblogged" context:@"reblogging"]; - } - _post = post; - [_post addObserver:self forKeyPath:@"isReblogged" options:NSKeyValueObservingOptionNew context:@"reblogging"]; } - (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated { diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index 85e1f4925072..3373afbb8467 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -254,13 +254,8 @@ - (void)configurePost:(ReaderPost *)post { - (void)setPost:(ReaderPost *)post { if ([post isEqual:_post]) return; - - if (_post) { - [_post removeObserver:self forKeyPath:@"isReblogged" context:@"reblogging"]; - } - + _post = post; - [_post addObserver:self forKeyPath:@"isReblogged" options:NSKeyValueObservingOptionNew context:@"reblogging"]; } - (UIView *)buildContentView { @@ -568,10 +563,6 @@ - (void)videoLinkAction:(id)sender { #pragma mark - Instance Methods -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - [self updateActionButtons]; -} - - (void)setAvatar:(UIImage *)avatar { if (_avatarIsSet) return; From 32be7a54541bdaa84ea79ed346b41a1d55af8c4b Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 26 Nov 2013 01:04:59 -0800 Subject: [PATCH 15/41] Make image caching resilient to rounding and only use widths --- WordPress/Classes/WPTableImageSource.m | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/WordPress/Classes/WPTableImageSource.m b/WordPress/Classes/WPTableImageSource.m index b57885449b0b..144d69eac7bf 100644 --- a/WordPress/Classes/WPTableImageSource.m +++ b/WordPress/Classes/WPTableImageSource.m @@ -36,6 +36,10 @@ - (id)initWithMaxSize:(CGSize)size - (UIImage *)imageForURL:(NSURL *)url withSize:(CGSize)size { + // Force rounding and only cache based on width + size.width = ceilf(size.width); + size.height = 0; + UIImage *image = [self cachedImageForURL:url withSize:size]; if (image) { return image; @@ -180,11 +184,18 @@ - (UIImage *)resizeImage:(UIImage *)image toSize:(CGSize)size - (void)setCachedImage:(UIImage *)image forURL:(NSURL *)url withSize:(CGSize)size { + // Force rounding and only cache based on width + size.width = ceilf(size.width); + size.height = 0; + [_imageCache setObject:image forKey:[self cacheKeyForURL:url withSize:size]]; } - (UIImage *)cachedImageForURL:(NSURL *)url withSize:(CGSize)size { + size.width = ceilf(size.width); + size.height = 0; + return [_imageCache objectForKey:[self cacheKeyForURL:url withSize:size]]; } From fda45920311b3abfa7a999962781ca1cc8c677b5 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 26 Nov 2013 01:42:43 -0800 Subject: [PATCH 16/41] Various sizing fixes, disable scroll detection for now --- .../Classes/ReaderPostDetailViewController.m | 3 +- WordPress/Classes/ReaderPostView.m | 18 +++++--- WordPress/Classes/ReaderPostsViewController.m | 45 ++++++++++--------- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index bcab092e57f1..4079d04cc5c7 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -96,7 +96,6 @@ - (void)viewDidLoad { self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; [self.tableView registerClass:[WPTableViewCell class] forCellReuseIdentifier:@"PostCell"]; [WPStyleGuide configureColorsForView:self.view andTableView:self.tableView]; - self.tableView.backgroundColor = [UIColor whiteColor]; [self buildHeader]; //[self buildTopToolbar]; @@ -144,6 +143,8 @@ - (void)viewDidAppear:(BOOL)animated { if (lastSynced == nil || ABS([lastSynced timeIntervalSinceNow]) > ReaderPostDetailViewControllerRefreshTimeout) { [self syncWithUserInteraction:NO]; } + + [self.tableView reloadData]; } - (void)viewWillDisappear:(BOOL)animated { diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index 3373afbb8467..240e1a3ebb4b 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -176,7 +176,7 @@ - (id)initWithFrame:(CGRect)frame showFullContent:(BOOL)showFullContent { self.opaque = YES; self.showFullContent = showFullContent; - self.cellImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 44.0f, 44.0f)]; // arbitrary size. + self.cellImageView = [[UIImageView alloc] init]; _cellImageView.backgroundColor = [WPStyleGuide readGrey]; _cellImageView.contentMode = UIViewContentModeScaleAspectFill; _cellImageView.clipsToBounds = YES; @@ -248,7 +248,6 @@ - (void)configurePost:(ReaderPost *)post { _reblogButton.userInteractionEnabled = ![post.isReblogged boolValue]; [self updateActionButtons]; - } - (void)setPost:(ReaderPost *)post { @@ -396,7 +395,15 @@ - (void)buildMetaContent { - (void)layoutSubviews { [super layoutSubviews]; - CGFloat contentWidth = self.superview.frame.size.width; + CGFloat contentWidth; + + // On iPad, get the width from the cell instead in order to account for margins + if (IS_IPHONE) { + contentWidth = self.frame.size.width; + } else { + contentWidth = self.superview.frame.size.width; + } + CGFloat innerContentWidth = contentWidth - RPVHorizontalInnerPadding * 2; CGFloat nextY = RPVAuthorPadding; CGFloat height = 0.0f; @@ -490,12 +497,13 @@ - (void)layoutSubviews { // Update own frame CGRect ownFrame = self.frame; - ownFrame.size.width = contentWidth; + ownFrame.size.height = nextY + RPVMetaViewHeight + 1; self.frame = ownFrame; } - (void)reset { + self.post = nil; _avatarIsSet = NO; _bylineLabel.text = nil; @@ -790,7 +798,7 @@ - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedT frame.size.height = roundf(width / ratio); } else { frame.size.width = availableWidth; - frame.size.height = roundf(width * 0.66f); + frame.size.height = roundf(width * RPVMaxImageHeightPercentage); } } diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index 7037154ebddd..06c12294c958 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -94,8 +94,10 @@ - (void)viewDidLoad { CGFloat maxWidth = self.tableView.bounds.size.width; if (IS_IPHONE) { maxWidth = MAX(self.tableView.bounds.size.width, self.tableView.bounds.size.height); + } else { + maxWidth *= (1 - 2 * WPTableViewCellMarginPercentage); } - maxWidth -= 20.f; // Container frame + CGFloat maxHeight = maxWidth * RPVCMaxImageHeightPercentage; _featuredImageSource = [[WPTableImageSource alloc] initWithMaxSize:CGSizeMake(maxWidth, maxHeight)]; _featuredImageSource.delegate = self; @@ -173,7 +175,6 @@ - (void)viewWillAppear:(BOOL)animated { [self performSelector:@selector(showFriendFinderNudgeView:) withObject:self afterDelay:3.0]; self.title = [[[ReaderPost currentTopic] objectForKey:@"title"] capitalizedString]; - [self loadImagesForVisibleRows]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyboardDidShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; @@ -456,20 +457,22 @@ - (void)readerTextFormDidCancel:(ReaderTextFormView *)readerTextForm { - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat offset = self.tableView.contentOffset.y; + + // Disable fast scrolling detection for now // We just take a diff from the last known offset, as the approximation is good enough - CGFloat velocity = fabsf(offset - _lastOffset); - if (velocity > RPVCScrollingFastVelocityThreshold && self.isScrolling) { - _isScrollingFast = YES; - } else { - _isScrollingFast = NO; - } +// CGFloat velocity = fabsf(offset - _lastOffset); +// if (velocity > RPVCScrollingFastVelocityThreshold && self.isScrolling) { +// _isScrollingFast = YES; +// } else { +// _isScrollingFast = NO; +// } _lastOffset = offset; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [super scrollViewDidEndDecelerating:scrollView]; _isScrollingFast = NO; - [self loadImagesForVisibleRows]; + //[self loadImagesForVisibleRows]; NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow]; if (!selectedIndexPath) @@ -578,6 +581,7 @@ - (void)configureCell:(UITableViewCell *)aCell atIndexPath:(NSIndexPath *)indexP cell.accessoryType = UITableViewCellAccessoryNone; ReaderPost *post = (ReaderPost *)[self.resultsController objectAtIndexPath:indexPath]; + [cell configureCell:post]; [self setImageForPost:post forCell:cell indexPath:indexPath]; @@ -613,8 +617,13 @@ - (void)setImageForPost:(ReaderPost *)post forCell:(ReaderPostTableViewCell *)ce if (!imageURL) return; - CGSize imageSize = cell.postView.cellImageView.bounds.size; - UIImage *image = [self imageForURL:imageURL size: imageSize]; + // We know the width, but not the height; let the image loader figure that out + CGFloat imageWidth = self.tableView.frame.size.width; + if (IS_IPAD) { + imageWidth *= (1 - 2 * WPTableViewCellMarginPercentage); + } + CGSize imageSize = CGSizeMake(imageWidth, 0); + UIImage *image = [self imageForURL:imageURL size:imageSize]; if (image) { [cell.postView setFeaturedImage:image]; @@ -757,6 +766,10 @@ - (void)onSyncSuccess:(AFHTTPRequestOperation *)operation response:(id)responseO #pragma mark - #pragma mark TableView Methods +- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { + return [ReaderPostTableViewCell cellHeightForPost:[self.resultsController objectAtIndexPath:indexPath] withWidth:self.tableView.bounds.size.width]; +} + - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [ReaderPostTableViewCell cellHeightForPost:[self.resultsController objectAtIndexPath:indexPath] withWidth:self.tableView.bounds.size.width]; } @@ -797,7 +810,7 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath // Pass the image forward ReaderPost *post = [self.resultsController.fetchedObjects objectAtIndex:indexPath.row]; ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]; - CGSize imageSize = cell.postView.cellImageView.frame.size; + CGSize imageSize = cell.postView.cellImageView.image.size; UIImage *image = [_featuredImageSource imageForURL:post.featuredImageURL withSize:imageSize]; self.detailController = [[ReaderPostDetailViewController alloc] initWithPost:post featuredImage:image]; @@ -808,14 +821,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]; - - ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)aCell; - ReaderPost *post = (ReaderPost *)[self.resultsController objectAtIndexPath:indexPath]; - [self setImageForPost:post forCell:cell indexPath:indexPath]; -} - #pragma mark - ReaderTopicsDelegate Methods From 85f986f0559c39d35db95620231bb4145000ed46 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 26 Nov 2013 02:01:41 -0800 Subject: [PATCH 17/41] Override fetched results controller to prevent table updates from context merges (for now) --- WordPress/Classes/ReaderPostsViewController.m | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index 06c12294c958..6dd6ff5a021a 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -822,6 +822,26 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath } +#pragma mark - NSFetchedResultsController overrides + +- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { + // Do nothing (prevent superclass from adjusting table view) +} + +- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { + [self.tableView reloadData]; + [self.noResultsView removeFromSuperview]; +} + +- (void)controller:(NSFetchedResultsController *)controller + didChangeObject:(id)anObject + atIndexPath:(NSIndexPath *)indexPath + forChangeType:(NSFetchedResultsChangeType)type + newIndexPath:(NSIndexPath *)newIndexPath { + // Do nothing (prevent superclass from adjusting table view) +} + + #pragma mark - ReaderTopicsDelegate Methods - (void)readerTopicChanged { From ca8955bb157bfee4914dc95f0b9c5f0fed02156a Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 26 Nov 2013 09:05:34 -0800 Subject: [PATCH 18/41] Remove iOS6-specific code --- WordPress/Classes/ReaderPostsViewController.m | 50 ++++--------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index 6dd6ff5a021a..01e1645b306f 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -105,41 +105,18 @@ - (void)viewDidLoad { // Topics button UIBarButtonItem *button = nil; - if (IS_IOS7) { - UIButton *topicsButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [topicsButton setImage:[UIImage imageNamed:@"icon-reader-topics"] forState:UIControlStateNormal]; - [topicsButton setImage:[UIImage imageNamed:@"icon-reader-topics-active"] forState:UIControlStateHighlighted]; + UIButton *topicsButton = [UIButton buttonWithType:UIButtonTypeCustom]; + [topicsButton setImage:[UIImage imageNamed:@"icon-reader-topics"] forState:UIControlStateNormal]; + [topicsButton setImage:[UIImage imageNamed:@"icon-reader-topics-active"] forState:UIControlStateHighlighted]; - CGSize imageSize = [UIImage imageNamed:@"icon-reader-topics"].size; - topicsButton.frame = CGRectMake(0.0, 0.0, imageSize.width, imageSize.height); - - [topicsButton addTarget:self action:@selector(topicsAction:) forControlEvents:UIControlEventTouchUpInside]; - button = [[UIBarButtonItem alloc] initWithCustomView:topicsButton]; - } else { - UIButton *readButton = [UIButton buttonWithType:UIButtonTypeCustom]; - [readButton setImage:[UIImage imageNamed:@"navbar_read"] forState:UIControlStateNormal]; - - UIImage *backgroundImage = [[UIImage imageNamed:@"navbar_button_bg"] stretchableImageWithLeftCapWidth:4 topCapHeight:0]; - [readButton setBackgroundImage:backgroundImage forState:UIControlStateNormal]; - - backgroundImage = [[UIImage imageNamed:@"navbar_button_bg_active"] stretchableImageWithLeftCapWidth:4 topCapHeight:0]; - [readButton setBackgroundImage:backgroundImage forState:UIControlStateHighlighted]; - - readButton.frame = CGRectMake(0.0f, 0.0f, 44.0f, 30.0f); - - [readButton addTarget:self action:@selector(topicsAction:) forControlEvents:UIControlEventTouchUpInside]; - button = [[UIBarButtonItem alloc] initWithCustomView:readButton]; - } - - [button setAccessibilityLabel:NSLocalizedString(@"Topics", @"")]; + CGSize imageSize = [UIImage imageNamed:@"icon-reader-topics"].size; + topicsButton.frame = CGRectMake(0.0, 0.0, imageSize.width, imageSize.height); + topicsButton.contentEdgeInsets = UIEdgeInsetsMake(0, 16, 0, -16); - if (IS_IOS7) { - [WPStyleGuide setRightBarButtonItemWithCorrectSpacing:button forNavigationItem:self.navigationItem]; - } else { - UIColor *color = [UIColor UIColorFromHex:0x464646]; - button.tintColor = color; - [self.navigationItem setRightBarButtonItem:button animated:YES]; - } + [topicsButton addTarget:self action:@selector(topicsAction:) forControlEvents:UIControlEventTouchUpInside]; + button = [[UIBarButtonItem alloc] initWithCustomView:topicsButton]; + [button setAccessibilityLabel:NSLocalizedString(@"Topics", @"")]; + self.navigationItem.rightBarButtonItem = button; CGRect frame = CGRectMake(0.0f, self.view.bounds.size.height, self.view.bounds.size.width, [ReaderReblogFormView desiredHeight]); self.readerReblogFormView = [[ReaderReblogFormView alloc] initWithFrame:frame]; @@ -426,12 +403,7 @@ - (void)topicsAction:(id)sender { _popover.popoverBackgroundViewClass = [WPPopoverBackgroundView class]; UIBarButtonItem *shareButton; - if (IS_IOS7) { - // For iOS7 there is an added spacing element inserted before the share button to adjust the position of the button. - shareButton = [self.navigationItem.rightBarButtonItems objectAtIndex:1]; - } else { - shareButton = self.navigationItem.rightBarButtonItem; - } + shareButton = self.navigationItem.rightBarButtonItem; [_popover presentPopoverFromBarButtonItem:shareButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; } else { UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller]; From ad87de1db52fb57d182d75250bf90c66344722d5 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 26 Nov 2013 10:55:52 -0800 Subject: [PATCH 19/41] Change iPad tables to have a fixed and wider width --- WordPress/Classes/ReaderPostView.m | 2 +- WordPress/Classes/ReaderPostsViewController.m | 4 ++-- WordPress/Classes/WPTableViewCell.h | 2 +- WordPress/Classes/WPTableViewCell.m | 7 +++---- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index 240e1a3ebb4b..573a60551634 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -79,7 +79,7 @@ + (CGFloat)heightForPost:(ReaderPost *)post withWidth:(CGFloat)width { // Margins CGFloat contentWidth = width; if (IS_IPAD) { - contentWidth = contentWidth * (1 - WPTableViewCellMarginPercentage * 2); + contentWidth = WPTableViewFixedWidth; } desiredHeight += RPVAuthorPadding; diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index 01e1645b306f..ec52866ac52d 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -95,7 +95,7 @@ - (void)viewDidLoad { if (IS_IPHONE) { maxWidth = MAX(self.tableView.bounds.size.width, self.tableView.bounds.size.height); } else { - maxWidth *= (1 - 2 * WPTableViewCellMarginPercentage); + maxWidth = WPTableViewFixedWidth; } CGFloat maxHeight = maxWidth * RPVCMaxImageHeightPercentage; @@ -592,7 +592,7 @@ - (void)setImageForPost:(ReaderPost *)post forCell:(ReaderPostTableViewCell *)ce // We know the width, but not the height; let the image loader figure that out CGFloat imageWidth = self.tableView.frame.size.width; if (IS_IPAD) { - imageWidth *= (1 - 2 * WPTableViewCellMarginPercentage); + imageWidth = WPTableViewFixedWidth; } CGSize imageSize = CGSizeMake(imageWidth, 0); UIImage *image = [self imageForURL:imageURL size:imageSize]; diff --git a/WordPress/Classes/WPTableViewCell.h b/WordPress/Classes/WPTableViewCell.h index 2a739331307b..a8c8195155d1 100644 --- a/WordPress/Classes/WPTableViewCell.h +++ b/WordPress/Classes/WPTableViewCell.h @@ -8,7 +8,7 @@ #import -extern CGFloat const WPTableViewCellMarginPercentage; +extern CGFloat const WPTableViewFixedWidth; @interface WPTableViewCell : UITableViewCell diff --git a/WordPress/Classes/WPTableViewCell.m b/WordPress/Classes/WPTableViewCell.m index e2ac1b14331d..ae065c720e7f 100644 --- a/WordPress/Classes/WPTableViewCell.m +++ b/WordPress/Classes/WPTableViewCell.m @@ -8,16 +8,15 @@ #import "WPTableViewCell.h" -CGFloat const WPTableViewCellMarginPercentage = 0.2; +CGFloat const WPTableViewFixedWidth = 500; @implementation WPTableViewCell - (void)setFrame:(CGRect)frame { // On iPad, add a margin around tables if (IS_IPAD) { - CGFloat inset = ceilf(self.superview.frame.size.width * WPTableViewCellMarginPercentage); - frame.origin.x = inset; - frame.size.width = self.superview.frame.size.width - 2 * inset; + frame.origin.x = (self.superview.frame.size.width - WPTableViewFixedWidth) / 2; + frame.size.width = WPTableViewFixedWidth; } [super setFrame:frame]; } From 85f2cf69488cf9b8be767bc9cf0898b0e95ed3ba Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 26 Nov 2013 12:05:43 -0800 Subject: [PATCH 20/41] Make Reader comments narrower on iPad as well --- .../Classes/ReaderCommentTableViewCell.h | 3 ++- .../Classes/ReaderCommentTableViewCell.m | 5 +++-- .../Classes/ReaderPostDetailViewController.h | 2 +- .../Classes/ReaderPostDetailViewController.m | 20 ++++++++++++++++++- WordPress/Classes/WPTableViewCell.m | 9 +++++++++ 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/WordPress/Classes/ReaderCommentTableViewCell.h b/WordPress/Classes/ReaderCommentTableViewCell.h index ea9589f83cd6..b64586cc9dec 100644 --- a/WordPress/Classes/ReaderCommentTableViewCell.h +++ b/WordPress/Classes/ReaderCommentTableViewCell.h @@ -9,8 +9,9 @@ #import #import "ReaderTableViewCell.h" #import "ReaderComment.h" +#import "WPTableViewCell.h" -@interface ReaderCommentTableViewCell : UITableViewCell +@interface ReaderCommentTableViewCell : WPTableViewCell @property (nonatomic, strong) UIImageView *cellImageView; + (NSAttributedString *)convertHTMLToAttributedString:(NSString *)html withOptions:(NSDictionary *)options; diff --git a/WordPress/Classes/ReaderCommentTableViewCell.m b/WordPress/Classes/ReaderCommentTableViewCell.m index e993c92b4515..13d1085117c5 100644 --- a/WordPress/Classes/ReaderCommentTableViewCell.m +++ b/WordPress/Classes/ReaderCommentTableViewCell.m @@ -165,8 +165,9 @@ - (void)layoutSubviews { // We have to manually update the indentation of the content view? wtf. CGRect frame = self.contentView.frame; - frame.origin.x += (self.indentationWidth * self.indentationLevel); - frame.size.width -= frame.origin.x; + CGFloat indent = self.indentationWidth * self.indentationLevel; + frame.origin.x += indent; + frame.size.width -= indent; self.contentView.frame = frame; [self.cellImageView setFrame:CGRectMake(10.0f, 10.0f, 20.0f, 20.0f)]; diff --git a/WordPress/Classes/ReaderPostDetailViewController.h b/WordPress/Classes/ReaderPostDetailViewController.h index cff797640ea9..72ca4fb82254 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.h +++ b/WordPress/Classes/ReaderPostDetailViewController.h @@ -11,7 +11,7 @@ #import "ReaderPost.h" #import "ReaderPostView.h" -@interface ReaderPostDetailViewController : UITableViewController +@interface ReaderPostDetailViewController : UITableViewController @property (nonatomic, strong) ReaderPost *post; @property (nonatomic, assign) BOOL showInlineActionBar; diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 4079d04cc5c7..f79d4d78e6fe 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -852,10 +852,12 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa if ([_comments count] == 0) { return 0.0f; } + + CGFloat width = IS_IPAD ? WPTableViewFixedWidth : tableView.frame.size.width; ReaderComment *comment = [_comments objectAtIndex:indexPath.row]; return [ReaderCommentTableViewCell heightForComment:comment - width:tableView.frame.size.width + width:width tableStyle:tableView.style accessoryType:UITableViewCellAccessoryNone]; } @@ -1073,6 +1075,8 @@ - (NSFetchedResultsController *)resultsController { managedObjectContext:moc sectionNameKeyPath:nil cacheName:nil]; + + _resultsController.delegate = self; NSError *error = nil; if (![_resultsController performFetch:&error]) { @@ -1083,6 +1087,20 @@ - (NSFetchedResultsController *)resultsController { return _resultsController; } +- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { +} + +- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { + [self.tableView reloadData]; +} + +- (void)controller:(NSFetchedResultsController *)controller + didChangeObject:(id)anObject + atIndexPath:(NSIndexPath *)indexPath + forChangeType:(NSFetchedResultsChangeType)type + newIndexPath:(NSIndexPath *)newIndexPath { +} + #pragma mark - MFMailComposeViewControllerDelegate diff --git a/WordPress/Classes/WPTableViewCell.m b/WordPress/Classes/WPTableViewCell.m index ae065c720e7f..aa072c00d4a6 100644 --- a/WordPress/Classes/WPTableViewCell.m +++ b/WordPress/Classes/WPTableViewCell.m @@ -21,4 +21,13 @@ - (void)setFrame:(CGRect)frame { [super setFrame:frame]; } +- (void)layoutSubviews { + // Need to set the origin again on iPad (for margins) + if (IS_IPAD) { + CGRect frame = self.frame; + frame.origin.x = (self.superview.frame.size.width - WPTableViewFixedWidth) / 2; + self.frame = frame; + } +} + @end From 94b9f9ff056a0b22680ded6d98aefb5223bb0a60 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 26 Nov 2013 12:38:40 -0800 Subject: [PATCH 21/41] Fix comment form not displaying correctly --- .../Classes/ReaderPostDetailViewController.m | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index f79d4d78e6fe..d1c86dba24ee 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -477,7 +477,7 @@ - (void)showCommentForm { CGFloat y = tableFrame.origin.y + tableFrame.size.height; _readerCommentFormView.frame = CGRectMake(0.0f, y, self.view.bounds.size.width, formHeight); - [self.view addSubview:_readerCommentFormView]; + [self.view.superview addSubview:_readerCommentFormView]; self.isShowingCommentForm = YES; [_readerCommentFormView.textView becomeFirstResponder]; } @@ -511,7 +511,7 @@ - (void)showReblogForm { CGFloat y = tableFrame.origin.y + tableFrame.size.height; _readerReblogFormView.frame = CGRectMake(0.0f, y, self.view.bounds.size.width, reblogHeight); - [self.view addSubview:_readerReblogFormView]; + [self.view.superview addSubview:_readerReblogFormView]; self.isShowingReblogForm = YES; [_readerReblogFormView.textView becomeFirstResponder]; } @@ -531,46 +531,58 @@ - (void)hideReblogForm { [self.view endEditing:YES]; } +- (CGSize)tabBarSize { + CGSize tabBarSize = CGSizeZero; + if ([self tabBarController]) { + tabBarSize = [[[self tabBarController] tabBar] bounds].size; + } + + return tabBarSize; +} + - (void)handleKeyboardDidShow:(NSNotification *)notification { - CGRect frame = self.view.frame; + UIView *view = self.view.superview; + CGRect frame = view.frame; CGRect startFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue]; CGRect endFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; // Figure out the difference between the bottom of this view, and the top of the keyboard. // This should account for any toolbars. - CGPoint point = [self.view.window convertPoint:startFrame.origin toView:self.view]; - _keyboardOffset = point.y - (frame.origin.y + frame.size.height); + CGPoint point = [view.window convertPoint:startFrame.origin toView:view]; + self.keyboardOffset = point.y - (frame.origin.y + frame.size.height); // if we're upside down, we need to adjust the origin. if (endFrame.origin.x == 0 && endFrame.origin.y == 0) { endFrame.origin.y = endFrame.origin.x += MIN(endFrame.size.height, endFrame.size.width); } - point = [self.view.window convertPoint:endFrame.origin toView:self.view]; - frame.size.height = point.y; + point = [view.window convertPoint:endFrame.origin toView:view]; + CGSize tabBarSize = [self tabBarSize]; + frame.size.height = point.y + tabBarSize.height; [UIView animateWithDuration:0.3f delay:0.0f options:UIViewAnimationOptionBeginFromCurrentState animations:^{ - self.view.frame = frame; + view.frame = frame; } completion:^(BOOL finished) { // BUG: When dismissing a modal view, and the keyboard is showing again, the animation can get clobbered in some cases. // When this happens the view is set to the dimensions of its wrapper view, hiding content that should be visible // above the keyboard. // For now use a fallback animation. - if (!CGRectEqualToRect(self.view.frame, frame)) { + if (!CGRectEqualToRect(view.frame, frame)) { [UIView animateWithDuration:0.3 animations:^{ - self.view.frame = frame; + view.frame = frame; }]; } }]; } - (void)handleKeyboardWillHide:(NSNotification *)notification { - CGRect frame = self.view.frame; + UIView *view = self.view.superview; + CGRect frame = view.frame; CGRect keyFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; - CGPoint point = [self.view.window convertPoint:keyFrame.origin toView:self.view]; - frame.size.height = point.y - (frame.origin.y + _keyboardOffset); - self.view.frame = frame; + CGPoint point = [view.window convertPoint:keyFrame.origin toView:view]; + frame.size.height = point.y - (frame.origin.y + self.keyboardOffset); + view.frame = frame; } - (void)moviePlaybackDidFinish:(NSNotification *)notification { From 9a6132708ddb31f356def232e85b8778216ccc2d Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 26 Nov 2013 13:18:47 -0800 Subject: [PATCH 22/41] Changed detail view background colors --- WordPress/Classes/ReaderCommentTableViewCell.m | 16 +++++++--------- .../Classes/ReaderPostDetailViewController.m | 4 +--- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/WordPress/Classes/ReaderCommentTableViewCell.m b/WordPress/Classes/ReaderCommentTableViewCell.m index 13d1085117c5..944465cc0630 100644 --- a/WordPress/Classes/ReaderCommentTableViewCell.m +++ b/WordPress/Classes/ReaderCommentTableViewCell.m @@ -96,17 +96,15 @@ + (NSAttributedString *)convertHTMLToAttributedString:(NSString *)html withOptio - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { - - UIColor *color = DTColorCreateWithHexString(@"EFEFEF"); CGFloat width = self.frame.size.width; - self.backgroundColor = color; + self.backgroundColor = [UIColor whiteColor]; [self.cellImageView setFrame:CGRectMake(10.0f, 10.0f, 20.0f, 20.0f)]; self.cellImageView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin; self.textContentView = [[DTAttributedTextContentView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.frame.size.width, 44.0f)]; _textContentView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _textContentView.backgroundColor = color; + _textContentView.backgroundColor = [UIColor clearColor]; _textContentView.edgeInsets = UIEdgeInsetsMake(0.0f, 10.0f, 0.0f, 10.0f); _textContentView.delegate = self; _textContentView.shouldDrawImages = NO; @@ -118,14 +116,14 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus _dateLabel.textColor = [WPStyleGuide littleEddieGrey]; _dateLabel.textAlignment = NSTextAlignmentRight; _dateLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; - _dateLabel.backgroundColor = color; + _dateLabel.backgroundColor = [UIColor clearColor]; [self.contentView addSubview:_dateLabel]; - self.authorLabel = [[UILabel alloc] initWithFrame:CGRectMake(40.0f, 10.0f, (_dateLabel.frame.origin.x - 50.0f), 20.0f)]; + self.authorLabel = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 10.0f, (_dateLabel.frame.origin.x - 50.0f), 20.0f)]; [_authorLabel setFont:[WPStyleGuide subtitleFont]]; _authorLabel.textColor = [WPStyleGuide littleEddieGrey]; _authorLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; - _authorLabel.backgroundColor = color; + _authorLabel.backgroundColor = [UIColor clearColor]; [self.contentView addSubview:_authorLabel]; UIImageView *separatorImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell-separator"]]; @@ -135,14 +133,14 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus self.textContentView.frame = CGRectMake(0.0f, _authorLabel.frame.size.height + 10.0f, width, 44.0f); - UIView *view = [[UIView alloc] initWithFrame:self.bounds]; + UIView *view = [[UIView alloc] initWithFrame:self.frame]; view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; view.backgroundColor = DTColorCreateWithHexString(@"A9E2F3"); CGRect rect = CGRectMake(0, 0, 1, 1); UIGraphicsBeginImageContext(rect.size); CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, [color CGColor]); + CGContextSetFillColorWithColor(context, [[UIColor whiteColor] CGColor]); CGContextFillRect(context, rect); UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index d1c86dba24ee..d7de7c9610a1 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -96,6 +96,7 @@ - (void)viewDidLoad { self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; [self.tableView registerClass:[WPTableViewCell class] forCellReuseIdentifier:@"PostCell"]; [WPStyleGuide configureColorsForView:self.view andTableView:self.tableView]; + self.tableView.backgroundColor = [UIColor whiteColor]; [self buildHeader]; //[self buildTopToolbar]; @@ -356,9 +357,6 @@ __block void(__unsafe_unretained ^flattenComments)(NSArray *) = ^void (NSArray * }; flattenComments(self.resultsController.fetchedObjects); - if ([_comments count] > 0) { - self.tableView.backgroundColor = DTColorCreateWithHexString(@"EFEFEF"); - } // Cache attributed strings. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL), ^{ From dbc7195c7e638a4f69bf2546e763795c94f63c1e Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 26 Nov 2013 13:45:56 -0800 Subject: [PATCH 23/41] Fix cell contentView not being sized --- WordPress/Classes/WPTableViewCell.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WordPress/Classes/WPTableViewCell.m b/WordPress/Classes/WPTableViewCell.m index aa072c00d4a6..43cb39c419dc 100644 --- a/WordPress/Classes/WPTableViewCell.m +++ b/WordPress/Classes/WPTableViewCell.m @@ -22,6 +22,8 @@ - (void)setFrame:(CGRect)frame { } - (void)layoutSubviews { + [super layoutSubviews]; + // Need to set the origin again on iPad (for margins) if (IS_IPAD) { CGRect frame = self.frame; From f42bcbf5bc25475cfb396b51953533fd1f868282 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 26 Nov 2013 15:39:41 -0800 Subject: [PATCH 24/41] Changed Reader comment design --- .../Classes/ReaderCommentTableViewCell.m | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/WordPress/Classes/ReaderCommentTableViewCell.m b/WordPress/Classes/ReaderCommentTableViewCell.m index 944465cc0630..8bd923472adb 100644 --- a/WordPress/Classes/ReaderCommentTableViewCell.m +++ b/WordPress/Classes/ReaderCommentTableViewCell.m @@ -14,7 +14,7 @@ #import "NSDate+StringFormatting.h" #define RCTVCVerticalPadding 5.0f -#define RCTVCIndentationWidth 10.0f +#define RCTVCIndentationWidth 15.0f #define RCTVCAuthorLabelHeight 20.0f @interface ReaderCommentTableViewCell() @@ -97,7 +97,7 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { CGFloat width = self.frame.size.width; - self.backgroundColor = [UIColor whiteColor]; + self.backgroundColor = [WPStyleGuide itsEverywhereGrey]; [self.cellImageView setFrame:CGRectMake(10.0f, 10.0f, 20.0f, 20.0f)]; self.cellImageView.autoresizingMask = UIViewAutoresizingFlexibleRightMargin; @@ -126,8 +126,8 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus _authorLabel.backgroundColor = [UIColor clearColor]; [self.contentView addSubview:_authorLabel]; - UIImageView *separatorImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell-separator"]]; - separatorImageView.frame = CGRectMake(0.0f, 0.0f, width, 2.0f); + UIImageView *separatorImageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.indentationWidth, 0.0f, width - self.indentationWidth, 1.0f)]; + separatorImageView.backgroundColor = [UIColor colorWithHexString:@"e5e5e5"]; separatorImageView.autoresizingMask = UIViewAutoresizingFlexibleWidth; [self.contentView addSubview:separatorImageView]; @@ -135,21 +135,7 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus UIView *view = [[UIView alloc] initWithFrame:self.frame]; view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - view.backgroundColor = DTColorCreateWithHexString(@"A9E2F3"); - - CGRect rect = CGRectMake(0, 0, 1, 1); - UIGraphicsBeginImageContext(rect.size); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, [[UIColor whiteColor] CGColor]); - CGContextFillRect(context, rect); - UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - - UIView *colorView = [[UIImageView alloc] initWithImage:img]; - colorView.frame = CGRectMake(0.0f, 0.0f, width, 2.0f); - colorView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - - [view addSubview:colorView]; + view.backgroundColor = DTColorCreateWithHexString(@"e5e5e5"); [self setSelectedBackgroundView:view]; } From 0814a8a75366118f94c3682a452441a3556e8856 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 26 Nov 2013 17:44:28 -0800 Subject: [PATCH 25/41] Remove logic for loading visible images --- WordPress/Classes/ReaderPostsViewController.m | 52 +++++-------------- 1 file changed, 14 insertions(+), 38 deletions(-) diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index ec52866ac52d..ec0209617545 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -32,6 +32,7 @@ static CGFloat const RPVCScrollingFastVelocityThreshold = 30.f; static CGFloat const RPVCHeaderHeightPhone = 10.f; static CGFloat const RPVCMaxImageHeightPercentage = 0.58f; +static CGFloat const RPVCExtraTableViewHeight = 800.f; NSString *const RPVCDisplayedNativeFriendFinder = @"DisplayedNativeFriendFinder"; @@ -102,7 +103,7 @@ - (void)viewDidLoad { _featuredImageSource = [[WPTableImageSource alloc] initWithMaxSize:CGSizeMake(maxWidth, maxHeight)]; _featuredImageSource.delegate = self; self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; - + // Topics button UIBarButtonItem *button = nil; UIButton *topicsButton = [UIButton buttonWithType:UIButtonTypeCustom]; @@ -178,14 +179,23 @@ - (void)viewWillDisappear:(BOOL)animated { - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; - // After rotation, visible images might be scaled up/down - // Force them to reload so they're pixel perfect - [self loadImagesForVisibleRows]; } #pragma mark - Instance Methods +- (void)resizeTableViewForImagePreloading { + // Use a trick to preload more images by making the table view longer +// CGRect rect = self.tableView.bounds; +// rect.origin.y = 0; +// rect.size.height = [[UIScreen mainScreen] bounds].size.height + RPVCExtraTableViewHeight; +// self.tableView.bounds = rect; +// UIEdgeInsets inset = self.tableView.contentInset; +// inset.bottom = RPVCExtraTableViewHeight + [self tabBarSize].height; +// NSLog(@"Reader new frame height %f inset %f", rect.size.height, inset.bottom); +// self.tableView.contentInset = inset; +} + - (void)setTitle:(NSString *)title { [super setTitle:title]; @@ -281,39 +291,6 @@ - (void)hideReblogForm { [self.view endEditing:YES]; } -- (void)loadImagesForVisibleRows { - NSArray *visiblePaths = [self.tableView indexPathsForVisibleRows]; - for (NSIndexPath *indexPath in visiblePaths) { - ReaderPost *post = (ReaderPost *)[self.resultsController objectAtIndexPath:indexPath]; - - ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]; - - UIImage *image = [post cachedAvatarWithSize:cell.postView.avatarImageView.bounds.size]; - CGSize imageSize = cell.postView.avatarImageView.bounds.size; - if (image) { - [cell.postView setAvatar:image]; - } else { - __weak UITableView *tableView = self.tableView; - [post fetchAvatarWithSize:imageSize success:^(UIImage *image) { - if (cell == [tableView cellForRowAtIndexPath:indexPath]) { - [cell.postView setAvatar:image]; - } - }]; - } - - if (post.featuredImageURL) { - NSURL *imageURL = post.featuredImageURL; - imageSize = cell.postView.cellImageView.frame.size; - image = [_featuredImageSource imageForURL:imageURL withSize:imageSize]; - if (image) { - [cell.postView setFeaturedImage:image]; - } else { - [_featuredImageSource fetchImageForURL:imageURL withSize:imageSize indexPath:indexPath isPrivate:post.isPrivate]; - } - } - } -} - #pragma mark - ReaderPostView delegate methods @@ -444,7 +421,6 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [super scrollViewDidEndDecelerating:scrollView]; _isScrollingFast = NO; - //[self loadImagesForVisibleRows]; NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow]; if (!selectedIndexPath) From eb14d254c5a6477294f267e922e231b33930fde4 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 26 Nov 2013 23:29:09 -0800 Subject: [PATCH 26/41] Code for preloading images (disabled for now) --- WordPress/Classes/ReaderPostsViewController.m | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index ec0209617545..77385cb8f30f 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -169,6 +169,8 @@ - (void)viewDidAppear:(BOOL)animated { if (selectedIndexPath) { [self.tableView deselectRowAtIndexPath:selectedIndexPath animated:YES]; } + + //[self resizeTableViewForImagePreloading]; } - (void)viewWillDisappear:(BOOL)animated { @@ -179,6 +181,7 @@ - (void)viewWillDisappear:(BOOL)animated { - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; + //[self resizeTableViewForImagePreloading]; } @@ -186,14 +189,14 @@ - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceO - (void)resizeTableViewForImagePreloading { // Use a trick to preload more images by making the table view longer -// CGRect rect = self.tableView.bounds; -// rect.origin.y = 0; -// rect.size.height = [[UIScreen mainScreen] bounds].size.height + RPVCExtraTableViewHeight; -// self.tableView.bounds = rect; -// UIEdgeInsets inset = self.tableView.contentInset; -// inset.bottom = RPVCExtraTableViewHeight + [self tabBarSize].height; -// NSLog(@"Reader new frame height %f inset %f", rect.size.height, inset.bottom); -// self.tableView.contentInset = inset; + CGRect rect = self.tableView.frame; + rect.size.height = [[UIScreen mainScreen] bounds].size.height + RPVCExtraTableViewHeight; + self.tableView.frame = rect; + UIEdgeInsets inset = self.tableView.contentInset; + inset.bottom = RPVCExtraTableViewHeight + [self tabBarSize].height; + NSLog(@"Reader new frame height %f inset %f", rect.size.height, inset.bottom); + self.tableView.contentInset = inset; + [self.tableView layoutIfNeeded]; } - (void)setTitle:(NSString *)title { From 4d22195ed26f0da964cce5a8e9199c231d38fe2f Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Fri, 29 Nov 2013 12:35:03 -0800 Subject: [PATCH 27/41] Remove remaining presentAsModal global antipatterns (fixes #620) --- .../Classes/ReaderPostDetailViewController.m | 21 +++++++-------- WordPress/Classes/ReaderReblogFormView.m | 14 ++++++++-- .../Classes/ReaderUsersBlogsViewController.h | 2 -- .../Classes/ReaderUsersBlogsViewController.m | 20 ++------------ WordPress/Classes/WPImageViewController.h | 4 --- WordPress/Classes/WPImageViewController.m | 27 ------------------- WordPress/Classes/WPWebVideoViewController.h | 3 --- WordPress/Classes/WPWebVideoViewController.m | 21 --------------- 8 files changed, 24 insertions(+), 88 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index d7de7c9610a1..fe35651a2743 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -661,7 +661,8 @@ - (void)postView:(ReaderPostView *)postView didReceiveLinkAction:(id)sender { - (void)postView:(ReaderPostView *)postView didReceiveImageLinkAction:(id)sender { ReaderImageView *imageView = (ReaderImageView *)sender; - + UIViewController *controller; + if (imageView.linkURL) { NSString *url = [imageView.linkURL absoluteString]; @@ -675,21 +676,19 @@ - (void)postView:(ReaderPostView *)postView didReceiveImageLinkAction:(id)sender } if (matched) { - UIViewController *controller = [[WPImageViewController alloc] initWithImage:imageView.image andURL:imageView.linkURL]; - controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; - controller.modalPresentationStyle = UIModalPresentationFullScreen; + controller = [[WPImageViewController alloc] initWithImage:imageView.image andURL:imageView.linkURL]; [self.navigationController presentViewController:controller animated:YES completion:nil]; - - //[WPImageViewController presentAsModalWithImage:imageView.image andURL:((ReaderImageView *)sender).linkURL]; - // [WPImageViewController presentAsModalWithURL:((ReaderImageView *)sender).linkURL]; } else { - WPWebViewController *controller = [[WPWebViewController alloc] init]; - [controller setUrl:((ReaderImageView *)sender).linkURL]; - [self.navigationController pushViewController:controller animated:YES]; + controller = [[WPWebViewController alloc] init]; + [(WPWebViewController *)controller setUrl:((ReaderImageView *)sender).linkURL]; } } else { - [WPImageViewController presentAsModalWithImage:imageView.image]; + controller = [[WPImageViewController alloc] initWithImage:imageView.image]; } + + controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + controller.modalPresentationStyle = UIModalPresentationFullScreen; + [self.navigationController pushViewController:controller animated:YES]; } - (void)postView:(ReaderPostView *)postView didReceiveVideoLinkAction:(id)sender { diff --git a/WordPress/Classes/ReaderReblogFormView.m b/WordPress/Classes/ReaderReblogFormView.m index 2e09fb62eb36..5d4eea09fab1 100644 --- a/WordPress/Classes/ReaderReblogFormView.m +++ b/WordPress/Classes/ReaderReblogFormView.m @@ -218,8 +218,18 @@ - (void)handleSendButtonTapped:(id)sender { } -- (void)handleBlogButtonTapped:(id)sender { - [ReaderUsersBlogsViewController presentAsModalWithDelegate:self]; +- (void)handleBlogButtonTapped:(id)sender { + ReaderUsersBlogsViewController *controller = [[ReaderUsersBlogsViewController alloc] init]; + controller.delegate = self; + + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller]; + navController.navigationBar.translucent = NO; + navController.modalPresentationStyle = UIModalPresentationFormSheet; + if (!IS_IPAD) { + // Avoid a weird issue on the iPad with cross dissolves when the keyboard is visible. + navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + } + [[[WordPressAppDelegate sharedWordPressApplicationDelegate].window rootViewController] presentViewController:navController animated:YES completion:nil]; } diff --git a/WordPress/Classes/ReaderUsersBlogsViewController.h b/WordPress/Classes/ReaderUsersBlogsViewController.h index 20d3c1c8c282..5f72d13fc01d 100644 --- a/WordPress/Classes/ReaderUsersBlogsViewController.h +++ b/WordPress/Classes/ReaderUsersBlogsViewController.h @@ -14,8 +14,6 @@ @property (nonatomic, weak) iddelegate; -+ (id)presentAsModalWithDelegate:(id)delegate; - @end @protocol ReaderUsersBlogsDelegate diff --git a/WordPress/Classes/ReaderUsersBlogsViewController.m b/WordPress/Classes/ReaderUsersBlogsViewController.m index 2b8d110c21fb..227c208a3256 100644 --- a/WordPress/Classes/ReaderUsersBlogsViewController.m +++ b/WordPress/Classes/ReaderUsersBlogsViewController.m @@ -24,23 +24,6 @@ - (void)handleCloseButtonTapped:(id)sender; @implementation ReaderUsersBlogsViewController -+ (id)presentAsModalWithDelegate:(id)delegate { - ReaderUsersBlogsViewController *controller = [[ReaderUsersBlogsViewController alloc] init]; - controller.delegate = delegate; - controller.title = NSLocalizedString(@"My Blogs", @"Title of the list of the user's blogs as shown in the reader."); - - UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller]; - navController.navigationBar.translucent = NO; - navController.modalPresentationStyle = UIModalPresentationFormSheet; - if (!IS_IPAD) { - // Avoid a weird issue on the iPad with cross dissolves when the keyboard is visible. - navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; - } - [[[WordPressAppDelegate sharedWordPressApplicationDelegate] navigationController] presentViewController:navController animated:YES completion:nil]; - - return controller; -} - #pragma mark - Lifecycle Methods - (id)init { @@ -53,7 +36,8 @@ - (id)init { } - (void)viewDidLoad { - + self.title = NSLocalizedString(@"My Blogs", @"Title of the list of the user's blogs as shown in the reader."); + self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui-texture"]]; self.view.backgroundColor = [WPNUXUtility backgroundColor]; diff --git a/WordPress/Classes/WPImageViewController.h b/WordPress/Classes/WPImageViewController.h index ffcc134a8fc9..7e98db8bbbf3 100644 --- a/WordPress/Classes/WPImageViewController.h +++ b/WordPress/Classes/WPImageViewController.h @@ -10,10 +10,6 @@ @interface WPImageViewController : UIViewController -+ (id)presentAsModalWithImage:(UIImage *)image; -+ (id)presentAsModalWithURL:(NSURL *)url; -+ (id)presentAsModalWithImage:(UIImage *)image andURL:(NSURL *)url; - - (id)initWithImage:(UIImage *)image; - (id)initWithURL:(NSURL *)url; - (id)initWithImage:(UIImage *)image andURL:(NSURL *)url; diff --git a/WordPress/Classes/WPImageViewController.m b/WordPress/Classes/WPImageViewController.m index 932cc294b634..d7099a53844f 100644 --- a/WordPress/Classes/WPImageViewController.m +++ b/WordPress/Classes/WPImageViewController.m @@ -24,33 +24,6 @@ - (void)handleImageDoubleTapped:(UITapGestureRecognizer *)tgr; @implementation WPImageViewController -+ (id)presentAsModalWithImage:(UIImage *)image { - UIViewController *controller = [[self alloc] initWithImage:image]; - controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; - controller.modalPresentationStyle = UIModalPresentationFullScreen; - [[[WordPressAppDelegate sharedWordPressApplicationDelegate] navigationController] presentViewController:controller animated:YES completion:nil]; - return controller; -} - - -+ (id)presentAsModalWithURL:(NSURL *)url { - UIViewController *controller = [[self alloc] initWithURL:url]; - controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; - controller.modalPresentationStyle = UIModalPresentationFullScreen; - [[[WordPressAppDelegate sharedWordPressApplicationDelegate] navigationController] presentViewController:controller animated:YES completion:nil]; - return controller; -} - - -+ (id)presentAsModalWithImage:(UIImage *)image andURL:(NSURL *)url { - UIViewController *controller = [[self alloc] initWithImage:image andURL:url]; - controller.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; - controller.modalPresentationStyle = UIModalPresentationFullScreen; - [[[WordPressAppDelegate sharedWordPressApplicationDelegate] navigationController] presentViewController:controller animated:YES completion:nil]; - return controller; -} - - #pragma mark - LifeCycle Methods - (id)initWithImage:(UIImage *)image { diff --git a/WordPress/Classes/WPWebVideoViewController.h b/WordPress/Classes/WPWebVideoViewController.h index 81c3aaf1eecd..da03fd8831ce 100644 --- a/WordPress/Classes/WPWebVideoViewController.h +++ b/WordPress/Classes/WPWebVideoViewController.h @@ -10,9 +10,6 @@ @interface WPWebVideoViewController : UIViewController -+ (id)presentAsModalWithURL:(NSURL *)url; -+ (id)presentAsModalWithHTML:(NSString *)html; - - (id)initWithURL:(NSURL *)url; - (id)initWithHTML:(NSString *)html; diff --git a/WordPress/Classes/WPWebVideoViewController.m b/WordPress/Classes/WPWebVideoViewController.m index 93a5971480b6..5d5a8b6d4c27 100644 --- a/WordPress/Classes/WPWebVideoViewController.m +++ b/WordPress/Classes/WPWebVideoViewController.m @@ -23,27 +23,6 @@ - (void)handleCloseTapped:(id)sender; @implementation WPWebVideoViewController -+ (id)presentAsModalWithURL:(NSURL *)url { - UIViewController *controller = [[self alloc] initWithURL:url]; - UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller]; - navController.navigationBar.translucent = NO; - navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; - navController.modalPresentationStyle = UIModalPresentationFullScreen; - - [[[WordPressAppDelegate sharedWordPressApplicationDelegate] navigationController] presentViewController:navController animated:YES completion:nil]; - return controller; -} - - -+ (id)presentAsModalWithHTML:(NSString *)html { - UIViewController *controller = [[self alloc] initWithHTML:html]; - UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller]; - navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; - navController.modalPresentationStyle = UIModalPresentationFullScreen; - [[[WordPressAppDelegate sharedWordPressApplicationDelegate] navigationController] presentViewController:navController animated:YES completion:nil]; - return controller; -} - #pragma mark - LifeCycle Methods From e0869c0e56ceedcad8f2ad610d61626958e0bfa8 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Fri, 29 Nov 2013 15:52:05 -0800 Subject: [PATCH 28/41] Remove unimplemented failure handler (fixes #645) --- WordPress/Classes/ReaderPostDetailViewController.m | 6 ------ 1 file changed, 6 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index fe35651a2743..cfcd17f49ed5 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -778,7 +778,6 @@ - (void)loadMoreWithSuccess:(void (^)())success failure:(void (^)(NSError *error success:^(AFHTTPRequestOperation *operation, id responseObject) { [self onSyncSuccess:operation response:responseObject]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { - [self onSyncFailure:operation error:error]; }]; } @@ -805,11 +804,6 @@ - (void)onSyncSuccess:(AFHTTPRequestOperation *)operation response:(id)responseO [self prepareComments]; } -// TODO: Unhandled failure for user interaction -- (void)onSyncFailure:(AFHTTPRequestOperation *)operation error:(NSError *)error { - @throw ([NSException exceptionWithName:@"Method unimplemented" reason:@"onSyncFailure:error: not implemented in ReaderPostDetailViewController" userInfo:nil]); -} - #pragma mark - Infinite Scrolling From 80650e1a2e2872eba07f124e7f300b9709149a40 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Sat, 30 Nov 2013 15:09:05 -0800 Subject: [PATCH 29/41] Remove another reference to removed handler --- WordPress/Classes/ReaderPostDetailViewController.m | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index cfcd17f49ed5..b2413b9016d3 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -758,7 +758,6 @@ - (void)syncWithUserInteraction:(BOOL)userInteraction { success:^(AFHTTPRequestOperation *operation, id responseObject) { [self onSyncSuccess:operation response:responseObject]; } failure:^(AFHTTPRequestOperation *operation, NSError *error) { - [self onSyncFailure:operation error:error]; }]; } From 5db9f4029d6fb2fa7a11b9b81298791bb921e529 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 3 Dec 2013 21:57:57 -0800 Subject: [PATCH 30/41] Reenable and improve trick for preloading images --- WordPress/Classes/ReaderPostsViewController.m | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index d5e49bbb1c0f..d6017925693f 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -31,7 +31,7 @@ static CGFloat const RPVCScrollingFastVelocityThreshold = 30.f; static CGFloat const RPVCHeaderHeightPhone = 10.f; static CGFloat const RPVCMaxImageHeightPercentage = 0.58f; -static CGFloat const RPVCExtraTableViewHeight = 800.f; +static CGFloat const RPVCExtraTableViewHeightPercentage = 2.0f; NSString *const RPVCDisplayedNativeFriendFinder = @"DisplayedNativeFriendFinder"; @@ -169,7 +169,7 @@ - (void)viewDidAppear:(BOOL)animated { [self.tableView deselectRowAtIndexPath:selectedIndexPath animated:YES]; } - //[self resizeTableViewForImagePreloading]; + [self resizeTableViewForImagePreloading]; } - (void)viewWillDisappear:(BOOL)animated { @@ -178,23 +178,35 @@ - (void)viewWillDisappear:(BOOL)animated { [[NSNotificationCenter defaultCenter] removeObserver:self]; } +- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { + [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; +} + - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; - //[self resizeTableViewForImagePreloading]; + [self resizeTableViewForImagePreloading]; } #pragma mark - Instance Methods - (void)resizeTableViewForImagePreloading { - // Use a trick to preload more images by making the table view longer + // Use a little trick to preload more images by making the table view longer CGRect rect = self.tableView.frame; - rect.size.height = [[UIScreen mainScreen] bounds].size.height + RPVCExtraTableViewHeight; + CGFloat navigationHeight = self.navigationController.view.frame.size.height; + CGFloat extraHeight = navigationHeight * RPVCExtraTableViewHeightPercentage; + rect.size.height = navigationHeight + extraHeight; self.tableView.frame = rect; - UIEdgeInsets inset = self.tableView.contentInset; - inset.bottom = RPVCExtraTableViewHeight + [self tabBarSize].height; - NSLog(@"Reader new frame height %f inset %f", rect.size.height, inset.bottom); - self.tableView.contentInset = inset; + + // Move insets up to compensate + UIEdgeInsets insets = self.tableView.contentInset; + insets.bottom = extraHeight + [self tabBarSize].height; + self.tableView.contentInset = insets; + + // Adjust the scroll insets as well + UIEdgeInsets scrollInsets = self.tableView.scrollIndicatorInsets; + scrollInsets.bottom = insets.bottom; + self.tableView.scrollIndicatorInsets = scrollInsets; [self.tableView layoutIfNeeded]; } From 73304f6431c2d68d3cf8ec985df943e845ace726 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 3 Dec 2013 22:06:22 -0800 Subject: [PATCH 31/41] Don't display the placeholder icon for images --- WordPress/Classes/ReaderPostView.m | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index 573a60551634..5dbd60835b61 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -221,8 +221,6 @@ - (void)configurePost:(ReaderPost *)post { self.showImage = NO; self.cellImageView.hidden = YES; - self.cellImageView.contentMode = UIViewContentModeCenter; - self.cellImageView.image = [UIImage imageNamed:@"wp_img_placeholder"]; if (post.featuredImageURL) { self.showImage = YES; self.cellImageView.hidden = NO; @@ -783,15 +781,13 @@ - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedT DTImageTextAttachment *imageAttachment = (DTImageTextAttachment *)attachment; UIImage *image; - if( [imageAttachment.image isKindOfClass:[UIImage class]] ) { + if ([imageAttachment.image isKindOfClass:[UIImage class]]) { image = imageAttachment.image; CGFloat ratio = image.size.width / image.size.height; frame.size.width = availableWidth; frame.size.height = roundf(width / ratio); - } else { - image = [UIImage imageNamed:@"wp_img_placeholder.png"]; - + } else { if (frame.size.width > 1.0f && frame.size.height > 1.0f) { CGFloat ratio = frame.size.width / frame.size.height; frame.size.width = availableWidth; @@ -816,7 +812,6 @@ - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedT if ([imageAttachment.image isKindOfClass:[UIImage class]]) { [imageView setImage:image]; } else { - //imageView.contentMode = UIViewContentModeCenter; imageView.backgroundColor = [UIColor colorWithRed:192.0f/255.0f green:192.0f/255.0f blue:192.0f/255.0f alpha:1.0]; [self.mediaQueue enqueueMedia:imageView From 5b2eafcc9dbd425aa25c95bd3ba30db32a9b18fb Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Tue, 3 Dec 2013 22:12:46 -0800 Subject: [PATCH 32/41] Set state of follow button on configuration (fixes #704) --- WordPress/Classes/ReaderPostView.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index 5dbd60835b61..b8fc91d618a4 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -242,7 +242,8 @@ - (void)configurePost:(ReaderPost *)post { _reblogButton.hidden = YES; _commentButton.hidden = YES; } - + + [_followButton setSelected:[self.post.isFollowing boolValue]]; _reblogButton.userInteractionEnabled = ![post.isReblogged boolValue]; [self updateActionButtons]; @@ -320,7 +321,6 @@ - (void)buildPostContent { [_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]; @@ -508,6 +508,7 @@ - (void)reset { _titleLabel.text = nil; _snippetLabel.text = nil; [_tagButton setTitle:nil forState:UIControlStateNormal]; + [_followButton setSelected:NO]; [_cellImageView cancelImageRequestOperation]; _cellImageView.image = nil; From e70e6892e58be6f7686ab9da30cdfa723ae1c926 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Wed, 4 Dec 2013 11:26:55 -0800 Subject: [PATCH 33/41] Fix reblog form not displaying correctly --- WordPress/Classes/ReaderPostsViewController.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index d6017925693f..1df0b7e80bdc 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -280,7 +280,10 @@ - (void)showReblogForm { CGFloat reblogHeight = [ReaderReblogFormView desiredHeight]; CGRect tableFrame = self.tableView.frame; - tableFrame.size.height = self.tableView.frame.size.height - reblogHeight; + CGRect superviewFrame = self.view.superview.frame; + + // The table's frame is artifically tall due to resizeTableViewForImagePreloading, so effectively undo that + tableFrame.size.height = superviewFrame.size.height - tableFrame.origin.y - reblogHeight - [self tabBarSize].height; self.tableView.frame = tableFrame; CGFloat y = tableFrame.origin.y + tableFrame.size.height; @@ -300,6 +303,7 @@ - (void)hideReblogForm { tableFrame.size.height = self.tableView.frame.size.height + _readerReblogFormView.frame.size.height; self.tableView.frame = tableFrame; + [self resizeTableViewForImagePreloading]; [_readerReblogFormView removeFromSuperview]; self.isShowingReblogForm = NO; [self.view endEditing:YES]; From f6dc6c686e7b86605810c798efd9062c790d3146 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Wed, 4 Dec 2013 11:54:37 -0800 Subject: [PATCH 34/41] Comment cleanup --- WordPress/Classes/ReaderPostDetailViewController.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index f44fa42835c0..4be01675b19e 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -99,7 +99,6 @@ - (void)viewDidLoad { self.tableView.backgroundColor = [UIColor whiteColor]; [self buildHeader]; - //[self buildTopToolbar]; [WPStyleGuide setRightBarButtonItemWithCorrectSpacing:self.shareButton forNavigationItem:self.navigationItem]; [self buildForms]; @@ -397,7 +396,7 @@ - (void)updateActionBar { [items addObject:placeholder]; - // TODO: put these in the title bar instead + // Could put these in the title bar instead. We're preserving this code for now pending design decisions. //[self setToolbarItems:items animated:YES]; } From ef99356416e7e68fce16b89b3c5f1aa5dd6f4520 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Wed, 4 Dec 2013 11:54:54 -0800 Subject: [PATCH 35/41] Constrain the width of the follow button --- WordPress/Classes/ReaderPostView.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index b8fc91d618a4..b5245a3907d2 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -36,6 +36,7 @@ const CGFloat RPVMaxImageHeightPercentage = 0.59f; const CGFloat RPVMaxSummaryHeight = 88.0f; const CGFloat RPVLineHeightMultiple = 1.15f; +const CGFloat RPVFollowButtonWidth = 100.0f; // Control buttons (Like, Reblog, ...) const CGFloat RPVControlButtonHeight = 48.0f; @@ -415,7 +416,7 @@ - (void)layoutSubviews { CGFloat followX = bylineX - 4; // Fudge factor for image alignment CGFloat followY = RPVAuthorPadding + _bylineLabel.frame.size.height - 2; height = ceil([_followButton.titleLabel suggestedSizeForWidth:innerContentWidth].height); - _followButton.frame = CGRectMake(followX, followY, contentWidth - bylineX, height); + _followButton.frame = CGRectMake(followX, followY, RPVFollowButtonWidth, height); } else { _followButton.hidden = YES; } From 829a4677f97ab7179c0e89d8efcf1e75153df7aa Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Wed, 4 Dec 2013 12:10:36 -0800 Subject: [PATCH 36/41] Swap out topic change delegate for NSNotification for easier reuse --- WordPress/Classes/ReaderPostsViewController.h | 2 ++ WordPress/Classes/ReaderPostsViewController.m | 14 +++++++++----- WordPress/Classes/ReaderTopicsViewController.h | 8 -------- WordPress/Classes/ReaderTopicsViewController.m | 6 ++---- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/WordPress/Classes/ReaderPostsViewController.h b/WordPress/Classes/ReaderPostsViewController.h index c7d11e415005..a9e327c7a84c 100644 --- a/WordPress/Classes/ReaderPostsViewController.h +++ b/WordPress/Classes/ReaderPostsViewController.h @@ -10,6 +10,8 @@ #import "WPTableViewController.h" #import "ReaderPostView.h" +extern NSString * const ReaderTopicDidChangeNotification; + @interface ReaderPostsViewController : WPTableViewController @end diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index 1df0b7e80bdc..04b13b42e487 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -33,9 +33,10 @@ static CGFloat const RPVCMaxImageHeightPercentage = 0.58f; static CGFloat const RPVCExtraTableViewHeightPercentage = 2.0f; -NSString *const RPVCDisplayedNativeFriendFinder = @"DisplayedNativeFriendFinder"; +NSString * const ReaderTopicDidChangeNotification = @"ReaderTopicDidChangeNotification"; +NSString * const RPVCDisplayedNativeFriendFinder = @"DisplayedNativeFriendFinder"; -@interface ReaderPostsViewController () { +@interface ReaderPostsViewController () { BOOL _hasMoreContent; BOOL _loadingMore; WPTableImageSource *_featuredImageSource; @@ -82,6 +83,10 @@ - (id)init { _hasMoreContent = YES; self.infiniteScrollEnabled = YES; self.incrementalLoadingSupported = YES; + + [[NSNotificationCenter defaultCenter] addObserverForName:ReaderTopicDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) { + [self readerTopicDidChange]; + }]; } return self; } @@ -379,7 +384,7 @@ - (void)postView:(ReaderPostView *)postView didReceiveTagAction:(id)sender { [[NSUserDefaults standardUserDefaults] setObject:dict forKey:ReaderCurrentTopicKey]; [[NSUserDefaults standardUserDefaults] synchronize]; - [self readerTopicChanged]; + [self readerTopicDidChange]; } @@ -387,7 +392,6 @@ - (void)postView:(ReaderPostView *)postView didReceiveTagAction:(id)sender { - (void)topicsAction:(id)sender { ReaderTopicsViewController *controller = [[ReaderTopicsViewController alloc] initWithStyle:UITableViewStyleGrouped]; - controller.delegate = self; if (IS_IPAD) { if (_popover) { [self dismissPopover]; @@ -807,7 +811,7 @@ - (void)controller:(NSFetchedResultsController *)controller #pragma mark - ReaderTopicsDelegate Methods -- (void)readerTopicChanged { +- (void)readerTopicDidChange { if (IS_IPAD){ [self dismissPopover]; } diff --git a/WordPress/Classes/ReaderTopicsViewController.h b/WordPress/Classes/ReaderTopicsViewController.h index 5de04d555ba1..960f14360db8 100644 --- a/WordPress/Classes/ReaderTopicsViewController.h +++ b/WordPress/Classes/ReaderTopicsViewController.h @@ -8,14 +8,6 @@ #import -@protocol ReaderTopicsDelegate - -- (void)readerTopicChanged; - -@end - @interface ReaderTopicsViewController : UITableViewController -@property (nonatomic, strong) iddelegate; - @end diff --git a/WordPress/Classes/ReaderTopicsViewController.m b/WordPress/Classes/ReaderTopicsViewController.m index 12a1fdf17cae..cc62f6d542f2 100644 --- a/WordPress/Classes/ReaderTopicsViewController.m +++ b/WordPress/Classes/ReaderTopicsViewController.m @@ -6,6 +6,7 @@ // Copyright (c) 2013 WordPress. All rights reserved. // +#import "ReaderPostsViewController.h" #import "ReaderTopicsViewController.h" #import "WordPressComApi.h" #import "ReaderPost.h" @@ -27,7 +28,6 @@ - (void)handleFriendFinderButtonTapped:(id)sender; @implementation ReaderTopicsViewController -@synthesize delegate; #pragma mark - LifeCycle Methods @@ -255,9 +255,7 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [[NSUserDefaults standardUserDefaults] synchronize]; if(![[dict objectForKey:@"endpoint"] isEqualToString:[_currentTopic objectForKey:@"endpoint"]]) { - if(self.delegate) { - [delegate readerTopicChanged]; - } + [[NSNotificationCenter defaultCenter] postNotificationName:ReaderTopicDidChangeNotification object:self]; } [self dismissViewControllerAnimated:YES completion:nil]; From ee078e4f3d7bb85d0e1e681349e911c01cc62e7b Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Wed, 4 Dec 2013 12:10:59 -0800 Subject: [PATCH 37/41] Handle tapping a tag in the Reader detail view --- .../Classes/ReaderPostDetailViewController.m | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 4be01675b19e..d7574382c7f5 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -8,6 +8,7 @@ */ #import "ReaderPostDetailViewController.h" +#import "ReaderPostsViewController.h" #import #import #import @@ -727,16 +728,17 @@ - (void)postView:(ReaderPostView *)postView didReceiveVideoLinkAction:(id)sender } - (void)postView:(ReaderPostView *)postView didReceiveTagAction:(id)sender { - // TODO: decide how to browse from the Reader detail view -// ReaderPost *post = postView.post; -// -// NSString *endpoint = [NSString stringWithFormat:@"read/tags/%@/posts", post.primaryTagSlug]; -// NSDictionary *dict = @{@"endpoint" : endpoint, -// @"title" : post.primaryTagName}; -// -// [[NSUserDefaults standardUserDefaults] setObject:dict forKey:ReaderCurrentTopicKey]; -// [[NSUserDefaults standardUserDefaults] synchronize]; -// [self readerTopicChanged]; + ReaderPost *post = postView.post; + + NSString *endpoint = [NSString stringWithFormat:@"read/tags/%@/posts", post.primaryTagSlug]; + NSDictionary *dict = @{@"endpoint" : endpoint, + @"title" : post.primaryTagName}; + + [[NSUserDefaults standardUserDefaults] setObject:dict forKey:ReaderCurrentTopicKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; + + [self.navigationController popViewControllerAnimated:YES]; + [[NSNotificationCenter defaultCenter] postNotificationName:ReaderTopicDidChangeNotification object:self]; } From e2711e77864104d670f3fadc74c3b44c2c2b82b7 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Wed, 4 Dec 2013 12:18:49 -0800 Subject: [PATCH 38/41] Comment cleanup --- WordPress/Classes/ReaderPostView.m | 15 +-------------- WordPress/Classes/ReaderPostsViewController.m | 4 ---- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/WordPress/Classes/ReaderPostView.m b/WordPress/Classes/ReaderPostView.m index b5245a3907d2..511221fa5b93 100644 --- a/WordPress/Classes/ReaderPostView.m +++ b/WordPress/Classes/ReaderPostView.m @@ -636,8 +636,6 @@ - (void)updateLayout { frame = self.frame; frame.size.height = height + _textContentView.frame.origin.y + 10.0f; // + bottom padding self.frame = frame; - - //[self.delegate readerPostDetailViewLayoutChanged]; } @@ -704,7 +702,6 @@ - (void)readerMediaQueue:(ReaderMediaQueue *)mediaQueue didLoadBatch:(NSArray *) // layout might have changed due to image sizes [self.textContentView relayoutText]; [self setNeedsLayout]; - //[self _updateLayout]; } } @@ -740,17 +737,7 @@ - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedT if (!attachment.contentURL) return nil; - - // If it's the same as the featured image, don't display that image again -// BOOL sameImage = [[attachment.contentURL absoluteString] rangeOfString: [self.post.featuredImageURL absoluteString] -// ].location != NSNotFound; -// if (sameImage) { -// ReaderImageView *emptyView = [[ReaderImageView alloc] initWithFrame:CGRectZero]; -// [self handleMediaViewLoaded:emptyView]; -// [self setNeedsLayout]; -// return emptyView; -// } - + CGFloat width = _textContentView.frame.size.width; CGFloat availableWidth = _textContentView.frame.size.width - (_textContentView.edgeInsets.left + _textContentView.edgeInsets.right); diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index 04b13b42e487..ec20e70f63d2 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -183,10 +183,6 @@ - (void)viewWillDisappear:(BOOL)animated { [[NSNotificationCenter defaultCenter] removeObserver:self]; } -- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { - [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; -} - - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; [self resizeTableViewForImagePreloading]; From 73ed940245e472835c614133dab5afb4990da85e Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Wed, 4 Dec 2013 12:20:24 -0800 Subject: [PATCH 39/41] Remove unused isScrollingFast logic --- WordPress/Classes/ReaderPostsViewController.m | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/WordPress/Classes/ReaderPostsViewController.m b/WordPress/Classes/ReaderPostsViewController.m index ec20e70f63d2..3916b9ddd36a 100644 --- a/WordPress/Classes/ReaderPostsViewController.m +++ b/WordPress/Classes/ReaderPostsViewController.m @@ -41,7 +41,6 @@ @interface ReaderPostsViewController () RPVCScrollingFastVelocityThreshold && self.isScrolling) { -// _isScrollingFast = YES; -// } else { -// _isScrollingFast = NO; -// } - _lastOffset = offset; -} - - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [super scrollViewDidEndDecelerating:scrollView]; - _isScrollingFast = NO; NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow]; if (!selectedIndexPath) @@ -590,7 +574,7 @@ - (void)setImageForPost:(ReaderPost *)post forCell:(ReaderPostTableViewCell *)ce if (image) { [cell.postView setFeaturedImage:image]; - } else if (!_isScrollingFast) { + } else { [_featuredImageSource fetchImageForURL:imageURL withSize:imageSize indexPath:indexPath isPrivate:post.isPrivate]; } } @@ -1003,10 +987,8 @@ - (void)openFriendFinder:(id)sender { #pragma mark - WPTableImageSourceDelegate - (void)tableImageSource:(WPTableImageSource *)tableImageSource imageReady:(UIImage *)image forIndexPath:(NSIndexPath *)indexPath { - if (!_isScrollingFast) { - ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]; - [cell.postView setFeaturedImage:image]; - } + ReaderPostTableViewCell *cell = (ReaderPostTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath]; + [cell.postView setFeaturedImage:image]; ReaderPost *post = [self.resultsController objectAtIndexPath:indexPath]; From 4ada971998190613d6fb92524399156295c14e84 Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Fri, 6 Dec 2013 11:02:55 -0800 Subject: [PATCH 40/41] Don't use self to set properties in init --- WordPress/Classes/ReaderPostDetailViewController.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index d7574382c7f5..18d92706e570 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -77,10 +77,10 @@ - (void)dealloc { - (id)initWithPost:(ReaderPost *)post featuredImage:(UIImage *)image { self = [super init]; if (self) { - self.post = post; - self.comments = [NSMutableArray array]; - self.featuredImage = image; - self.showInlineActionBar = YES; + _post = post; + _comments = [NSMutableArray array]; + _featuredImage = image; + _showInlineActionBar = YES; } return self; } From 390e2e9513764fcb6081cbdcec5641e89f53bf9b Mon Sep 17 00:00:00 2001 From: Mike Johnston Date: Fri, 6 Dec 2013 11:22:39 -0800 Subject: [PATCH 41/41] Move code from viewDidUnload to dealloc --- .../Classes/ReaderPostDetailViewController.m | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/WordPress/Classes/ReaderPostDetailViewController.m b/WordPress/Classes/ReaderPostDetailViewController.m index 18d92706e570..5d2c9b00702e 100644 --- a/WordPress/Classes/ReaderPostDetailViewController.m +++ b/WordPress/Classes/ReaderPostDetailViewController.m @@ -72,6 +72,17 @@ - (void)dealloc { _resultsController.delegate = nil; self.tableView.delegate = nil; self.postView.delegate = nil; + + self.activityFooter = nil; + self.postView = nil; + self.readerCommentFormView = nil; + self.readerReblogFormView = nil; + self.commentButton = nil; + self.likeButton = nil; + self.reblogButton = nil; + self.shareButton = nil; + + [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (id)initWithPost:(ReaderPost *)post featuredImage:(UIImage *)image { @@ -158,21 +169,6 @@ - (void)viewWillDisappear:(BOOL)animated { [[NSNotificationCenter defaultCenter] removeObserver:self]; } -- (void)viewDidUnload { - [super viewDidUnload]; - - self.activityFooter = nil; - self.postView = nil; - self.readerCommentFormView = nil; - self.readerReblogFormView = nil; - self.commentButton = nil; - self.likeButton = nil; - self.reblogButton = nil; - self.shareButton = nil; - - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];