From bd695a7a23e06c7e9347f334150d417b30e51026 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 31 Oct 2014 16:22:19 -0300 Subject: [PATCH 01/61] Implements NSAttributedString Extension --- .../NSAttributedString+RichTextView.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 WordPress/Classes/ViewRelated/Notifications/RichTextView/NSAttributedString+RichTextView.swift diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/NSAttributedString+RichTextView.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/NSAttributedString+RichTextView.swift new file mode 100644 index 000000000000..d41a99d6efdc --- /dev/null +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/NSAttributedString+RichTextView.swift @@ -0,0 +1,17 @@ +import Foundation + + +extension NSAttributedString +{ + public func enumerateAttachments(block: (attachment: NSTextAttachment, range: NSRange) -> ()) { + let range = NSMakeRange(0, length) + + enumerateAttribute(NSAttachmentAttributeName, inRange: range, options: .LongestEffectiveRangeNotRequired) { + (value: AnyObject!, range: NSRange, stop: UnsafeMutablePointer) -> Void in + + if let attachment = value as? NSTextAttachment { + block(attachment: attachment, range: range) + } + } + } +} From 00b49a7704214527b9fbdb877f2f1b4a3a164a0a Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 31 Oct 2014 16:22:32 -0300 Subject: [PATCH 02/61] Implements UITextView Extension --- .../RichTextView/UITextView+RichTextView.swift | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 WordPress/Classes/ViewRelated/Notifications/RichTextView/UITextView+RichTextView.swift diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/UITextView+RichTextView.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/UITextView+RichTextView.swift new file mode 100644 index 000000000000..e961cb2389d5 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/UITextView+RichTextView.swift @@ -0,0 +1,14 @@ +import Foundation + + +extension UITextView +{ + func frameForTextInRange(range: NSRange) -> CGRect { + let firstPosition = positionFromPosition(beginningOfDocument, offset: range.location) + let lastPosition = positionFromPosition(beginningOfDocument, offset: range.location + range.length) + let textRange = textRangeFromPosition(firstPosition, toPosition: lastPosition) + let textFrame = firstRectForRange(textRange) + + return textFrame + } +} From e898a131c3613714605eb1e661bfc03e0796d920 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 31 Oct 2014 16:22:39 -0300 Subject: [PATCH 03/61] Implements RichTextView --- .../RichTextView/RichTextView.swift | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift new file mode 100644 index 000000000000..944c818c182c --- /dev/null +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift @@ -0,0 +1,176 @@ +import Foundation + + +@objc public protocol RichTextViewDataSource +{ + func viewForTextAttachment(attachment: NSTextAttachment) -> UIView? +} + +@objc public protocol RichTextViewDelegate : UITextViewDelegate +{ + +} + + +@objc public class RichTextView : UIView, UITextViewDelegate +{ + public var dataSource: RichTextViewDataSource? + public var delegate: RichTextViewDelegate? + + + // MARK: - Initializers + public override init() { + super.init() + setupSubviews() + } + + public override init(frame: CGRect) { + super.init(frame: frame) + setupSubviews() + } + + public required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setupSubviews() + } + + public override func layoutSubviews() { + assert(textView != nil) + super.layoutSubviews() + textView.frame = bounds + } + + + // MARK: - Properties + public override var frame: CGRect { + didSet { + setNeedsLayout() + } + } + + public override var bounds: CGRect { + didSet { + setNeedsLayout() + } + } + + public var editable: Bool = false { + didSet { + textView?.editable = editable + } + } + + public var dataDetectorTypes: UIDataDetectorTypes = .None { + didSet { + textView?.dataDetectorTypes = dataDetectorTypes + } + } + + public override var backgroundColor: UIColor? { + didSet { + textView?.backgroundColor = backgroundColor + } + } + + public override func intrinsicContentSize() -> CGSize { + // Fix: Let's add 1pt extra size. There are few scenarios in which text gets clipped by 1 point + let bottomPadding = CGFloat(1) + let maxSize = CGSize(width: frame.width, height: CGFloat.max) + let requiredSize = textView!.sizeThatFits(maxSize) + let roundedSize = CGSize(width: ceil(requiredSize.width), height: ceil(requiredSize.height) + bottomPadding) + + return roundedSize + } + + public var attributedText: NSAttributedString! { + didSet { + assert(textView != nil) + textView.attributedText = attributedText + renderAttachments() + } + } + + + // MARK: - Private Methods + private func setupSubviews() { + textView = UITextView(frame: bounds) + textView.backgroundColor = backgroundColor + textView.contentInset = UIEdgeInsetsZero + textView.textContainerInset = UIEdgeInsetsZero + textView.textContainer.lineFragmentPadding = 0 + textView.layoutManager.allowsNonContiguousLayout = false + textView.editable = editable + textView.dataDetectorTypes = dataDetectorTypes + textView.delegate = self + addSubview(textView) + } + + private func renderAttachments() { + // Nuke old attachments + attachmentViews.map { $0.removeFromSuperview() } + attachmentViews.removeAll(keepCapacity: false) + + // Proceed only if needed + if attributedText == nil { + return + } + + // Load new attachments + attributedText.enumerateAttachments { + (attachment: NSTextAttachment, range: NSRange) -> () in + + let attachmentView = self.dataSource?.viewForTextAttachment(attachment) + if attachmentView == nil { + return + } + + let unwrappedView = attachmentView! + unwrappedView.frame.origin = self.textView.frameForTextInRange(range).integerRect.origin + self.textView.addSubview(unwrappedView) + self.attachmentViews.append(unwrappedView) + } + } + + + // MARK: - UITextViewDelegate Wrapped Methods + public func textViewShouldBeginEditing(textView: UITextView) -> Bool { + return delegate?.textViewShouldBeginEditing?(textView) ?? true + } + + public func textViewShouldEndEditing(textView: UITextView) -> Bool { + return delegate?.textViewShouldEndEditing?(textView) ?? true + } + + public func textViewDidBeginEditing(textView: UITextView) { + delegate?.textViewDidBeginEditing?(textView) + } + + public func textViewDidEndEditing(textView: UITextView) { + delegate?.textViewDidEndEditing?(textView) + } + + public func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { + return delegate?.textView?(textView, shouldChangeTextInRange: range, replacementText: text) ?? true + } + + public func textViewDidChange(textView: UITextView) { + delegate?.textViewDidChange?(textView) + } + + public func textViewDidChangeSelection(textView: UITextView) { + delegate?.textViewDidChangeSelection?(textView) + } + + public func textView(textView: UITextView, shouldInteractWithURL URL: NSURL, inRange characterRange: NSRange) -> Bool { + return delegate?.textView?(textView, shouldInteractWithURL: URL, inRange: characterRange) ?? true + } + + public func textView(textView: UITextView, shouldInteractWithTextAttachment textAttachment: NSTextAttachment, inRange characterRange: NSRange) -> Bool { + return delegate?.textView?(textView, shouldInteractWithTextAttachment: textAttachment, inRange: characterRange) ?? true + } + + + // MARK: - Private Properites + private var textView: UITextView! + private var attachmentViews: [UIView] = [] +} From 53b35efa52a4c9d23ad21a5243295366ca750d15 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 31 Oct 2014 16:22:49 -0300 Subject: [PATCH 04/61] Updates project --- WordPress/WordPress.xcodeproj/project.pbxproj | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 37f79eb7e3b8..27175fc010d7 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -300,6 +300,9 @@ B5CC05F61962150600975CAC /* Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = B5CC05F51962150600975CAC /* Constants.m */; }; B5CC05F91962186D00975CAC /* Meta.m in Sources */ = {isa = PBXBuildFile; fileRef = B5CC05F81962186D00975CAC /* Meta.m */; }; B5CC05FC196218E100975CAC /* XMLParserCollecter.m in Sources */ = {isa = PBXBuildFile; fileRef = B5CC05FB196218E100975CAC /* XMLParserCollecter.m */; }; + B5D7F2DC1A04180A006D3047 /* NSAttributedString+RichTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D7F2D91A04180A006D3047 /* NSAttributedString+RichTextView.swift */; }; + B5D7F2DD1A04180A006D3047 /* RichTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D7F2DA1A04180A006D3047 /* RichTextView.swift */; }; + B5D7F2DE1A04180A006D3047 /* UITextView+RichTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D7F2DB1A04180A006D3047 /* UITextView+RichTextView.swift */; }; B5E167F419C08D18009535AA /* NSCalendar+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E167F319C08D18009535AA /* NSCalendar+Helpers.swift */; }; B5E23BDC19AD0CED000D6879 /* ReplyTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E23BDA19AD0CED000D6879 /* ReplyTextView.swift */; }; B5E23BDD19AD0CED000D6879 /* ReplyTextView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E23BDB19AD0CED000D6879 /* ReplyTextView.xib */; }; @@ -1001,6 +1004,9 @@ B5CC05F81962186D00975CAC /* Meta.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Meta.m; sourceTree = ""; }; B5CC05FA196218E100975CAC /* XMLParserCollecter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XMLParserCollecter.h; sourceTree = ""; }; B5CC05FB196218E100975CAC /* XMLParserCollecter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XMLParserCollecter.m; sourceTree = ""; }; + B5D7F2D91A04180A006D3047 /* NSAttributedString+RichTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+RichTextView.swift"; sourceTree = ""; }; + B5D7F2DA1A04180A006D3047 /* RichTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RichTextView.swift; sourceTree = ""; }; + B5D7F2DB1A04180A006D3047 /* UITextView+RichTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITextView+RichTextView.swift"; sourceTree = ""; }; B5E167F319C08D18009535AA /* NSCalendar+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSCalendar+Helpers.swift"; sourceTree = ""; }; B5E23BDA19AD0CED000D6879 /* ReplyTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyTextView.swift; sourceTree = ""; }; B5E23BDB19AD0CED000D6879 /* ReplyTextView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReplyTextView.xib; sourceTree = ""; }; @@ -2218,6 +2224,7 @@ isa = PBXGroup; children = ( B587798319B799EB00E57C5A /* Notifications */, + B5E167F319C08D18009535AA /* NSCalendar+Helpers.swift */, B587796F19B799D800E57C5A /* NSDate+Helpers.swift */, B587797019B799D800E57C5A /* NSIndexPath+Swift.swift */, B587797119B799D800E57C5A /* NSParagraphStyle+Helpers.swift */, @@ -2228,7 +2235,6 @@ B587797619B799D800E57C5A /* UITableViewCell+Helpers.swift */, B587797719B799D800E57C5A /* UIView+Helpers.swift */, B53FDF6C19B8C336000723B6 /* UIScreen+Helpers.swift */, - B5E167F319C08D18009535AA /* NSCalendar+Helpers.swift */, ); path = Extensions; sourceTree = ""; @@ -2251,6 +2257,16 @@ path = Style; sourceTree = ""; }; + B5D7F2D81A04180A006D3047 /* RichTextView */ = { + isa = PBXGroup; + children = ( + B5D7F2DA1A04180A006D3047 /* RichTextView.swift */, + B5D7F2D91A04180A006D3047 /* NSAttributedString+RichTextView.swift */, + B5D7F2DB1A04180A006D3047 /* UITextView+RichTextView.swift */, + ); + path = RichTextView; + sourceTree = ""; + }; B5E23BD919AD0CED000D6879 /* Tools */ = { isa = PBXGroup; children = ( @@ -2401,6 +2417,7 @@ isa = PBXGroup; children = ( B5B56D2F19AFB68800B4E29B /* Style */, + B5D7F2D81A04180A006D3047 /* RichTextView */, B5E23BD919AD0CED000D6879 /* Tools */, B5FD453E199D0F2800286FBB /* Controllers */, B5FD4523199D0F1100286FBB /* Views */, @@ -3204,6 +3221,7 @@ E1B4A9E112FC8B1000EB3F67 /* EGORefreshTableHeaderView.m in Sources */, 5DF94E521962BAEB00359241 /* ReaderPostRichContentView.m in Sources */, 5DA3EE12192508F700294E0B /* WPImageOptimizer.m in Sources */, + B5D7F2DE1A04180A006D3047 /* UITextView+RichTextView.swift in Sources */, E1D458691309589C00BF0235 /* Coordinate.m in Sources */, 375D090D133B94C3000CC9CD /* BlogsTableViewCell.m in Sources */, 859CFD46190E3198005FB217 /* WPMediaUploader.m in Sources */, @@ -3246,6 +3264,7 @@ B52B4F7A19C0E49B00526D6F /* WPDynamicHeightTextView.swift in Sources */, E1AB07AD1578D34300D6AD64 /* SettingsViewController.m in Sources */, E13EB7A5157D230000885780 /* WordPressComApi.m in Sources */, + B5D7F2DC1A04180A006D3047 /* NSAttributedString+RichTextView.swift in Sources */, 5D5D0027187DA9D30027CEF6 /* CategoriesViewController.m in Sources */, 5DF7389A1965FB3C00393584 /* WPTableViewHandler.m in Sources */, E1E4CE0B1773C59B00430844 /* WPAvatarSource.m in Sources */, @@ -3331,6 +3350,7 @@ 5DBCD9D518F35D7500B32229 /* ReaderTopicService.m in Sources */, 5D42A3DF175E7452005CFF05 /* AbstractPost.m in Sources */, 5D42A3E0175E7452005CFF05 /* BasePost.m in Sources */, + B5D7F2DD1A04180A006D3047 /* RichTextView.swift in Sources */, E1249B4319408C910035E895 /* RemoteComment.m in Sources */, 93DEB88219E5BF7100F9546D /* TodayExtensionService.m in Sources */, 5D42A3E2175E7452005CFF05 /* ReaderPost.m in Sources */, From 8857fd24ae4fa94706449dca54726e753ec5148b Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 31 Oct 2014 18:16:26 -0300 Subject: [PATCH 05/61] NotificationDetailsViewController Cleanup --- .../Controllers/NotificationDetailsViewController.m | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m index 36ba8deb5a85..cb2a3400d185 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m @@ -572,10 +572,7 @@ - (void)setupTextCell:(NoteBlockTextTableViewCell *)cell blockGroup:(Notificatio - (void)openURL:(NSURL *)url { // NOTE: - // - // DTAttributedLabel doesn't allow us to use *any* object as a DTLinkAttribute instance. - // So, we lose the range metadata: is it a post? stats? comment?. - // In this step, we attempt to match the URL with any NotificationRange instance, contained in the note, + // In this step, we attempt to match the URL tapped with any NotificationRange instance, contained in the note, // and thus, recover the metadata! // NotificationRange *range = [self.note notificationRangeWithUrl:url]; @@ -1038,6 +1035,7 @@ - (void)textViewDidEndEditing:(UITextView *)textView self.tableGesturesRecognizer.enabled = false; } + #pragma mark - SuggestionsTableViewDelegate - (void)view:(UIView *)view didTypeInWord:(NSString *)word @@ -1051,6 +1049,7 @@ - (void)suggestionsTableView:(SuggestionsTableView *)suggestionsTableView didSel [suggestionsTableView showSuggestionsForWord:@""]; } + #pragma mark - Gestures Recognizer Delegate - (IBAction)dismissKeyboardIfNeeded:(id)sender From c467f68da7a7071af6fa088531425d8baebc19b7 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 31 Oct 2014 18:27:11 -0300 Subject: [PATCH 06/61] Splits ReplyTextView and Mentions code --- .../NotificationDetailsViewController.m | 104 ++++++++++-------- 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m index cb2a3400d185..a517b97c92b0 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m @@ -226,63 +226,71 @@ - (void)attachReplyViewIfNeeded return; } - // Attach the SuggestionsTableView for WPCOM blogs - NSManagedObjectContext *context = [[ContextManager sharedInstance] mainContext]; - BlogService *service = [[BlogService alloc] initWithManagedObjectContext:context]; - Blog *blog = [service blogByBlogId:self.note.metaSiteID]; - - BOOL shouldAddSuggestionView = (blog.isWPcom && [[SuggestionService sharedInstance] shouldShowSuggestionsForSiteID:self.note.metaSiteID]); - - if (shouldAddSuggestionView) { - self.suggestionsTableView = [[SuggestionsTableView alloc] initWithSiteID:self.note.metaSiteID]; - self.suggestionsTableView.suggestionsDelegate = self; - [self.suggestionsTableView setTranslatesAutoresizingMaskIntoConstraints:NO]; - [self.view addSubview:self.suggestionsTableView]; - } + __typeof(self) __weak weakSelf = self; - __typeof(self) __weak weakSelf = self; - - ReplyTextView *replyTextView = [[ReplyTextView alloc] initWithWidth:CGRectGetWidth(self.view.frame)]; - replyTextView.placeholder = NSLocalizedString(@"Write a reply…", @"Placeholder text for inline compose view"); - replyTextView.replyText = [NSLocalizedString(@"Reply", @"") uppercaseString]; - replyTextView.onReply = ^(NSString *content) { + ReplyTextView *replyTextView = [[ReplyTextView alloc] initWithWidth:CGRectGetWidth(self.view.frame)]; + replyTextView.placeholder = NSLocalizedString(@"Write a reply…", @"Placeholder text for inline compose view"); + replyTextView.replyText = [NSLocalizedString(@"Reply", @"") uppercaseString]; + replyTextView.accessibilityIdentifier = @"Reply Text"; + replyTextView.onReply = ^(NSString *content) { [weakSelf sendReplyWithBlock:block content:content]; }; - replyTextView.delegate = self; - self.replyTextView = replyTextView; - replyTextView.accessibilityIdentifier = @"Reply Text"; + replyTextView.delegate = self; + self.replyTextView = replyTextView; + // Attach the ReplyTextView at the very bottom [self.view addSubview:self.replyTextView]; [self.view pinSubviewAtBottom:self.replyTextView]; [self.view pinSubview:self.tableView aboveSubview:self.replyTextView]; - // If allowing suggestions, set up the reply text view keyboard and suggestion view constraints - if (shouldAddSuggestionView) { - // Set reply text view keyboard type to Twitter to expose the @ key for easy suggesting - [replyTextView setKeyboardType:UIKeyboardTypeTwitter]; - - // Pin the suggestions view left and right edges to the super view edges - NSDictionary *views = @{@"suggestionsview": self.suggestionsTableView }; - [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[suggestionsview]|" - options:0 - metrics:nil - views:views]]; - - // Pin the suggestions view top to the super view top - [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[suggestionsview]" - options:0 - metrics:nil - views:views]]; - - // Pin the suggestions view bottom to the top of the reply box - [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.suggestionsTableView - attribute:NSLayoutAttributeBottom - relatedBy:NSLayoutRelationEqual - toItem:self.replyTextView - attribute:NSLayoutAttributeTop - multiplier:1 - constant:0]]; + // Attach suggestionsView + [self attachSuggestionsViewIfNeeded]; +} + + +#pragma mark - Suggestions View Helpers + +- (void)attachSuggestionsViewIfNeeded +{ + // Proceed only if needed! + NSManagedObjectContext *context = [[ContextManager sharedInstance] mainContext]; + BlogService *service = [[BlogService alloc] initWithManagedObjectContext:context]; + Blog *blog = [service blogByBlogId:self.note.metaSiteID]; + BOOL shouldAddSuggestionView = blog.isWPcom && [[SuggestionService sharedInstance] shouldShowSuggestionsForSiteID:self.note.metaSiteID]; + + if (!shouldAddSuggestionView) { + return; } + + self.suggestionsTableView = [[SuggestionsTableView alloc] initWithSiteID:self.note.metaSiteID]; + self.suggestionsTableView.suggestionsDelegate = self; + [self.suggestionsTableView setTranslatesAutoresizingMaskIntoConstraints:NO]; + [self.view addSubview:self.suggestionsTableView]; + + // Set reply text view keyboard type to Twitter to expose the @ key for easy suggesting + [self.replyTextView setKeyboardType:UIKeyboardTypeTwitter]; + + // Pin the suggestions view left and right edges to the super view edges + NSDictionary *views = @{@"suggestionsview": self.suggestionsTableView }; + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[suggestionsview]|" + options:0 + metrics:nil + views:views]]; + + // Pin the suggestions view top to the super view top + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[suggestionsview]" + options:0 + metrics:nil + views:views]]; + + // Pin the suggestions view bottom to the top of the reply box + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.suggestionsTableView + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationEqual + toItem:self.replyTextView + attribute:NSLayoutAttributeTop + multiplier:1 + constant:0]]; } From 71f4c64db876af8236f5455ae844558a62846ed1 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 31 Oct 2014 18:43:03 -0300 Subject: [PATCH 07/61] Code Cleanup --- WordPress/Classes/Models/Notifications/Notification.h | 10 +++++----- .../Views/NoteBlockImageTableViewCell.swift | 3 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/WordPress/Classes/Models/Notifications/Notification.h b/WordPress/Classes/Models/Notifications/Notification.h index abced555379c..f4650998763e 100644 --- a/WordPress/Classes/Models/Notifications/Notification.h +++ b/WordPress/Classes/Models/Notifications/Notification.h @@ -22,7 +22,7 @@ extern NSString * NoteActionEditKey; typedef NS_ENUM(NSInteger, NoteBlockType) { NoteBlockTypeText, - NoteBlockTypeImage, // BlockTypesImage: Includes Badges and Images + NoteBlockTypeImage, // BlockTypesImage: Includes Badges and Images NoteBlockTypeUser, NoteBlockTypeComment }; @@ -32,9 +32,9 @@ typedef NS_ENUM(NSInteger, NoteBlockGroupType) NoteBlockGroupTypeText = NoteBlockTypeText, NoteBlockGroupTypeImage = NoteBlockTypeImage, NoteBlockGroupTypeUser = NoteBlockTypeUser, - NoteBlockGroupTypeComment = NoteBlockTypeComment, // Contains a User + Comment Block - NoteBlockGroupTypeSubject = 20, // Contains a User + Text Block - NoteBlockGroupTypeHeader = 30 // Contains a User + Text Block + NoteBlockGroupTypeComment = NoteBlockTypeComment, // Contains a User + Comment Block + NoteBlockGroupTypeSubject = 20, // Contains a User + Text Block + NoteBlockGroupTypeHeader = 30 // Contains a User + Text Block }; @@ -109,7 +109,7 @@ typedef NS_ENUM(NSInteger, NoteBlockGroupType) @property (nonatomic, strong, readonly) NSDictionary *actions; // Derived Properties -@property (nonatomic, assign, readonly) NoteBlockType type; +@property (nonatomic, assign, readonly) NoteBlockType type; @property (nonatomic, strong, readonly) NSNumber *metaSiteID; @property (nonatomic, strong, readonly) NSNumber *metaCommentID; @property (nonatomic, strong, readonly) NSString *metaLinksHome; diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockImageTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockImageTableViewCell.swift index 6359841c8497..a698111f9dbe 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockImageTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockImageTableViewCell.swift @@ -35,9 +35,6 @@ import Foundation selectionStyle = .None } - // MARK: - Private Methods - - // MARK: - Private private var imageURL: NSURL? From ccd94b3a76dbdd66632dd7ac6997acf6bd4da246 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 13:33:56 -0300 Subject: [PATCH 08/61] RichTextView: Switching over to Autolayout --- .../Notifications/RichTextView/RichTextView.swift | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift index 944c818c182c..f3a7a59a6b6d 100644 --- a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift @@ -34,12 +34,6 @@ import Foundation setupSubviews() } - public override func layoutSubviews() { - assert(textView != nil) - super.layoutSubviews() - textView.frame = bounds - } - // MARK: - Properties public override var frame: CGRect { @@ -103,6 +97,11 @@ import Foundation textView.dataDetectorTypes = dataDetectorTypes textView.delegate = self addSubview(textView) + + // Setup Layout + setTranslatesAutoresizingMaskIntoConstraints(false) + textView.setTranslatesAutoresizingMaskIntoConstraints(false) + pinSubviewToAllEdges(textView) } private func renderAttachments() { From bbb9de53a023debaf52734a3b1643c8b014313fe Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 13:38:21 -0300 Subject: [PATCH 09/61] RichTextView: Wrapping up extra UITextView properties --- .../RichTextView/RichTextView.swift | 71 ++++++++++++++++--- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift index f3a7a59a6b6d..408bccc90f07 100644 --- a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift @@ -48,11 +48,37 @@ import Foundation } } + public var contentInset: UIEdgeInsets = UIEdgeInsetsZero { + didSet { + textView?.contentInset = contentInset + } + } + + public var textContainerInset: UIEdgeInsets = UIEdgeInsetsZero { + didSet { + textView?.textContainerInset = textContainerInset + } + } + + public var attributedText: NSAttributedString! { + didSet { + assert(textView != nil) + textView.attributedText = attributedText + renderAttachments() + } + } + public var editable: Bool = false { didSet { textView?.editable = editable } } + + public var selectable: Bool = true { + didSet { + textView?.selectable = selectable + } + } public var dataDetectorTypes: UIDataDetectorTypes = .None { didSet { @@ -66,24 +92,51 @@ import Foundation } } + public var linkTextAttributes: [NSObject : AnyObject]! { + didSet { + textView?.linkTextAttributes = linkTextAttributes + } + } + + + // MARK: - TextKit Getters + public var layoutManager: NSLayoutManager { + get { + return textView.layoutManager + } + } + + public var textStorage: NSTextStorage { + get { + return textView.textStorage + } + } + + public var textContainer: NSTextContainer { + get { + return textView.textContainer + } + } + + + // MARK: - Autolayout Helpers + public var preferredMaxLayoutWidth: CGFloat = 0 { + didSet { + invalidateIntrinsicContentSize() + } + } + public override func intrinsicContentSize() -> CGSize { // Fix: Let's add 1pt extra size. There are few scenarios in which text gets clipped by 1 point let bottomPadding = CGFloat(1) - let maxSize = CGSize(width: frame.width, height: CGFloat.max) + let maxWidth = (preferredMaxLayoutWidth != 0) ? preferredMaxLayoutWidth : frame.width + let maxSize = CGSize(width: maxWidth, height: CGFloat.max) let requiredSize = textView!.sizeThatFits(maxSize) let roundedSize = CGSize(width: ceil(requiredSize.width), height: ceil(requiredSize.height) + bottomPadding) return roundedSize } - public var attributedText: NSAttributedString! { - didSet { - assert(textView != nil) - textView.attributedText = attributedText - renderAttachments() - } - } - // MARK: - Private Methods private func setupSubviews() { From e0b74de90bb8eeac4ba5f733e2759adb7714f937 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 13:40:31 -0300 Subject: [PATCH 10/61] CommentTableViewCell: Switching over to RichTextView --- .../Classes/ViewRelated/Comments/CommentTableViewCell.xib | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib b/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib index c71c23d08073..169ee2551f82 100644 --- a/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib +++ b/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib @@ -1,8 +1,8 @@ - + - - + + @@ -54,7 +54,7 @@ - + From 14a097aae5277295771572c085ed6448ccba3e3d Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 13:40:45 -0300 Subject: [PATCH 11/61] Nukes WPDynamicHeightTextView --- .../Utility/WPDynamicHeightTextView.swift | 22 ------------------- WordPress/WordPress.xcodeproj/project.pbxproj | 4 ---- 2 files changed, 26 deletions(-) delete mode 100644 WordPress/Classes/Utility/WPDynamicHeightTextView.swift diff --git a/WordPress/Classes/Utility/WPDynamicHeightTextView.swift b/WordPress/Classes/Utility/WPDynamicHeightTextView.swift deleted file mode 100644 index 6f17a362118a..000000000000 --- a/WordPress/Classes/Utility/WPDynamicHeightTextView.swift +++ /dev/null @@ -1,22 +0,0 @@ -import Foundation - - -public class WPDynamicHeightTextView : UITextView -{ - public var preferredMaxLayoutWidth: CGFloat = 0 { - didSet { - invalidateIntrinsicContentSize() - } - } - - public override func intrinsicContentSize() -> CGSize { - // Fix: Let's add 1pt extra size. There are few scenarios in which text gets clipped by 1 point - let bottomPadding: CGFloat = 1 - let maxWidth = (preferredMaxLayoutWidth != 0) ? preferredMaxLayoutWidth : frame.width - let maxSize = CGSize(width: maxWidth, height: CGFloat.max) - let requiredSize = sizeThatFits(maxSize) - let roundedSize = CGSize(width: ceil(requiredSize.width), height: ceil(requiredSize.height) + bottomPadding) - - return roundedSize - } -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 27175fc010d7..1773168c6d0c 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -263,7 +263,6 @@ ADF544C2195A0F620092213D /* CustomHighlightButton.m in Sources */ = {isa = PBXBuildFile; fileRef = ADF544C1195A0F620092213D /* CustomHighlightButton.m */; }; B5134AF519B2C4F200FADE8C /* ReplyBezierView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5134AF419B2C4F200FADE8C /* ReplyBezierView.swift */; }; B51D9A7E19634D4400CA857B /* Noticons-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = B55853F419630AF900FAF6C3 /* Noticons-Regular.otf */; }; - B52B4F7A19C0E49B00526D6F /* WPDynamicHeightTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52B4F7919C0E49B00526D6F /* WPDynamicHeightTextView.swift */; }; B52C4C7D199D4CD3009FD823 /* NoteBlockUserTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52C4C7C199D4CD3009FD823 /* NoteBlockUserTableViewCell.swift */; }; B52C4C7F199D74AE009FD823 /* NoteTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52C4C7E199D74AE009FD823 /* NoteTableViewCell.swift */; }; B532D4E9199D4357006E4DF6 /* NoteBlockCommentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B532D4E5199D4357006E4DF6 /* NoteBlockCommentTableViewCell.swift */; }; @@ -957,7 +956,6 @@ AEFB66560B716519236CEE67 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "../Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; B43F6A7D9B3DC5B8B4A7DDCA /* Pods-WordPressTest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressTest.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPressTest/Pods-WordPressTest.debug.xcconfig"; sourceTree = ""; }; B5134AF419B2C4F200FADE8C /* ReplyBezierView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyBezierView.swift; sourceTree = ""; }; - B52B4F7919C0E49B00526D6F /* WPDynamicHeightTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WPDynamicHeightTextView.swift; sourceTree = ""; }; B52C4C7C199D4CD3009FD823 /* NoteBlockUserTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoteBlockUserTableViewCell.swift; sourceTree = ""; }; B52C4C7E199D74AE009FD823 /* NoteTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoteTableViewCell.swift; sourceTree = ""; }; B532D4E5199D4357006E4DF6 /* NoteBlockCommentTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoteBlockCommentTableViewCell.swift; sourceTree = ""; }; @@ -2006,7 +2004,6 @@ 8525398A171761D9003F6B32 /* WPComLanguages.m */, E183BD7217621D85000B0822 /* WPCookie.h */, E183BD7317621D86000B0822 /* WPCookie.m */, - B52B4F7919C0E49B00526D6F /* WPDynamicHeightTextView.swift */, E114D798153D85A800984182 /* WPError.h */, E114D799153D85A800984182 /* WPError.m */, 5DA3EE0E192508F700294E0B /* WPImageOptimizer.h */, @@ -3261,7 +3258,6 @@ 5DEB61B8156FCD5200242C35 /* WPChromelessWebViewController.m in Sources */, CC24E5EF1577D1EA00A6D5B5 /* WPFriendFinderViewController.m in Sources */, 5903AE1B19B60A98009D5354 /* WPButtonForNavigationBar.m in Sources */, - B52B4F7A19C0E49B00526D6F /* WPDynamicHeightTextView.swift in Sources */, E1AB07AD1578D34300D6AD64 /* SettingsViewController.m in Sources */, E13EB7A5157D230000885780 /* WordPressComApi.m in Sources */, B5D7F2DC1A04180A006D3047 /* NSAttributedString+RichTextView.swift in Sources */, From d34e7a35cb288034fee10122c9925390a8ac5b4f Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 13:54:54 -0300 Subject: [PATCH 12/61] Notifications: Switching over to RichTextView --- .../Notifications/Notifications.storyboard | 12 ++++++------ .../Views/NoteBlockTextTableViewCell.swift | 10 +++++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard b/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard index 7c0234bec8ea..4d8f03a7f3e9 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard +++ b/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard @@ -1,8 +1,8 @@ - + - + @@ -128,7 +128,7 @@ - + @@ -193,8 +193,8 @@ - - + + @@ -302,7 +302,7 @@ - + diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift index 724c3b777ed0..02523779b26d 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift @@ -11,6 +11,7 @@ import Foundation setNeedsLayout() } } + public var isBadge: Bool = false { didSet { if isBadge { @@ -22,6 +23,7 @@ import Foundation } } } + public var linkColor: UIColor? { didSet { if let unwrappedLinkColor = linkColor { @@ -29,6 +31,7 @@ import Foundation } } } + public var dataDetectors: UIDataDetectorTypes? { didSet { if let unwrappedDataDetectors = dataDetectors { @@ -36,9 +39,11 @@ import Foundation } } } + public var labelPadding: UIEdgeInsets { return privateLabelPadding } + public var isTextViewSelectable: Bool = false { didSet { textView.selectable = isTextViewSelectable @@ -72,7 +77,7 @@ import Foundation backgroundColor = WPStyleGuide.Notifications.blockBackgroundColor selectionStyle = .None - textView.contentInset = privateLabelInsets + textView.contentInset = UIEdgeInsetsZero textView.textContainerInset = UIEdgeInsetsZero textView.backgroundColor = UIColor.clearColor() textView.editable = false @@ -119,11 +124,10 @@ import Foundation // MARK: - Constants private let maxWidth = WPTableViewFixedWidth private let privateLabelPadding = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12) - private let privateLabelInsets = UIEdgeInsets(top: 1, left: -5, bottom: 0, right: 0) // MARK: - Private private var gesturesRecognizer: UITapGestureRecognizer! // MARK: - IBOutlets - @IBOutlet private weak var textView: WPDynamicHeightTextView! + @IBOutlet private weak var textView: RichTextView! } From 26e7793ef99dcb1f647300a790ad2095e3bbad52 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 14:43:22 -0300 Subject: [PATCH 13/61] NotificationBlock: Nukes range failsafe. Fixed backend side --- .../Notifications/NotificationBlock+Interface.swift | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift index b77cc7e00026..f74aff93ec47 100644 --- a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift +++ b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift @@ -13,17 +13,10 @@ extension NotificationBlock theString.applyAttributesToQuotes(WPStyleGuide.Notifications.subjectItalicsStyle) for notificationRange in ranges as [NotificationRange] { - - // Make sure this range is not of bounds! - let range = notificationRange.range - if range.location + range.length > theString.length { - continue - } - if notificationRange.isUser { - theString.addAttributes(WPStyleGuide.Notifications.subjectBoldStyle, range: range) + theString.addAttributes(WPStyleGuide.Notifications.subjectBoldStyle, range: notificationRange.range) } else if notificationRange.isPost || notificationRange.isComment { - theString.addAttributes(WPStyleGuide.Notifications.subjectItalicsStyle, range: range) + theString.addAttributes(WPStyleGuide.Notifications.subjectItalicsStyle, range: notificationRange.range) } } From daaceaa5acdb07de7aa443b6c244cf0336a308be Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 14:51:00 -0300 Subject: [PATCH 14/61] NotificationBlock: Code cleanup --- .../NotificationBlock+Interface.swift | 23 ++++++++++++------- .../NotificationDetailsViewController.m | 2 +- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift index f74aff93ec47..31fee11eff4d 100644 --- a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift +++ b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift @@ -28,12 +28,20 @@ extension NotificationBlock return NSAttributedString() } - return NSMutableAttributedString(string: text, attributes: WPStyleGuide.Notifications.snippetRegularStyle) + return NSAttributedString(string: text, attributes: WPStyleGuide.Notifications.snippetRegularStyle) } public func regularAttributedText() -> NSAttributedString { + // Operations such as editing a comment cause a lag between the REST and Simperium update. + // TextOverride is a transient property meant to store, temporarily, the edited text + return regularAttributedOverride() ?? regularAttributedText() ?? NSAttributedString() + } + + + // MARK: - Private Helpers + private func regularAttributedText() -> NSAttributedString? { if text == nil { - return NSAttributedString() + return nil } let theString = NSMutableAttributedString(string: text, attributes: WPStyleGuide.Notifications.blockRegularStyle) @@ -56,12 +64,11 @@ extension NotificationBlock return theString } - public func regularAttributedTextOverride() -> NSAttributedString? { - // Operations such as editing a comment cause a lag between the REST and Simperium update. - // TextOverride is a transient property meant to store, temporarily, the edited text - if textOverride != nil { - return NSAttributedString(string: textOverride, attributes: WPStyleGuide.Notifications.blockRegularStyle) + private func regularAttributedOverride() -> NSAttributedString? { + if textOverride == nil { + return nil } - return nil + + return NSAttributedString(string: textOverride, attributes: WPStyleGuide.Notifications.blockRegularStyle) } } diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m index a517b97c92b0..87533abc4636 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m @@ -512,7 +512,7 @@ - (void)setupCommentCell:(NoteBlockCommentTableViewCell *)cell blockGroup:(Notif cell.name = userBlock.text; cell.timestamp = [self.note.timestampAsDate shortString]; - cell.attributedCommentText = commentBlock.regularAttributedTextOverride ?: commentBlock.regularAttributedText; + cell.attributedCommentText = commentBlock.regularAttributedText; cell.onUrlClick = ^(NSURL *url){ [weakSelf openURL:url]; From ed3336054dcddcde21e9c0ec57ac190d4be35ee6 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 15:37:26 -0300 Subject: [PATCH 15/61] NotificationBlock: Extension code cleanup --- .../NotificationBlock+Interface.swift | 65 ++++++++----------- .../Comments/CommentTableViewCell.swift | 3 +- 2 files changed, 30 insertions(+), 38 deletions(-) diff --git a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift index 31fee11eff4d..0663928f57d7 100644 --- a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift +++ b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift @@ -4,23 +4,7 @@ import Foundation extension NotificationBlock { public func subjectAttributedText() -> NSAttributedString { - if text == nil { - return NSAttributedString() - } - - let theString = NSMutableAttributedString(string: text, attributes: WPStyleGuide.Notifications.subjectRegularStyle) - - theString.applyAttributesToQuotes(WPStyleGuide.Notifications.subjectItalicsStyle) - - for notificationRange in ranges as [NotificationRange] { - if notificationRange.isUser { - theString.addAttributes(WPStyleGuide.Notifications.subjectBoldStyle, range: notificationRange.range) - } else if notificationRange.isPost || notificationRange.isComment { - theString.addAttributes(WPStyleGuide.Notifications.subjectItalicsStyle, range: notificationRange.range) - } - } - - return theString; + return textWithRangeStyles(isSubject: true) } public func snippetAttributedText() -> NSAttributedString { @@ -34,41 +18,48 @@ extension NotificationBlock public func regularAttributedText() -> NSAttributedString { // Operations such as editing a comment cause a lag between the REST and Simperium update. // TextOverride is a transient property meant to store, temporarily, the edited text - return regularAttributedOverride() ?? regularAttributedText() ?? NSAttributedString() + if textOverride != nil { + return NSAttributedString(string: textOverride, attributes: WPStyleGuide.Notifications.blockRegularStyle(false)) + } + + return textWithRangeStyles(isSubject: false) } // MARK: - Private Helpers - private func regularAttributedText() -> NSAttributedString? { + private func textWithRangeStyles(#isSubject: Bool) -> NSAttributedString { if text == nil { - return nil + return NSAttributedString() } - let theString = NSMutableAttributedString(string: text, attributes: WPStyleGuide.Notifications.blockRegularStyle) + let regularStyle = WPStyleGuide.Notifications.blockRegularStyle(isSubject) + let quotesStyle = WPStyleGuide.Notifications.blockQuotesStyle(isSubject) + let userStyle = WPStyleGuide.Notifications.blockUserStyle(isSubject) + let postStyle = WPStyleGuide.Notifications.blockPostStyle(isSubject) + let commentStyle = WPStyleGuide.Notifications.blockCommentStyle(isSubject) + let blockStyle = WPStyleGuide.Notifications.blockBlockquotedStyle(isSubject) + let linkColor = WPStyleGuide.Notifications.blockLinkColor - theString.applyAttributesToQuotes(WPStyleGuide.Notifications.blockBoldStyle) + let theString = NSMutableAttributedString(string: text, attributes: regularStyle) + theString.applyAttributesToQuotes(quotesStyle) for range in ranges as [NotificationRange] { - if range.isPost { - theString.addAttributes(WPStyleGuide.Notifications.blockItalicsStyle, range: range.range) + if range.isUser { + theString.addAttributes(userStyle, range: range.range) + } else if range.isPost { + theString.addAttributes(postStyle, range: range.range) + } else if range.isComment { + theString.addAttributes(commentStyle, range: range.range) } else if range.isBlockquote { - theString.addAttributes(WPStyleGuide.Notifications.blockQuotedStyle, range: range.range) + theString.addAttributes(blockStyle, range: range.range) } - if range.url != nil { + if isSubject == false && range.url != nil { theString.addAttribute(NSLinkAttributeName, value: range.url, range: range.range) - theString.addAttribute(NSForegroundColorAttributeName, value: WPStyleGuide.Notifications.blockLinkColor, range: range.range) + theString.addAttribute(NSForegroundColorAttributeName, value: linkColor, range: range.range) } } - - return theString - } - - private func regularAttributedOverride() -> NSAttributedString? { - if textOverride == nil { - return nil - } - - return NSAttributedString(string: textOverride, attributes: WPStyleGuide.Notifications.blockRegularStyle) + + return theString; } } diff --git a/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.swift b/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.swift index 6fe2cb3e36c2..cb5deca875a0 100644 --- a/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.swift @@ -17,7 +17,8 @@ import Foundation return } - super.attributedCommentText = NSMutableAttributedString(string: commentText!, attributes: WPStyleGuide.Notifications.blockRegularStyle) + let style = WPStyleGuide.Notifications.blockRegularStyle(false) + super.attributedCommentText = NSMutableAttributedString(string: commentText!, attributes: style) } } } From 617ffcf5cf29839acf0d6e9d9bbefffdaa4ad62e Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 15:39:19 -0300 Subject: [PATCH 16/61] Updates Notifications WPStyleGuide Extension --- .../Style/WPStyleGuide+Notifications.swift | 115 ++++++++++++------ 1 file changed, 77 insertions(+), 38 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift b/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift index 64bc5e0a2262..8e3e6c2fb255 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift @@ -5,7 +5,7 @@ extension WPStyleGuide { public struct Notifications { - // Styles Used by NotificationsViewController + // MARK: - Styles Used by NotificationsViewController // // NoteTableViewCell @@ -17,30 +17,13 @@ extension WPStyleGuide public static let noteBackgroundReadColor = UIColor.whiteColor() public static let noteBackgroundUnreadColor = UIColor(red: 0xF1/255.0, green: 0xF6/255.0, blue: 0xF9/255.0, alpha: 0xFF/255.0) - // Subject Text - public static let subjectColor = WPStyleGuide.littleEddieGrey() - public static let subjectRegularFont = WPFontManager.openSansRegularFontOfSize(subjectFontSize) - public static let subjectBoldFont = WPFontManager.openSansBoldFontOfSize(subjectFontSize) - public static let subjectItalicsFont = WPFontManager.openSansItalicFontOfSize(subjectFontSize) - - public static let subjectRegularStyle = [ NSParagraphStyleAttributeName: subjectParagraph, - NSFontAttributeName: subjectRegularFont, - NSForegroundColorAttributeName: subjectColor ] - - public static let subjectBoldStyle = [ NSParagraphStyleAttributeName: subjectParagraph, - NSFontAttributeName: subjectBoldFont ] - - public static let subjectItalicsStyle = [ NSParagraphStyleAttributeName: subjectParagraph, - NSFontAttributeName: subjectItalicsFont ] - // Subject Snippet - public static let snippetColor = WPStyleGuide.allTAllShadeGrey() + private static let snippetColor = WPStyleGuide.allTAllShadeGrey() public static let snippetRegularStyle = [ NSParagraphStyleAttributeName: snippetParagraph, NSFontAttributeName: subjectRegularFont, NSForegroundColorAttributeName: snippetColor ] - - // Styles used by NotificationDetailsViewController + // MARK: - Styles used by NotificationDetailsViewController // // Header @@ -64,22 +47,6 @@ extension WPStyleGuide public static let blockUnapprovedBgColor = UIColor(red: 0xFF/255.0, green: 0xBA/255.0, blue: 0x00/255.0, alpha: 0x19/255.0) public static let blockUnapprovedTextColor = UIColor(red: 0xF0/255.0, green: 0x82/255.0, blue: 0x1E/255.0, alpha: 0xFF/255.0) - public static let blockRegularStyle = [ NSParagraphStyleAttributeName: blockParagraph, - NSFontAttributeName: blockRegularFont, - NSForegroundColorAttributeName: blockTextColor] - - public static let blockBoldStyle = [ NSParagraphStyleAttributeName: blockParagraph, - NSFontAttributeName: blockBoldFont, - NSForegroundColorAttributeName: blockTextColor] - - public static let blockItalicsStyle = [ NSParagraphStyleAttributeName: blockParagraph, - NSFontAttributeName: blockItalicsFont, - NSForegroundColorAttributeName: blockTextColor] - - public static let blockQuotedStyle = [ NSParagraphStyleAttributeName: blockParagraph, - NSFontAttributeName: blockItalicsFont, - NSForegroundColorAttributeName: blockQuotedColor] - // Badges public static let badgeBackgroundColor = UIColor.clearColor() @@ -87,7 +54,39 @@ extension WPStyleGuide public static let blockActionDisabledColor = UIColor(red: 0x7F/255.0, green: 0x9E/255.0, blue: 0xB4/255.0, alpha: 0xFF/255.0) public static let blockActionEnabledColor = UIColor(red: 0xEA/255.0, green: 0x6D/255.0, blue: 0x1B/255.0, alpha: 0xFF/255.0) - // Helper Methods + + // Block Styling Convenience Helpers + public static func blockRegularStyle(isSubject: Bool) -> [NSString: AnyObject] { + return isSubject ? subjectRegularStyle : blockRegularStyle + } + + public static func blockQuotesStyle(isSubject: Bool) -> [NSString: AnyObject] { + return isSubject ? subjectItalicsStyle : blockBoldStyle + } + + public static func blockUserStyle(isSubject: Bool) -> [NSString: AnyObject] { + return isSubject ? subjectBoldStyle : blockBoldStyle + } + + public static func blockPostStyle(isSubject: Bool) -> [NSString: AnyObject] { + return isSubject ? subjectItalicsStyle : blockItalicsStyle + } + + public static func blockCommentStyle(isSubject: Bool) -> [NSString: AnyObject] { + return isSubject ? subjectItalicsStyle : blockItalicsStyle + } + + public static func blockBlockquotedStyle(isSubject: Bool) -> [NSString: AnyObject] { + return blockQuotedStyle + } + + + // RichText Helpers + public static func blockBackgroundColorForRichText(isBadge: Bool) -> UIColor { + return isBadge ? badgeBackgroundColor : blockBackgroundColor + } + + // Comment Helpers public static func blockParagraphStyleWithIndentation(indentation: CGFloat) -> NSParagraphStyle { let paragraph = blockParagraph.mutableCopy() as NSMutableParagraphStyle paragraph.firstLineHeadIndent = indentation @@ -116,12 +115,17 @@ extension WPStyleGuide return approved ? blockLinkColor : blockUnapprovedTextColor } - // Private + + // MARK: - Private Propreties + // + + // Constants private static let subjectFontSize = UIDevice.isPad() ? CGFloat(16) : CGFloat(14) private static let subjectLineSize = UIDevice.isPad() ? CGFloat(24) : CGFloat(18) private static let blockFontSize = UIDevice.isPad() ? CGFloat(16) : CGFloat(14) private static let blockLineSize = UIDevice.isPad() ? CGFloat(24) : CGFloat(20) + // ParagraphStyle's private static let subjectParagraph = NSMutableParagraphStyle( minLineHeight: subjectLineSize, maxLineHeight: subjectLineSize, lineBreakMode: .ByWordWrapping, alignment: .Left ) @@ -131,5 +135,40 @@ extension WPStyleGuide private static let blockParagraph = NSMutableParagraphStyle( minLineHeight: blockLineSize, maxLineHeight: blockLineSize, lineBreakMode: .ByWordWrapping, alignment: .Left ) + + // Styles + private static let subjectRegularStyle = [ NSParagraphStyleAttributeName: subjectParagraph, + NSFontAttributeName: subjectRegularFont, + NSForegroundColorAttributeName: subjectColor ] + + private static let subjectBoldStyle = [ NSParagraphStyleAttributeName: subjectParagraph, + NSFontAttributeName: subjectBoldFont ] + + private static let subjectItalicsStyle = [ NSParagraphStyleAttributeName: subjectParagraph, + NSFontAttributeName: subjectItalicsFont ] + + private static let blockRegularStyle = [ NSParagraphStyleAttributeName: blockParagraph, + NSFontAttributeName: blockRegularFont, + NSForegroundColorAttributeName: blockTextColor] + + private static let blockBoldStyle = [ NSParagraphStyleAttributeName: blockParagraph, + NSFontAttributeName: blockBoldFont, + NSForegroundColorAttributeName: blockTextColor] + + private static let blockItalicsStyle = [ NSParagraphStyleAttributeName: blockParagraph, + NSFontAttributeName: blockItalicsFont, + NSForegroundColorAttributeName: blockTextColor] + + private static let blockQuotedStyle = [ NSParagraphStyleAttributeName: blockParagraph, + NSFontAttributeName: blockItalicsFont, + NSForegroundColorAttributeName: blockQuotedColor] + + // Colors + private static let subjectColor = WPStyleGuide.littleEddieGrey() + + // Fonts + private static let subjectRegularFont = WPFontManager.openSansRegularFontOfSize(subjectFontSize) + private static let subjectBoldFont = WPFontManager.openSansBoldFontOfSize(subjectFontSize) + private static let subjectItalicsFont = WPFontManager.openSansItalicFontOfSize(subjectFontSize) } } From 151e0e25137402e525d2f0999f5ab37d6740eb39 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 15:41:43 -0300 Subject: [PATCH 17/61] NoteBlockText: Selectable by default --- .../Notifications/Views/NoteBlockTextTableViewCell.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift index 02523779b26d..80600426c04b 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift @@ -44,7 +44,7 @@ import Foundation return privateLabelPadding } - public var isTextViewSelectable: Bool = false { + public var isTextViewSelectable: Bool = true { didSet { textView.selectable = isTextViewSelectable } @@ -81,7 +81,7 @@ import Foundation textView.textContainerInset = UIEdgeInsetsZero textView.backgroundColor = UIColor.clearColor() textView.editable = false - textView.selectable = false + textView.selectable = true textView.dataDetectorTypes = .None // Setup a Gestures Recognizer: This way we'll handle links! From e0387f74a9d797d3fd4342ea96f9efe1f80b2c9c Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 15:42:10 -0300 Subject: [PATCH 18/61] NoteBlockText: Code Cleanup --- .../Notifications/RichTextView/RichTextView.swift | 2 +- .../Views/NoteBlockTextTableViewCell.swift | 11 +++-------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift index 408bccc90f07..3eb51e58c3d2 100644 --- a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift @@ -63,7 +63,7 @@ import Foundation public var attributedText: NSAttributedString! { didSet { assert(textView != nil) - textView.attributedText = attributedText + textView.attributedText = attributedText ?? NSAttributedString() renderAttachments() } } diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift index 80600426c04b..6e3132b22023 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift @@ -7,20 +7,15 @@ import Foundation public var onUrlClick: ((NSURL) -> Void)? public var attributedText: NSAttributedString? { didSet { - textView.attributedText = attributedText ?? NSAttributedString() + textView.attributedText = attributedText setNeedsLayout() } } public var isBadge: Bool = false { didSet { - if isBadge { - backgroundColor = WPStyleGuide.Notifications.badgeBackgroundColor - alignment = .Center - } else { - backgroundColor = WPStyleGuide.Notifications.blockBackgroundColor - alignment = .Left - } + backgroundColor = WPStyleGuide.Notifications.blockBackgroundColorForRichText(isBadge) + alignment = isBadge ? .Center : .Left } } From b45d81e4fc73a7c03dd097857165e4ee9c3bfd53 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 17:41:13 -0300 Subject: [PATCH 19/61] Notification: Wires badge derived property --- .../Models/Notifications/Notification.h | 1 + .../Models/Notifications/Notification.m | 25 ++++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/Models/Notifications/Notification.h b/WordPress/Classes/Models/Notifications/Notification.h index f4650998763e..97cfa895b806 100644 --- a/WordPress/Classes/Models/Notifications/Notification.h +++ b/WordPress/Classes/Models/Notifications/Notification.h @@ -110,6 +110,7 @@ typedef NS_ENUM(NSInteger, NoteBlockGroupType) // Derived Properties @property (nonatomic, assign, readonly) NoteBlockType type; +@property (nonatomic, assign, readonly) BOOL isBadge; @property (nonatomic, strong, readonly) NSNumber *metaSiteID; @property (nonatomic, strong, readonly) NSNumber *metaCommentID; @property (nonatomic, strong, readonly) NSString *metaLinksHome; diff --git a/WordPress/Classes/Models/Notifications/Notification.m b/WordPress/Classes/Models/Notifications/Notification.m index 54b23c47801f..de4625e6721b 100644 --- a/WordPress/Classes/Models/Notifications/Notification.m +++ b/WordPress/Classes/Models/Notifications/Notification.m @@ -200,7 +200,8 @@ + (NSArray *)mediaFromArray:(NSArray *)rawMedia @interface NotificationBlock () @property (nonatomic, strong, readwrite) NSMutableDictionary *actionsOverride; -@property (nonatomic, assign, readwrite) NoteBlockType type; +@property (nonatomic, assign, readwrite) NoteBlockType type; +@property (nonatomic, assign, readwrite) BOOL isBadge; @end @@ -291,6 +292,7 @@ + (NSArray *)blocksFromArray:(NSArray *)rawBlocks notification:(Notification *)n } NSMutableArray *parsed = [NSMutableArray array]; + BOOL isBadge = false; for (NSDictionary *rawDict in rawBlocks) { if (![rawDict isKindOfClass:[NSDictionary class]]) { @@ -320,11 +322,24 @@ + (NSArray *)blocksFromArray:(NSArray *)rawBlocks notification:(Notification *)n } else { block.type = NoteBlockTypeText; } - + + // Figure out if this is a badge + for (NotificationMedia *media in block.media) { + if (media.isBadge) { + isBadge = true; + } + } [parsed addObject:block]; } + // Note: Seriously. Duck typing should be abolished. + if (isBadge) { + for (NotificationBlock *block in parsed) { + block.isBadge = true; + } + } + return parsed; } @@ -539,10 +554,8 @@ - (BOOL)isBadge // for (NotificationBlockGroup *group in self.bodyBlockGroups) { for (NotificationBlock *block in group.blocks) { - for (NotificationMedia *media in block.media) { - if (media.isBadge) { - return true; - } + if (block.isBadge) { + return true; } } } From 69554fd714901c3ea3ebac3a45bcf65aa4acfd25 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 17:41:30 -0300 Subject: [PATCH 20/61] Updates Notifications WPStyleGuide Extension --- .../Style/WPStyleGuide+Notifications.swift | 94 +++++++------------ 1 file changed, 34 insertions(+), 60 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift b/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift index 8e3e6c2fb255..8bcfd8862742 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift @@ -17,6 +17,17 @@ extension WPStyleGuide public static let noteBackgroundReadColor = UIColor.whiteColor() public static let noteBackgroundUnreadColor = UIColor(red: 0xF1/255.0, green: 0xF6/255.0, blue: 0xF9/255.0, alpha: 0xFF/255.0) + // Subject Text + public static let subjectRegularStyle = [ NSParagraphStyleAttributeName: subjectParagraph, + NSFontAttributeName: subjectRegularFont, + NSForegroundColorAttributeName: subjectColor ] + + public static let subjectBoldStyle = [ NSParagraphStyleAttributeName: subjectParagraph, + NSFontAttributeName: subjectBoldFont ] + + public static let subjectItalicsStyle = [ NSParagraphStyleAttributeName: subjectParagraph, + NSFontAttributeName: subjectItalicsFont ] + // Subject Snippet private static let snippetColor = WPStyleGuide.allTAllShadeGrey() public static let snippetRegularStyle = [ NSParagraphStyleAttributeName: snippetParagraph, @@ -47,6 +58,26 @@ extension WPStyleGuide public static let blockUnapprovedBgColor = UIColor(red: 0xFF/255.0, green: 0xBA/255.0, blue: 0x00/255.0, alpha: 0x19/255.0) public static let blockUnapprovedTextColor = UIColor(red: 0xF0/255.0, green: 0x82/255.0, blue: 0x1E/255.0, alpha: 0xFF/255.0) + public static let blockRegularStyle = [ NSParagraphStyleAttributeName: blockParagraph, + NSFontAttributeName: blockRegularFont, + NSForegroundColorAttributeName: blockTextColor] + + public static let blockBoldStyle = [ NSParagraphStyleAttributeName: blockParagraph, + NSFontAttributeName: blockBoldFont, + NSForegroundColorAttributeName: blockTextColor] + + public static let blockItalicsStyle = [ NSParagraphStyleAttributeName: blockParagraph, + NSFontAttributeName: blockItalicsFont, + NSForegroundColorAttributeName: blockTextColor] + + public static let blockQuotedStyle = [ NSParagraphStyleAttributeName: blockParagraph, + NSFontAttributeName: blockItalicsFont, + NSForegroundColorAttributeName: blockQuotedColor] + + public static let blockBadgeStyle = [ NSParagraphStyleAttributeName: badgeParagraph, + NSFontAttributeName: blockRegularFont, + NSForegroundColorAttributeName: blockTextColor] + // Badges public static let badgeBackgroundColor = UIColor.clearColor() @@ -54,33 +85,6 @@ extension WPStyleGuide public static let blockActionDisabledColor = UIColor(red: 0x7F/255.0, green: 0x9E/255.0, blue: 0xB4/255.0, alpha: 0xFF/255.0) public static let blockActionEnabledColor = UIColor(red: 0xEA/255.0, green: 0x6D/255.0, blue: 0x1B/255.0, alpha: 0xFF/255.0) - - // Block Styling Convenience Helpers - public static func blockRegularStyle(isSubject: Bool) -> [NSString: AnyObject] { - return isSubject ? subjectRegularStyle : blockRegularStyle - } - - public static func blockQuotesStyle(isSubject: Bool) -> [NSString: AnyObject] { - return isSubject ? subjectItalicsStyle : blockBoldStyle - } - - public static func blockUserStyle(isSubject: Bool) -> [NSString: AnyObject] { - return isSubject ? subjectBoldStyle : blockBoldStyle - } - - public static func blockPostStyle(isSubject: Bool) -> [NSString: AnyObject] { - return isSubject ? subjectItalicsStyle : blockItalicsStyle - } - - public static func blockCommentStyle(isSubject: Bool) -> [NSString: AnyObject] { - return isSubject ? subjectItalicsStyle : blockItalicsStyle - } - - public static func blockBlockquotedStyle(isSubject: Bool) -> [NSString: AnyObject] { - return blockQuotedStyle - } - - // RichText Helpers public static func blockBackgroundColorForRichText(isBadge: Bool) -> UIColor { return isBadge ? badgeBackgroundColor : blockBackgroundColor @@ -93,12 +97,6 @@ extension WPStyleGuide return paragraph } - public static func blockParagraphStyleWithAlignment(alignment: NSTextAlignment) -> NSParagraphStyle { - let paragraph = blockParagraph.mutableCopy() as NSMutableParagraphStyle - paragraph.alignment = alignment - return paragraph - } - public static func blockTextColorForComment(isApproved approved: Bool) -> UIColor { return approved ? blockTextColor : blockUnapprovedTextColor } @@ -135,33 +133,9 @@ extension WPStyleGuide private static let blockParagraph = NSMutableParagraphStyle( minLineHeight: blockLineSize, maxLineHeight: blockLineSize, lineBreakMode: .ByWordWrapping, alignment: .Left ) - - // Styles - private static let subjectRegularStyle = [ NSParagraphStyleAttributeName: subjectParagraph, - NSFontAttributeName: subjectRegularFont, - NSForegroundColorAttributeName: subjectColor ] - - private static let subjectBoldStyle = [ NSParagraphStyleAttributeName: subjectParagraph, - NSFontAttributeName: subjectBoldFont ] - - private static let subjectItalicsStyle = [ NSParagraphStyleAttributeName: subjectParagraph, - NSFontAttributeName: subjectItalicsFont ] - - private static let blockRegularStyle = [ NSParagraphStyleAttributeName: blockParagraph, - NSFontAttributeName: blockRegularFont, - NSForegroundColorAttributeName: blockTextColor] - - private static let blockBoldStyle = [ NSParagraphStyleAttributeName: blockParagraph, - NSFontAttributeName: blockBoldFont, - NSForegroundColorAttributeName: blockTextColor] - - private static let blockItalicsStyle = [ NSParagraphStyleAttributeName: blockParagraph, - NSFontAttributeName: blockItalicsFont, - NSForegroundColorAttributeName: blockTextColor] - - private static let blockQuotedStyle = [ NSParagraphStyleAttributeName: blockParagraph, - NSFontAttributeName: blockItalicsFont, - NSForegroundColorAttributeName: blockQuotedColor] + private static let badgeParagraph = NSMutableParagraphStyle( + minLineHeight: blockLineSize, maxLineHeight: blockLineSize, lineBreakMode: .ByWordWrapping, alignment: .Center + ) // Colors private static let subjectColor = WPStyleGuide.littleEddieGrey() From ea0ced41de3d721a3a0ba7144fbc285ccd89a011 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 17:41:58 -0300 Subject: [PATCH 21/61] NotificationBlock: Extension code cleanup. Part II --- .../NotificationBlock+Interface.swift | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift index 0663928f57d7..ab94af3cf22f 100644 --- a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift +++ b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift @@ -12,14 +12,14 @@ extension NotificationBlock return NSAttributedString() } - return NSAttributedString(string: text, attributes: WPStyleGuide.Notifications.snippetRegularStyle) + return NSAttributedString(string: text, attributes: Styles.snippetRegularStyle) } public func regularAttributedText() -> NSAttributedString { // Operations such as editing a comment cause a lag between the REST and Simperium update. // TextOverride is a transient property meant to store, temporarily, the edited text if textOverride != nil { - return NSAttributedString(string: textOverride, attributes: WPStyleGuide.Notifications.blockRegularStyle(false)) + return NSAttributedString(string: textOverride, attributes: Styles.blockRegularStyle) } return textWithRangeStyles(isSubject: false) @@ -32,14 +32,15 @@ extension NotificationBlock return NSAttributedString() } - let regularStyle = WPStyleGuide.Notifications.blockRegularStyle(isSubject) - let quotesStyle = WPStyleGuide.Notifications.blockQuotesStyle(isSubject) - let userStyle = WPStyleGuide.Notifications.blockUserStyle(isSubject) - let postStyle = WPStyleGuide.Notifications.blockPostStyle(isSubject) - let commentStyle = WPStyleGuide.Notifications.blockCommentStyle(isSubject) - let blockStyle = WPStyleGuide.Notifications.blockBlockquotedStyle(isSubject) - let linkColor = WPStyleGuide.Notifications.blockLinkColor + // Setup the styles + let regularStyle = isSubject ? Styles.subjectRegularStyle : (isBadge ? Styles.blockBadgeStyle : Styles.blockRegularStyle) + let quotesStyle = isSubject ? Styles.subjectItalicsStyle : Styles.blockBoldStyle + let userStyle = isSubject ? Styles.subjectBoldStyle : Styles.blockBoldStyle + let postStyle = isSubject ? Styles.subjectItalicsStyle : Styles.blockItalicsStyle + let commentStyle = postStyle + let blockStyle = Styles.blockQuotedStyle + // Apply the metadata to the text itself let theString = NSMutableAttributedString(string: text, attributes: regularStyle) theString.applyAttributesToQuotes(quotesStyle) @@ -56,10 +57,12 @@ extension NotificationBlock if isSubject == false && range.url != nil { theString.addAttribute(NSLinkAttributeName, value: range.url, range: range.range) - theString.addAttribute(NSForegroundColorAttributeName, value: linkColor, range: range.range) + theString.addAttribute(NSForegroundColorAttributeName, value: Styles.blockLinkColor, range: range.range) } } return theString; } + + private typealias Styles = WPStyleGuide.Notifications } From 9ae2bc09d857bbe3301503d62d66b78326640d97 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 17:42:06 -0300 Subject: [PATCH 22/61] Fixes CommentTableViewCell --- .../Classes/ViewRelated/Comments/CommentTableViewCell.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.swift b/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.swift index cb5deca875a0..c44619e4fb54 100644 --- a/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.swift @@ -17,7 +17,7 @@ import Foundation return } - let style = WPStyleGuide.Notifications.blockRegularStyle(false) + let style = WPStyleGuide.Notifications.blockRegularStyle super.attributedCommentText = NSMutableAttributedString(string: commentText!, attributes: style) } } From d40ac38da094be8d5b8a7a52a83950787ce2e1a8 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 17:42:23 -0300 Subject: [PATCH 23/61] NoteBlockTableViewCell: Nukes TODO --- .../Views/NoteBlockTextTableViewCell.swift | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift index 6e3132b22023..d6143e7258ec 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift @@ -15,7 +15,6 @@ import Foundation public var isBadge: Bool = false { didSet { backgroundColor = WPStyleGuide.Notifications.blockBackgroundColorForRichText(isBadge) - alignment = isBadge ? .Center : .Left } } @@ -46,26 +45,6 @@ import Foundation } - // TODO: - // Once NotificationDetailsViewController has been migrated to Swift, please, nuke this property, and make sure this class is fed - // with an string already aligned. - // This is temporary workaround since WPStyleGuide+Notifications is swift only. - // - private var alignment : NSTextAlignment = .Left { - didSet { - if attributedText == nil { - return - } - - let unwrappedMutableString = attributedText!.mutableCopy() as NSMutableAttributedString - let range = NSRange(location: 0, length: unwrappedMutableString.length) - let paragraph = WPStyleGuide.Notifications.blockParagraphStyleWithAlignment(.Center) - unwrappedMutableString.addAttribute(NSParagraphStyleAttributeName, value: paragraph, range: range) - - attributedText = unwrappedMutableString - } - } - // MARK: - View Methods public override func awakeFromNib() { super.awakeFromNib() From c5fe21b648dd06a1fed787f069528bc29fcfb1c9 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 3 Nov 2014 19:54:27 -0300 Subject: [PATCH 24/61] Code Cleanup --- .../Controllers/NotificationDetailsViewController.m | 2 +- .../Views/NoteBlockTextTableViewCell.swift | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m index 87533abc4636..22c79ab0b080 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m @@ -568,7 +568,7 @@ - (void)setupTextCell:(NoteBlockTextTableViewCell *)cell blockGroup:(Notificatio __weak __typeof(self) weakSelf = self; cell.attributedText = textBlock.regularAttributedText; - cell.isBadge = self.note.isBadge; + cell.isBadge = textBlock.isBadge; cell.onUrlClick = ^(NSURL *url){ [weakSelf openURL:url]; }; diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift index d6143e7258ec..5c85501c885c 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift @@ -51,23 +51,23 @@ import Foundation backgroundColor = WPStyleGuide.Notifications.blockBackgroundColor selectionStyle = .None + + gesturesRecognizer = UITapGestureRecognizer() + gesturesRecognizer.addTarget(self, action: "handleTap:") + + assert(textView != nil) textView.contentInset = UIEdgeInsetsZero textView.textContainerInset = UIEdgeInsetsZero textView.backgroundColor = UIColor.clearColor() textView.editable = false textView.selectable = true textView.dataDetectorTypes = .None - - // Setup a Gestures Recognizer: This way we'll handle links! - gesturesRecognizer = UITapGestureRecognizer() - gesturesRecognizer.addTarget(self, action: "handleTap:") - textView.gestureRecognizers = [gesturesRecognizer] + textView.gestureRecognizers = [gesturesRecognizer] } public override func layoutSubviews() { // Calculate the TextView's width, before hitting layoutSubviews! textView.preferredMaxLayoutWidth = min(bounds.width, maxWidth) - labelPadding.left - labelPadding.right - super.layoutSubviews() } From d0292cad92ab4de9e1ece7ce210580d6e1b07938 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 4 Nov 2014 11:55:47 -0300 Subject: [PATCH 25/61] RichTextView: Implements Link-Press Helper --- .../RichTextView/RichTextView.swift | 40 ++++++++++++++++-- .../Views/NoteBlockTextTableViewCell.swift | 41 ++++++------------- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift index 3eb51e58c3d2..fc3fd2bdbaa2 100644 --- a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift @@ -3,12 +3,12 @@ import Foundation @objc public protocol RichTextViewDataSource { - func viewForTextAttachment(attachment: NSTextAttachment) -> UIView? + optional func richTextView(richTextView: RichTextView, viewForTextAttachment attachment: NSTextAttachment) -> UIView? } @objc public protocol RichTextViewDelegate : UITextViewDelegate { - + optional func richTextView(richTextView: RichTextView, didPressLink link: NSURL) } @@ -140,6 +140,9 @@ import Foundation // MARK: - Private Methods private func setupSubviews() { + gesturesRecognizer = UITapGestureRecognizer() + gesturesRecognizer.addTarget(self, action: "handleTextViewTap:") + textView = UITextView(frame: bounds) textView.backgroundColor = backgroundColor textView.contentInset = UIEdgeInsetsZero @@ -149,8 +152,9 @@ import Foundation textView.editable = editable textView.dataDetectorTypes = dataDetectorTypes textView.delegate = self + textView.gestureRecognizers = [gesturesRecognizer] addSubview(textView) - + // Setup Layout setTranslatesAutoresizingMaskIntoConstraints(false) textView.setTranslatesAutoresizingMaskIntoConstraints(false) @@ -171,7 +175,7 @@ import Foundation attributedText.enumerateAttachments { (attachment: NSTextAttachment, range: NSRange) -> () in - let attachmentView = self.dataSource?.viewForTextAttachment(attachment) + let attachmentView = self.dataSource?.richTextView?(self, viewForTextAttachment: attachment) if attachmentView == nil { return } @@ -184,6 +188,33 @@ import Foundation } + // MARK: - UITapGestureRecognizer Helpers + public func handleTextViewTap(recognizer: UITapGestureRecognizer) { + + // NOTE: Why do we need this? + // Because this mechanism allows us to disable DataDetectors, and yet, detect taps on links. + // + let textStorage = textView.textStorage + let layoutManager = textView.layoutManager + let textContainer = textView.textContainer + + let locationInTextView = recognizer.locationInView(textView) + let characterIndex = layoutManager.characterIndexForPoint(locationInTextView, + inTextContainer: textContainer, + fractionOfDistanceBetweenInsertionPoints: nil) + + if characterIndex >= textStorage.length { + return + } + + // Load the NSURL instance, if any + let rawURL = textStorage.attribute(NSLinkAttributeName, atIndex: characterIndex, effectiveRange: nil) as? NSURL + if let unwrappedURL = rawURL { + delegate?.richTextView?(self, didPressLink: unwrappedURL) + } + } + + // MARK: - UITextViewDelegate Wrapped Methods public func textViewShouldBeginEditing(textView: UITextView) -> Bool { return delegate?.textViewShouldBeginEditing?(textView) ?? true @@ -224,5 +255,6 @@ import Foundation // MARK: - Private Properites private var textView: UITextView! + private var gesturesRecognizer: UITapGestureRecognizer! private var attachmentViews: [UIView] = [] } diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift index 5c85501c885c..c5f5cfb72114 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift @@ -1,7 +1,7 @@ import Foundation -@objc public class NoteBlockTextTableViewCell : NoteBlockTableViewCell +@objc public class NoteBlockTextTableViewCell : NoteBlockTableViewCell, RichTextViewDataSource, RichTextViewDelegate { // MARK: - Public Properties public var onUrlClick: ((NSURL) -> Void)? @@ -52,9 +52,6 @@ import Foundation backgroundColor = WPStyleGuide.Notifications.blockBackgroundColor selectionStyle = .None - gesturesRecognizer = UITapGestureRecognizer() - gesturesRecognizer.addTarget(self, action: "handleTap:") - assert(textView != nil) textView.contentInset = UIEdgeInsetsZero textView.textContainerInset = UIEdgeInsetsZero @@ -62,7 +59,8 @@ import Foundation textView.editable = false textView.selectable = true textView.dataDetectorTypes = .None - textView.gestureRecognizers = [gesturesRecognizer] + textView.dataSource = self + textView.delegate = self } public override func layoutSubviews() { @@ -72,26 +70,16 @@ import Foundation } - // MARK: - UITapGestureRecognizer Helpers - public func handleTap(recognizer: UITapGestureRecognizer) { - - // Detect the location tapped - let textStorage = textView.textStorage - let layoutManager = textView.layoutManager - let textContainer = textView.textContainer - - let locationInTextView = recognizer.locationInView(textView) - let characterIndex = layoutManager.characterIndexForPoint(locationInTextView, inTextContainer: textContainer, fractionOfDistanceBetweenInsertionPoints: nil) - - if characterIndex >= textStorage.length { - return - } - - // Load the NSURL instance, if any - let rawURL: AnyObject? = textView.textStorage.attribute(NSLinkAttributeName, atIndex: characterIndex, effectiveRange: nil) - if let unwrappedURL = rawURL as? NSURL { - onUrlClick?(unwrappedURL) - } + // MARK: - RichTextView Data Source + + public func richTextView(richTextView: RichTextView, viewForTextAttachment attachment: NSTextAttachment) -> UIView? { +// WARNING: TODO + println("viewForTextAttachment") + return nil + } + + public func richTextView(richTextView: RichTextView, didPressLink link: NSURL) { + onUrlClick?(link) } @@ -99,9 +87,6 @@ import Foundation private let maxWidth = WPTableViewFixedWidth private let privateLabelPadding = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12) - // MARK: - Private - private var gesturesRecognizer: UITapGestureRecognizer! - // MARK: - IBOutlets @IBOutlet private weak var textView: RichTextView! } From e5656a321174b465b6bf36a9f9965e43ac796943 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 4 Nov 2014 11:57:45 -0300 Subject: [PATCH 26/61] Updates RichTextView protocols --- .../Notifications/RichTextView/RichTextView.swift | 8 ++++---- .../Notifications/Views/NoteBlockTextTableViewCell.swift | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift index fc3fd2bdbaa2..868f1da20fba 100644 --- a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift @@ -3,12 +3,12 @@ import Foundation @objc public protocol RichTextViewDataSource { - optional func richTextView(richTextView: RichTextView, viewForTextAttachment attachment: NSTextAttachment) -> UIView? + optional func textView(textView: UITextView, viewForTextAttachment attachment: NSTextAttachment) -> UIView? } @objc public protocol RichTextViewDelegate : UITextViewDelegate { - optional func richTextView(richTextView: RichTextView, didPressLink link: NSURL) + optional func textView(textView: UITextView, didPressLink link: NSURL) } @@ -175,7 +175,7 @@ import Foundation attributedText.enumerateAttachments { (attachment: NSTextAttachment, range: NSRange) -> () in - let attachmentView = self.dataSource?.richTextView?(self, viewForTextAttachment: attachment) + let attachmentView = self.dataSource?.textView?(self.textView, viewForTextAttachment: attachment) if attachmentView == nil { return } @@ -210,7 +210,7 @@ import Foundation // Load the NSURL instance, if any let rawURL = textStorage.attribute(NSLinkAttributeName, atIndex: characterIndex, effectiveRange: nil) as? NSURL if let unwrappedURL = rawURL { - delegate?.richTextView?(self, didPressLink: unwrappedURL) + delegate?.textView?(textView, didPressLink: unwrappedURL) } } diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift index c5f5cfb72114..765ff385e602 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift @@ -72,13 +72,13 @@ import Foundation // MARK: - RichTextView Data Source - public func richTextView(richTextView: RichTextView, viewForTextAttachment attachment: NSTextAttachment) -> UIView? { + public func textView(textView: UITextView, viewForTextAttachment attachment: NSTextAttachment) -> UIView? { // WARNING: TODO println("viewForTextAttachment") return nil } - public func richTextView(richTextView: RichTextView, didPressLink link: NSURL) { + public func textView(textView: UITextView, didPressLink link: NSURL) { onUrlClick?(link) } From 287f84de7d418ebe816e6bcfc200b934519441f4 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 4 Nov 2014 14:39:53 -0300 Subject: [PATCH 27/61] Workaround to fix DTCoreText mess --- .../NSAttributedString+RichTextView.swift | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/NSAttributedString+RichTextView.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/NSAttributedString+RichTextView.swift index d41a99d6efdc..da4d19bbcaab 100644 --- a/WordPress/Classes/ViewRelated/Notifications/RichTextView/NSAttributedString+RichTextView.swift +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/NSAttributedString+RichTextView.swift @@ -1,12 +1,20 @@ import Foundation +import UIKit +// NOTE: +// This is not cool. The reason why we need this constant, is because DTCoreText overrides NSAttachmentAttributeName. +// Even using Swift's namespaces ("UIKit.NSAttachmentAttributeName") doesn't return the right value. +// Please, nuke DTCoreText, and remove this constant. +// +public let UIKitAttachmentAttributeName = "NSAttachment" + extension NSAttributedString { public func enumerateAttachments(block: (attachment: NSTextAttachment, range: NSRange) -> ()) { let range = NSMakeRange(0, length) - - enumerateAttribute(NSAttachmentAttributeName, inRange: range, options: .LongestEffectiveRangeNotRequired) { + + enumerateAttribute(UIKitAttachmentAttributeName, inRange: range, options: .LongestEffectiveRangeNotRequired) { (value: AnyObject!, range: NSRange, stop: UnsafeMutablePointer) -> Void in if let attachment = value as? NSTextAttachment { From bbbdc9f6aa8376410e3677ffc0eb75fa74d26bcc Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 4 Nov 2014 15:24:36 -0300 Subject: [PATCH 28/61] Implements TextImageAttachment --- .../Notifications/RichTextView/TextImageAttachment.swift | 7 +++++++ WordPress/WordPress.xcodeproj/project.pbxproj | 4 ++++ 2 files changed, 11 insertions(+) create mode 100644 WordPress/Classes/ViewRelated/Notifications/RichTextView/TextImageAttachment.swift diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/TextImageAttachment.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/TextImageAttachment.swift new file mode 100644 index 000000000000..e375b19fdf85 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/TextImageAttachment.swift @@ -0,0 +1,7 @@ +import Foundation + + +public class TextImageAttachment : NSTextAttachment +{ + public var url: NSURL? +} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 1773168c6d0c..8de1cfd6b870 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -272,6 +272,7 @@ B532D4EE199D4418006E4DF6 /* NoteBlockImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B532D4ED199D4418006E4DF6 /* NoteBlockImageTableViewCell.swift */; }; B53FDF6D19B8C336000723B6 /* UIScreen+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FDF6C19B8C336000723B6 /* UIScreen+Helpers.swift */; }; B548458219A258890077E7A5 /* UIActionSheet+Helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = B548458119A258890077E7A5 /* UIActionSheet+Helpers.m */; }; + B54FF5FF1A094FEA00352019 /* TextImageAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54FF5FE1A094FEA00352019 /* TextImageAttachment.swift */; }; B5509A9319CA38B3006D2E49 /* EditReplyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B5509A9219CA38B3006D2E49 /* EditReplyViewController.m */; }; B5509A9519CA3B9F006D2E49 /* EditReplyViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5509A9419CA3B9F006D2E49 /* EditReplyViewController.xib */; }; B55853F31962337500FAF6C3 /* NSScanner+Helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = B55853F21962337500FAF6C3 /* NSScanner+Helpers.m */; }; @@ -966,6 +967,7 @@ B53FDF6C19B8C336000723B6 /* UIScreen+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIScreen+Helpers.swift"; sourceTree = ""; }; B548458019A258890077E7A5 /* UIActionSheet+Helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIActionSheet+Helpers.h"; sourceTree = ""; }; B548458119A258890077E7A5 /* UIActionSheet+Helpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIActionSheet+Helpers.m"; sourceTree = ""; }; + B54FF5FE1A094FEA00352019 /* TextImageAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextImageAttachment.swift; sourceTree = ""; }; B5509A9119CA38B3006D2E49 /* EditReplyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditReplyViewController.h; sourceTree = ""; }; B5509A9219CA38B3006D2E49 /* EditReplyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditReplyViewController.m; sourceTree = ""; }; B5509A9419CA3B9F006D2E49 /* EditReplyViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = EditReplyViewController.xib; path = Resources/EditReplyViewController.xib; sourceTree = ""; }; @@ -2260,6 +2262,7 @@ B5D7F2DA1A04180A006D3047 /* RichTextView.swift */, B5D7F2D91A04180A006D3047 /* NSAttributedString+RichTextView.swift */, B5D7F2DB1A04180A006D3047 /* UITextView+RichTextView.swift */, + B54FF5FE1A094FEA00352019 /* TextImageAttachment.swift */, ); path = RichTextView; sourceTree = ""; @@ -3400,6 +3403,7 @@ E1D086E2194214C600F0CC19 /* NSDate+WordPressJSON.m in Sources */, 5D839AAB187F0D8000811F4A /* PostGeolocationCell.m in Sources */, A2DC5B1A1953451B009584C3 /* WPNUXHelpBadgeLabel.m in Sources */, + B54FF5FF1A094FEA00352019 /* TextImageAttachment.swift in Sources */, B532D4EA199D4357006E4DF6 /* NoteBlockHeaderTableViewCell.swift in Sources */, 319D6E8519E44F7F0013871C /* SuggestionsTableViewCell.m in Sources */, E1AC282D18282423004D394C /* SFHFKeychainUtils.m in Sources */, From 1bc0033b126fed4111ea4de29563349e371a5564 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Tue, 4 Nov 2014 15:25:37 -0300 Subject: [PATCH 29/61] NotificationBlock: Implements richAttributedText Helper --- .../NotificationBlock+Interface.swift | 24 +++++++++++++++++-- .../NotificationDetailsViewController.m | 4 ++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift index ab94af3cf22f..286e232508bc 100644 --- a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift +++ b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift @@ -15,7 +15,7 @@ extension NotificationBlock return NSAttributedString(string: text, attributes: Styles.snippetRegularStyle) } - public func regularAttributedText() -> NSAttributedString { + public func richAttributedText() -> NSAttributedString { // Operations such as editing a comment cause a lag between the REST and Simperium update. // TextOverride is a transient property meant to store, temporarily, the edited text if textOverride != nil { @@ -40,7 +40,7 @@ extension NotificationBlock let commentStyle = postStyle let blockStyle = Styles.blockQuotedStyle - // Apply the metadata to the text itself + // Format the String let theString = NSMutableAttributedString(string: text, attributes: regularStyle) theString.applyAttributesToQuotes(quotesStyle) @@ -55,14 +55,34 @@ extension NotificationBlock theString.addAttributes(blockStyle, range: range.range) } + // Don't Highlight Links in the subject if isSubject == false && range.url != nil { theString.addAttribute(NSLinkAttributeName, value: range.url, range: range.range) theString.addAttribute(NSForegroundColorAttributeName, value: Styles.blockLinkColor, range: range.range) } } + // Don't embed images in the subject + if isSubject { + return theString + } + + // Embed only Images -For now!- + for theMedia in media as [NotificationMedia] { + if theMedia.isImage == false { + continue + } + + let imageAttachment = TextImageAttachment() + imageAttachment.url = theMedia.mediaURL + imageAttachment.bounds = CGRect(origin: CGPointZero, size: theMedia.size) + let attachmentString = NSAttributedString(attachment: imageAttachment) + theString.replaceCharactersInRange(theMedia.range, withAttributedString: attachmentString) + } + return theString; } + private typealias Styles = WPStyleGuide.Notifications } diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m index 22c79ab0b080..8e2030d4a880 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m @@ -512,7 +512,7 @@ - (void)setupCommentCell:(NoteBlockCommentTableViewCell *)cell blockGroup:(Notif cell.name = userBlock.text; cell.timestamp = [self.note.timestampAsDate shortString]; - cell.attributedCommentText = commentBlock.regularAttributedText; + cell.attributedCommentText = commentBlock.richAttributedText; cell.onUrlClick = ^(NSURL *url){ [weakSelf openURL:url]; @@ -567,7 +567,7 @@ - (void)setupTextCell:(NoteBlockTextTableViewCell *)cell blockGroup:(Notificatio __weak __typeof(self) weakSelf = self; - cell.attributedText = textBlock.regularAttributedText; + cell.attributedText = textBlock.richAttributedText; cell.isBadge = textBlock.isBadge; cell.onUrlClick = ^(NSURL *url){ [weakSelf openURL:url]; From 3280e5366afd014afda0173c145564f62515b1c8 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Wed, 5 Nov 2014 11:57:08 -0300 Subject: [PATCH 30/61] Nukes TextImageAttachment --- .../Notifications/RichTextView/TextImageAttachment.swift | 7 ------- WordPress/WordPress.xcodeproj/project.pbxproj | 4 ---- 2 files changed, 11 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Notifications/RichTextView/TextImageAttachment.swift diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/TextImageAttachment.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/TextImageAttachment.swift deleted file mode 100644 index e375b19fdf85..000000000000 --- a/WordPress/Classes/ViewRelated/Notifications/RichTextView/TextImageAttachment.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - - -public class TextImageAttachment : NSTextAttachment -{ - public var url: NSURL? -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 28a7a6ad160f..6261eccb1d50 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -272,7 +272,6 @@ B532D4EE199D4418006E4DF6 /* NoteBlockImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B532D4ED199D4418006E4DF6 /* NoteBlockImageTableViewCell.swift */; }; B53FDF6D19B8C336000723B6 /* UIScreen+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FDF6C19B8C336000723B6 /* UIScreen+Helpers.swift */; }; B548458219A258890077E7A5 /* UIActionSheet+Helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = B548458119A258890077E7A5 /* UIActionSheet+Helpers.m */; }; - B54FF5FF1A094FEA00352019 /* TextImageAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54FF5FE1A094FEA00352019 /* TextImageAttachment.swift */; }; B5509A9319CA38B3006D2E49 /* EditReplyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B5509A9219CA38B3006D2E49 /* EditReplyViewController.m */; }; B5509A9519CA3B9F006D2E49 /* EditReplyViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5509A9419CA3B9F006D2E49 /* EditReplyViewController.xib */; }; B55853F31962337500FAF6C3 /* NSScanner+Helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = B55853F21962337500FAF6C3 /* NSScanner+Helpers.m */; }; @@ -967,7 +966,6 @@ B53FDF6C19B8C336000723B6 /* UIScreen+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIScreen+Helpers.swift"; sourceTree = ""; }; B548458019A258890077E7A5 /* UIActionSheet+Helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIActionSheet+Helpers.h"; sourceTree = ""; }; B548458119A258890077E7A5 /* UIActionSheet+Helpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIActionSheet+Helpers.m"; sourceTree = ""; }; - B54FF5FE1A094FEA00352019 /* TextImageAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextImageAttachment.swift; sourceTree = ""; }; B5509A9119CA38B3006D2E49 /* EditReplyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditReplyViewController.h; sourceTree = ""; }; B5509A9219CA38B3006D2E49 /* EditReplyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditReplyViewController.m; sourceTree = ""; }; B5509A9419CA3B9F006D2E49 /* EditReplyViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = EditReplyViewController.xib; path = Resources/EditReplyViewController.xib; sourceTree = ""; }; @@ -2262,7 +2260,6 @@ B5D7F2DA1A04180A006D3047 /* RichTextView.swift */, B5D7F2D91A04180A006D3047 /* NSAttributedString+RichTextView.swift */, B5D7F2DB1A04180A006D3047 /* UITextView+RichTextView.swift */, - B54FF5FE1A094FEA00352019 /* TextImageAttachment.swift */, ); path = RichTextView; sourceTree = ""; @@ -3403,7 +3400,6 @@ E1D086E2194214C600F0CC19 /* NSDate+WordPressJSON.m in Sources */, 5D839AAB187F0D8000811F4A /* PostGeolocationCell.m in Sources */, A2DC5B1A1953451B009584C3 /* WPNUXHelpBadgeLabel.m in Sources */, - B54FF5FF1A094FEA00352019 /* TextImageAttachment.swift in Sources */, B532D4EA199D4357006E4DF6 /* NoteBlockHeaderTableViewCell.swift in Sources */, 319D6E8519E44F7F0013871C /* SuggestionsTableViewCell.m in Sources */, E1AC282D18282423004D394C /* SFHFKeychainUtils.m in Sources */, From d836900b6a4d587134f858c886a184ef3f7c78fb Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Wed, 5 Nov 2014 11:58:54 -0300 Subject: [PATCH 31/61] NoteBlockTextTableViewCell: Nukes RichTextView Helper --- .../Notifications/Views/NoteBlockTextTableViewCell.swift | 7 ------- 1 file changed, 7 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift index 765ff385e602..4ed4a07fe39e 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift @@ -71,13 +71,6 @@ import Foundation // MARK: - RichTextView Data Source - - public func textView(textView: UITextView, viewForTextAttachment attachment: NSTextAttachment) -> UIView? { -// WARNING: TODO - println("viewForTextAttachment") - return nil - } - public func textView(textView: UITextView, didPressLink link: NSURL) { onUrlClick?(link) } From 2f33d6c8a1431db5d9ae73bf832f6eb94c6aab98 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Wed, 5 Nov 2014 12:01:15 -0300 Subject: [PATCH 32/61] NotificationDetails: Fixes alignments --- .../NotificationDetailsViewController.m | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m index 8e2030d4a880..a46168e581cf 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m @@ -99,16 +99,17 @@ - (void)viewDidLoad { [super viewDidLoad]; - self.title = self.note.title; - self.restorationClass = [self class]; - self.view.backgroundColor = [WPStyleGuide itsEverywhereGrey]; + self.title = self.note.title; + self.restorationClass = [self class]; + self.view.backgroundColor = [WPStyleGuide itsEverywhereGrey]; // Don't show the notification title in the next-view's back button UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:[NSString string] style:UIBarButtonItemStylePlain target:nil action:nil]; - self.navigationItem.backBarButtonItem = backButton; + self.navigationItem.backBarButtonItem = backButton; - self.tableView.separatorStyle = self.note.isBadge ? UITableViewCellSeparatorStyleNone : UITableViewCellSeparatorStyleSingleLine; - self.tableView.backgroundColor = [WPStyleGuide itsEverywhereGrey]; + self.tableView.separatorStyle = self.note.isBadge ? UITableViewCellSeparatorStyleNone : UITableViewCellSeparatorStyleSingleLine; + self.tableView.backgroundColor = [WPStyleGuide itsEverywhereGrey]; + self.tableView.accessibilityIdentifier = @"Notification Details Table"; self.reuseIdentifierMap = @{ @(NoteBlockGroupTypeHeader) : NoteBlockHeaderTableViewCell.reuseIdentifier, @@ -123,7 +124,6 @@ - (void)viewDidLoad selector:@selector(handleNotificationChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:context]; - self.tableView.accessibilityIdentifier = @"Notification Details Table"; } - (void)viewWillAppear:(BOOL)animated From 7c9ef2f584e1cdcf3f1a257b0a124bb830f714e9 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Wed, 5 Nov 2014 12:09:51 -0300 Subject: [PATCH 33/61] Notification: Implements helper method --- .../Classes/Models/Notifications/Notification.h | 3 +++ .../Classes/Models/Notifications/Notification.m | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/WordPress/Classes/Models/Notifications/Notification.h b/WordPress/Classes/Models/Notifications/Notification.h index 97cfa895b806..831467c49cae 100644 --- a/WordPress/Classes/Models/Notifications/Notification.h +++ b/WordPress/Classes/Models/Notifications/Notification.h @@ -19,6 +19,8 @@ extern NSString * NoteActionReplyKey; extern NSString * NoteActionApproveKey; extern NSString * NoteActionEditKey; +extern NSString * NoteMediaTypeImage; + typedef NS_ENUM(NSInteger, NoteBlockType) { NoteBlockTypeText, @@ -120,6 +122,7 @@ typedef NS_ENUM(NSInteger, NoteBlockGroupType) @property (nonatomic, strong, readwrite) NSString *textOverride; - (NotificationRange *)notificationRangeWithUrl:(NSURL *)url; +- (NSArray *)notificationMediaOfType:(NSString *)type; - (void)setActionOverrideValue:(NSNumber *)obj forKey:(NSString *)key; - (void)removeActionOverrideForKey:(NSString *)key; diff --git a/WordPress/Classes/Models/Notifications/Notification.m b/WordPress/Classes/Models/Notifications/Notification.m index de4625e6721b..77bbd4ad9af4 100644 --- a/WordPress/Classes/Models/Notifications/Notification.m +++ b/WordPress/Classes/Models/Notifications/Notification.m @@ -256,6 +256,19 @@ - (NotificationRange *)notificationRangeWithUrl:(NSURL *)url return nil; } +- (NSArray *)notificationMediaOfType:(NSString *)type +{ + NSMutableArray *theMedia = [NSMutableArray array]; + + for (NotificationMedia *media in self.media) { + if ([media.type isEqualToString:type]) { + [theMedia addObject:media]; + } + } + + return theMedia; +} + - (void)setActionOverrideValue:(NSNumber *)value forKey:(NSString *)key { if (!_actionsOverride) { From 2d8417ecc0c2abcc1e144a02c738ec4f077b6e86 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Wed, 5 Nov 2014 12:38:55 -0300 Subject: [PATCH 34/61] Updates ReplyTextView Location --- .../ReplyBezierView.swift | 0 .../ReplyTextView.swift | 0 .../ReplyTextView.xib | 0 WordPress/WordPress.xcodeproj/project.pbxproj | 32 ++++++++++++------- 4 files changed, 20 insertions(+), 12 deletions(-) rename WordPress/Classes/ViewRelated/Notifications/{Tools => ReplyTextView}/ReplyBezierView.swift (100%) rename WordPress/Classes/ViewRelated/Notifications/{Tools => ReplyTextView}/ReplyTextView.swift (100%) rename WordPress/Classes/ViewRelated/Notifications/{Tools => ReplyTextView}/ReplyTextView.xib (100%) diff --git a/WordPress/Classes/ViewRelated/Notifications/Tools/ReplyBezierView.swift b/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyBezierView.swift similarity index 100% rename from WordPress/Classes/ViewRelated/Notifications/Tools/ReplyBezierView.swift rename to WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyBezierView.swift diff --git a/WordPress/Classes/ViewRelated/Notifications/Tools/ReplyTextView.swift b/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.swift similarity index 100% rename from WordPress/Classes/ViewRelated/Notifications/Tools/ReplyTextView.swift rename to WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.swift diff --git a/WordPress/Classes/ViewRelated/Notifications/Tools/ReplyTextView.xib b/WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.xib similarity index 100% rename from WordPress/Classes/ViewRelated/Notifications/Tools/ReplyTextView.xib rename to WordPress/Classes/ViewRelated/Notifications/ReplyTextView/ReplyTextView.xib diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 6261eccb1d50..678ecc80e3e7 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -261,7 +261,6 @@ ACBAB6860E1247F700F38795 /* PostPreviewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ACBAB6850E1247F700F38795 /* PostPreviewViewController.m */; }; ACC156CC0E10E67600D6E1A0 /* WPPostViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = ACC156CB0E10E67600D6E1A0 /* WPPostViewController.m */; }; ADF544C2195A0F620092213D /* CustomHighlightButton.m in Sources */ = {isa = PBXBuildFile; fileRef = ADF544C1195A0F620092213D /* CustomHighlightButton.m */; }; - B5134AF519B2C4F200FADE8C /* ReplyBezierView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5134AF419B2C4F200FADE8C /* ReplyBezierView.swift */; }; B51D9A7E19634D4400CA857B /* Noticons-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = B55853F419630AF900FAF6C3 /* Noticons-Regular.otf */; }; B52C4C7D199D4CD3009FD823 /* NoteBlockUserTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52C4C7C199D4CD3009FD823 /* NoteBlockUserTableViewCell.swift */; }; B52C4C7F199D74AE009FD823 /* NoteTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B52C4C7E199D74AE009FD823 /* NoteTableViewCell.swift */; }; @@ -272,6 +271,9 @@ B532D4EE199D4418006E4DF6 /* NoteBlockImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B532D4ED199D4418006E4DF6 /* NoteBlockImageTableViewCell.swift */; }; B53FDF6D19B8C336000723B6 /* UIScreen+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FDF6C19B8C336000723B6 /* UIScreen+Helpers.swift */; }; B548458219A258890077E7A5 /* UIActionSheet+Helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = B548458119A258890077E7A5 /* UIActionSheet+Helpers.m */; }; + B54E1DF01A0A7BAA00807537 /* ReplyBezierView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54E1DED1A0A7BAA00807537 /* ReplyBezierView.swift */; }; + B54E1DF11A0A7BAA00807537 /* ReplyTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54E1DEE1A0A7BAA00807537 /* ReplyTextView.swift */; }; + B54E1DF21A0A7BAA00807537 /* ReplyTextView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B54E1DEF1A0A7BAA00807537 /* ReplyTextView.xib */; }; B5509A9319CA38B3006D2E49 /* EditReplyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B5509A9219CA38B3006D2E49 /* EditReplyViewController.m */; }; B5509A9519CA3B9F006D2E49 /* EditReplyViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5509A9419CA3B9F006D2E49 /* EditReplyViewController.xib */; }; B55853F31962337500FAF6C3 /* NSScanner+Helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = B55853F21962337500FAF6C3 /* NSScanner+Helpers.m */; }; @@ -303,8 +305,6 @@ B5D7F2DD1A04180A006D3047 /* RichTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D7F2DA1A04180A006D3047 /* RichTextView.swift */; }; B5D7F2DE1A04180A006D3047 /* UITextView+RichTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D7F2DB1A04180A006D3047 /* UITextView+RichTextView.swift */; }; B5E167F419C08D18009535AA /* NSCalendar+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E167F319C08D18009535AA /* NSCalendar+Helpers.swift */; }; - B5E23BDC19AD0CED000D6879 /* ReplyTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E23BDA19AD0CED000D6879 /* ReplyTextView.swift */; }; - B5E23BDD19AD0CED000D6879 /* ReplyTextView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E23BDB19AD0CED000D6879 /* ReplyTextView.xib */; }; B5E23BDF19AD0D00000D6879 /* NoteTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E23BDE19AD0D00000D6879 /* NoteTableViewCell.xib */; }; B5F015CB195DFD7600F6ECF2 /* WordPressActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = B5F015CA195DFD7600F6ECF2 /* WordPressActivity.m */; }; B5FD4543199D0F2800286FBB /* NotificationDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B5FD4540199D0F2800286FBB /* NotificationDetailsViewController.m */; }; @@ -955,7 +955,6 @@ ADF544C1195A0F620092213D /* CustomHighlightButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomHighlightButton.m; sourceTree = ""; }; AEFB66560B716519236CEE67 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "../Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; B43F6A7D9B3DC5B8B4A7DDCA /* Pods-WordPressTest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressTest.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPressTest/Pods-WordPressTest.debug.xcconfig"; sourceTree = ""; }; - B5134AF419B2C4F200FADE8C /* ReplyBezierView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyBezierView.swift; sourceTree = ""; }; B52C4C7C199D4CD3009FD823 /* NoteBlockUserTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoteBlockUserTableViewCell.swift; sourceTree = ""; }; B52C4C7E199D74AE009FD823 /* NoteTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoteTableViewCell.swift; sourceTree = ""; }; B532D4E5199D4357006E4DF6 /* NoteBlockCommentTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoteBlockCommentTableViewCell.swift; sourceTree = ""; }; @@ -966,6 +965,9 @@ B53FDF6C19B8C336000723B6 /* UIScreen+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIScreen+Helpers.swift"; sourceTree = ""; }; B548458019A258890077E7A5 /* UIActionSheet+Helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIActionSheet+Helpers.h"; sourceTree = ""; }; B548458119A258890077E7A5 /* UIActionSheet+Helpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIActionSheet+Helpers.m"; sourceTree = ""; }; + B54E1DED1A0A7BAA00807537 /* ReplyBezierView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyBezierView.swift; sourceTree = ""; }; + B54E1DEE1A0A7BAA00807537 /* ReplyTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyTextView.swift; sourceTree = ""; }; + B54E1DEF1A0A7BAA00807537 /* ReplyTextView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReplyTextView.xib; sourceTree = ""; }; B5509A9119CA38B3006D2E49 /* EditReplyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditReplyViewController.h; sourceTree = ""; }; B5509A9219CA38B3006D2E49 /* EditReplyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditReplyViewController.m; sourceTree = ""; }; B5509A9419CA3B9F006D2E49 /* EditReplyViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = EditReplyViewController.xib; path = Resources/EditReplyViewController.xib; sourceTree = ""; }; @@ -1006,8 +1008,6 @@ B5D7F2DA1A04180A006D3047 /* RichTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RichTextView.swift; sourceTree = ""; }; B5D7F2DB1A04180A006D3047 /* UITextView+RichTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UITextView+RichTextView.swift"; sourceTree = ""; }; B5E167F319C08D18009535AA /* NSCalendar+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSCalendar+Helpers.swift"; sourceTree = ""; }; - B5E23BDA19AD0CED000D6879 /* ReplyTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyTextView.swift; sourceTree = ""; }; - B5E23BDB19AD0CED000D6879 /* ReplyTextView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReplyTextView.xib; sourceTree = ""; }; B5E23BDE19AD0D00000D6879 /* NoteTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NoteTableViewCell.xib; sourceTree = ""; }; B5F015C9195DFD7600F6ECF2 /* WordPressActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WordPressActivity.h; sourceTree = ""; }; B5F015CA195DFD7600F6ECF2 /* WordPressActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WordPressActivity.m; sourceTree = ""; }; @@ -2217,6 +2217,16 @@ path = Notifications; sourceTree = ""; }; + B54E1DEC1A0A7BAA00807537 /* ReplyTextView */ = { + isa = PBXGroup; + children = ( + B54E1DED1A0A7BAA00807537 /* ReplyBezierView.swift */, + B54E1DEE1A0A7BAA00807537 /* ReplyTextView.swift */, + B54E1DEF1A0A7BAA00807537 /* ReplyTextView.xib */, + ); + path = ReplyTextView; + sourceTree = ""; + }; B587796C19B799D800E57C5A /* Extensions */ = { isa = PBXGroup; children = ( @@ -2267,9 +2277,6 @@ B5E23BD919AD0CED000D6879 /* Tools */ = { isa = PBXGroup; children = ( - B5E23BDA19AD0CED000D6879 /* ReplyTextView.swift */, - B5E23BDB19AD0CED000D6879 /* ReplyTextView.xib */, - B5134AF419B2C4F200FADE8C /* ReplyBezierView.swift */, ); path = Tools; sourceTree = ""; @@ -2415,6 +2422,7 @@ children = ( B5B56D2F19AFB68800B4E29B /* Style */, B5D7F2D81A04180A006D3047 /* RichTextView */, + B54E1DEC1A0A7BAA00807537 /* ReplyTextView */, B5E23BD919AD0CED000D6879 /* Tools */, B5FD453E199D0F2800286FBB /* Controllers */, B5FD4523199D0F1100286FBB /* Views */, @@ -2892,12 +2900,12 @@ 74C1C30E199170EA0077A7DC /* PostDetailViewController~ipad.xib in Resources */, 8370D10C11FA4A1B009D650F /* WPTableViewActivityCell.xib in Resources */, 8370D1BE11FA6295009D650F /* AddSiteViewController.xib in Resources */, - B5E23BDD19AD0CED000D6879 /* ReplyTextView.xib in Resources */, 8333FE0E11FF6EF200A495C1 /* EditSiteViewController.xib in Resources */, 74C1C306199170930077A7DC /* PostDetailViewController.xib in Resources */, 5DF94E331962B9D800359241 /* WPAlertView.xib in Resources */, 8362C1041201E7CE00599347 /* WebSignupViewController-iPad.xib in Resources */, 83CAD4211235F9F4003DFA20 /* MediaObjectView.xib in Resources */, + B54E1DF21A0A7BAA00807537 /* ReplyTextView.xib in Resources */, 3768BEF213041E7900E7C9A9 /* BetaFeedbackViewController.xib in Resources */, 313AE4A319E3F20400AAFABE /* CommentTableViewHeaderCell.xib in Resources */, E1D91456134A853D0089019C /* Localizable.strings in Resources */, @@ -3277,7 +3285,6 @@ 5D44EB351986D695008B7175 /* ReaderSiteServiceRemote.m in Sources */, 5DA5BF4318E32DCF005F11F9 /* MediaSearchFilterHeaderView.m in Sources */, 5DF94E441962BAA700359241 /* WPContentView.m in Sources */, - B5E23BDC19AD0CED000D6879 /* ReplyTextView.swift in Sources */, 5DB4683B18A2E718004A89A9 /* LocationService.m in Sources */, 93740DCB17D8F86700C41B2F /* WPAlertView.m in Sources */, E1D04D7E19374CFE002FADD7 /* BlogServiceRemoteXMLRPC.m in Sources */, @@ -3337,6 +3344,7 @@ 5DAE40AD19EC70930011A0AE /* ReaderPostHeaderView.m in Sources */, 74BB6F1A19AE7B9400FB7829 /* WPLegacyEditPageViewController.m in Sources */, 85B6F7521742DAE800CE7F3A /* WPNUXBackButton.m in Sources */, + B54E1DF01A0A7BAA00807537 /* ReplyBezierView.swift in Sources */, 5DF738941965FAB900393584 /* SubscribedTopicsViewController.m in Sources */, E2E7EB46185FB140004F5E72 /* WPBlogSelectorButton.m in Sources */, E183BD7417621D87000B0822 /* WPCookie.m in Sources */, @@ -3359,7 +3367,7 @@ 85D2275918F1EB8A001DA8DA /* WPAnalyticsTrackerMixpanel.m in Sources */, E149D64F19349E69006A843D /* AccountServiceRemoteXMLRPC.m in Sources */, E1DF5DFE19E7CFAE004E70D5 /* CategoryServiceRemoteXMLRPC.m in Sources */, - B5134AF519B2C4F200FADE8C /* ReplyBezierView.swift in Sources */, + B54E1DF11A0A7BAA00807537 /* ReplyTextView.swift in Sources */, 5DF94E461962BAA700359241 /* WPRichTextView.m in Sources */, 5D42A3FB175E75EE005CFF05 /* ReaderPostDetailViewController.m in Sources */, E18EE94E19349EBA00B0A40C /* BlogServiceRemote.m in Sources */, From 3bb4d3c8f6ee82b3a1b59b9093188a17e5b1b734 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Wed, 5 Nov 2014 13:52:29 -0300 Subject: [PATCH 35/61] Updates NotificationBlock richText Helper --- .../NotificationBlock+Interface.swift | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift index 286e232508bc..529d65917d72 100644 --- a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift +++ b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift @@ -4,7 +4,7 @@ import Foundation extension NotificationBlock { public func subjectAttributedText() -> NSAttributedString { - return textWithRangeStyles(isSubject: true) + return textWithRangeStyles(isSubject: true, mediaMap: nil) } public func snippetAttributedText() -> NSAttributedString { @@ -15,19 +15,19 @@ extension NotificationBlock return NSAttributedString(string: text, attributes: Styles.snippetRegularStyle) } - public func richAttributedText() -> NSAttributedString { + public func richAttributedTextWithEmbeddedImages(mediaMap: [NSURL: UIImage]?) -> NSAttributedString { // Operations such as editing a comment cause a lag between the REST and Simperium update. // TextOverride is a transient property meant to store, temporarily, the edited text if textOverride != nil { return NSAttributedString(string: textOverride, attributes: Styles.blockRegularStyle) } - return textWithRangeStyles(isSubject: false) + return textWithRangeStyles(isSubject: false, mediaMap: mediaMap) } // MARK: - Private Helpers - private func textWithRangeStyles(#isSubject: Bool) -> NSAttributedString { + private func textWithRangeStyles(#isSubject: Bool, mediaMap: [NSURL: UIImage]?) -> NSAttributedString { if text == nil { return NSAttributedString() } @@ -61,21 +61,24 @@ extension NotificationBlock theString.addAttribute(NSForegroundColorAttributeName, value: Styles.blockLinkColor, range: range.range) } } - - // Don't embed images in the subject - if isSubject { + + // Embed the images, if needed + if mediaMap == nil { return theString } - // Embed only Images -For now!- + let unwrappedMediaMap = mediaMap! for theMedia in media as [NotificationMedia] { - if theMedia.isImage == false { + + let image = unwrappedMediaMap[theMedia.mediaURL] + if theMedia.isImage == false || image == nil { continue } - let imageAttachment = TextImageAttachment() - imageAttachment.url = theMedia.mediaURL - imageAttachment.bounds = CGRect(origin: CGPointZero, size: theMedia.size) + let imageAttachment = NSTextAttachment() + imageAttachment.bounds = CGRect(origin: CGPointZero, size: image!.size) + imageAttachment.image = image! + let attachmentString = NSAttributedString(attachment: imageAttachment) theString.replaceCharactersInRange(theMedia.range, withAttributedString: attachmentString) } From e0354dec1eba941522e9b7070ba27a35801c883a Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Wed, 5 Nov 2014 14:41:22 -0300 Subject: [PATCH 36/61] Notification: Updates helper methods --- .../Models/Notifications/Notification.h | 3 +- .../Models/Notifications/Notification.m | 36 ++++++++++++++----- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/WordPress/Classes/Models/Notifications/Notification.h b/WordPress/Classes/Models/Notifications/Notification.h index 831467c49cae..b1a9451eb21a 100644 --- a/WordPress/Classes/Models/Notifications/Notification.h +++ b/WordPress/Classes/Models/Notifications/Notification.h @@ -94,6 +94,7 @@ typedef NS_ENUM(NSInteger, NoteBlockGroupType) @property (nonatomic, assign, readonly) NoteBlockGroupType type; - (NotificationBlock *)blockOfType:(NoteBlockType)type; +- (NSArray *)imageUrlsForBlocksOfTypes:(NSSet *)types; @end @@ -122,7 +123,7 @@ typedef NS_ENUM(NSInteger, NoteBlockGroupType) @property (nonatomic, strong, readwrite) NSString *textOverride; - (NotificationRange *)notificationRangeWithUrl:(NSURL *)url; -- (NSArray *)notificationMediaOfType:(NSString *)type; +- (NSArray *)imageUrls; - (void)setActionOverrideValue:(NSNumber *)obj forKey:(NSString *)key; - (void)removeActionOverrideForKey:(NSString *)key; diff --git a/WordPress/Classes/Models/Notifications/Notification.m b/WordPress/Classes/Models/Notifications/Notification.m index 77bbd4ad9af4..83027e6da66f 100644 --- a/WordPress/Classes/Models/Notifications/Notification.m +++ b/WordPress/Classes/Models/Notifications/Notification.m @@ -256,17 +256,17 @@ - (NotificationRange *)notificationRangeWithUrl:(NSURL *)url return nil; } -- (NSArray *)notificationMediaOfType:(NSString *)type +- (NSArray *)imageUrls { - NSMutableArray *theMedia = [NSMutableArray array]; - + NSMutableArray *urls = [NSMutableArray array]; + for (NotificationMedia *media in self.media) { - if ([media.type isEqualToString:type]) { - [theMedia addObject:media]; + if (media.isImage && media.mediaURL != nil) { + [urls addObject:media.mediaURL]; } } - - return theMedia; + + return urls; } - (void)setActionOverrideValue:(NSNumber *)value forKey:(NSString *)key @@ -364,8 +364,8 @@ + (NSArray *)blocksFromArray:(NSArray *)rawBlocks notification:(Notification *)n #pragma mark ==================================================================================== @interface NotificationBlockGroup () -@property (nonatomic, strong) NSArray *blocks; -@property (nonatomic, assign) NoteBlockGroupType type; +@property (nonatomic, strong) NSArray *blocks; +@property (nonatomic, assign) NoteBlockGroupType type; @end @implementation NotificationBlockGroup @@ -380,6 +380,24 @@ - (NotificationBlock *)blockOfType:(NoteBlockType)type return nil; } +- (NSArray *)imageUrlsForBlocksOfTypes:(NSSet *)types +{ + NSMutableArray *urls = [NSMutableArray array]; + + for (NotificationBlock *block in self.blocks) { + if ([types containsObject:@(block.type)] == false) { + continue; + } + + NSArray *imageUrls = [block imageUrls]; + if (imageUrls) { + [urls addObjectsFromArray:imageUrls]; + } + } + + return urls; +} + + (NotificationBlockGroup *)groupWithBlocks:(NSArray *)blocks type:(NoteBlockGroupType)type { NotificationBlockGroup *group = [self new]; From ed679a1dca623ddbbabee612b7f13816e4cad366 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Wed, 5 Nov 2014 15:19:35 -0300 Subject: [PATCH 37/61] Updates Bridging Header --- WordPress/Classes/System/WordPress-Bridging-Header.h | 1 + 1 file changed, 1 insertion(+) diff --git a/WordPress/Classes/System/WordPress-Bridging-Header.h b/WordPress/Classes/System/WordPress-Bridging-Header.h index 6a9d22829540..687c3448ba9b 100644 --- a/WordPress/Classes/System/WordPress-Bridging-Header.h +++ b/WordPress/Classes/System/WordPress-Bridging-Header.h @@ -1,3 +1,4 @@ +#import #import #import "Notification.h" From c96c4034b22c0075af0322095af37d7691b0d9f3 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Wed, 5 Nov 2014 15:19:54 -0300 Subject: [PATCH 38/61] Implements NotificationMediaDownloader --- .../Tools/NotificationMediaDownloader.swift | 96 +++++++++++++++++++ WordPress/WordPress.xcodeproj/project.pbxproj | 4 + 2 files changed, 100 insertions(+) create mode 100644 WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift diff --git a/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift b/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift new file mode 100644 index 000000000000..415914083bf9 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift @@ -0,0 +1,96 @@ +import Foundation + + +@objc public class NotificationMediaDownloader : NSObject +{ + deinit { + downloadQueue.cancelAllOperations() + } + + public override init() { + downloadQueue = NSOperationQueue() + mediaMap = [NSURL: UIImage]() + responseSerializer = AFImageResponseSerializer() as AFImageResponseSerializer + super.init() + } + + // MARK: - Public Helpers + public func downloadMediaWithUrls(urls: [NSURL], completion: (() -> ())) { + let missingUrls = urls.filter { self.shouldDownloadImageWithURL($0) } + if missingUrls.count == 0 { + return + } + + let group = dispatch_group_create() + for url in missingUrls { + + dispatch_group_enter(group) + downloadImageWithURL(url, callback: { (NSError error, UIImage image) -> () in + dispatch_group_leave(group) + }) + } + + // Hit the callback when we're ready + dispatch_group_notify(group, dispatch_get_main_queue()) { () -> Void in + completion() + } + } + + public func imagesForUrls(urls: [NSURL]) -> [NSURL: UIImage] { + var filtered = [NSURL: UIImage]() + for (url, image) in mediaMap { + if contains(urls, url) { + filtered[url] = image + } + } + + return filtered + } + + + // MARK: - Networking Wrappers + private func downloadImageWithURL(url: NSURL, callback: ((NSError?, UIImage?) -> ())) { + let request = NSMutableURLRequest(URL: url) + request.HTTPShouldHandleCookies = false + request.addValue("image/*", forHTTPHeaderField: "Accept") + + let operation = AFHTTPRequestOperation(request: request) + operation.responseSerializer = responseSerializer + operation.setCompletionBlockWithSuccess({ + [weak self] + (AFHTTPRequestOperation operation, AnyObject responseObject) -> Void in + + if let unwrappedImage = responseObject as? UIImage { + self?.mediaMap[url] = unwrappedImage + callback(nil, unwrappedImage) + } + + }, failure: { + (AFHTTPRequestOperation operation, NSError error) -> Void in + callback(error, nil) + }) + + downloadQueue.addOperation(operation) + } + + private func shouldDownloadImageWithURL(url: NSURL!) -> Bool { + // Download only if it's not cached, and if it's not being downloaded right now! + if url == nil || mediaMap[url] != nil { + return false + } + + for operation in downloadQueue.operations as [AFHTTPRequestOperation] { + if operation.request.URL.isEqual(url) { + return false + } + } + + return true + } + + + // MARK: - Private Properties + private let responseSerializer: AFHTTPResponseSerializer + private let downloadQueue: NSOperationQueue + private var mediaMap: [NSURL: UIImage] +} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 678ecc80e3e7..7f50952454ba 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -274,6 +274,7 @@ B54E1DF01A0A7BAA00807537 /* ReplyBezierView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54E1DED1A0A7BAA00807537 /* ReplyBezierView.swift */; }; B54E1DF11A0A7BAA00807537 /* ReplyTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54E1DEE1A0A7BAA00807537 /* ReplyTextView.swift */; }; B54E1DF21A0A7BAA00807537 /* ReplyTextView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B54E1DEF1A0A7BAA00807537 /* ReplyTextView.xib */; }; + B54E1DF41A0A7BBF00807537 /* NotificationMediaDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54E1DF31A0A7BBF00807537 /* NotificationMediaDownloader.swift */; }; B5509A9319CA38B3006D2E49 /* EditReplyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B5509A9219CA38B3006D2E49 /* EditReplyViewController.m */; }; B5509A9519CA3B9F006D2E49 /* EditReplyViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5509A9419CA3B9F006D2E49 /* EditReplyViewController.xib */; }; B55853F31962337500FAF6C3 /* NSScanner+Helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = B55853F21962337500FAF6C3 /* NSScanner+Helpers.m */; }; @@ -968,6 +969,7 @@ B54E1DED1A0A7BAA00807537 /* ReplyBezierView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyBezierView.swift; sourceTree = ""; }; B54E1DEE1A0A7BAA00807537 /* ReplyTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyTextView.swift; sourceTree = ""; }; B54E1DEF1A0A7BAA00807537 /* ReplyTextView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReplyTextView.xib; sourceTree = ""; }; + B54E1DF31A0A7BBF00807537 /* NotificationMediaDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationMediaDownloader.swift; sourceTree = ""; }; B5509A9119CA38B3006D2E49 /* EditReplyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditReplyViewController.h; sourceTree = ""; }; B5509A9219CA38B3006D2E49 /* EditReplyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EditReplyViewController.m; sourceTree = ""; }; B5509A9419CA3B9F006D2E49 /* EditReplyViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = EditReplyViewController.xib; path = Resources/EditReplyViewController.xib; sourceTree = ""; }; @@ -2277,6 +2279,7 @@ B5E23BD919AD0CED000D6879 /* Tools */ = { isa = PBXGroup; children = ( + B54E1DF31A0A7BBF00807537 /* NotificationMediaDownloader.swift */, ); path = Tools; sourceTree = ""; @@ -3389,6 +3392,7 @@ FF3DD6BE19F2B6B3003A52CB /* RemoteMedia.m in Sources */, B5FD4543199D0F2800286FBB /* NotificationDetailsViewController.m in Sources */, 74D5FFD619ACDF6700389E8F /* WPLegacyEditPostViewController.m in Sources */, + B54E1DF41A0A7BBF00807537 /* NotificationMediaDownloader.swift in Sources */, E174F6E6172A73960004F23A /* WPAccount.m in Sources */, E100C6BB1741473000AE48D8 /* WordPress-11-12.xcmappingmodel in Sources */, E1A03EE217422DCF0085D192 /* BlogToAccount.m in Sources */, From 240fe0ef385a2582bee219a6c0289afbee0b04b1 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Wed, 5 Nov 2014 15:20:07 -0300 Subject: [PATCH 39/61] Wires NotificationMediaDownloader --- .../NotificationDetailsViewController.m | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m index a46168e581cf..895cbf02dd2a 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m @@ -73,6 +73,9 @@ @interface NotificationDetailsViewController () Date: Wed, 5 Nov 2014 17:31:36 -0300 Subject: [PATCH 40/61] Nukes dead nib --- WordPress/Resources/InlineComposeView.xib | 63 ------------------- WordPress/WordPress.xcodeproj/project.pbxproj | 4 -- 2 files changed, 67 deletions(-) delete mode 100644 WordPress/Resources/InlineComposeView.xib diff --git a/WordPress/Resources/InlineComposeView.xib b/WordPress/Resources/InlineComposeView.xib deleted file mode 100644 index 1c70ed23ecb5..000000000000 --- a/WordPress/Resources/InlineComposeView.xib +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 7f50952454ba..ea4fef3c3996 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -319,7 +319,6 @@ CC24E5EF1577D1EA00A6D5B5 /* WPFriendFinderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CC24E5EE1577D1EA00A6D5B5 /* WPFriendFinderViewController.m */; }; CC24E5F11577DBC300A6D5B5 /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CC24E5F01577DBC300A6D5B5 /* AddressBook.framework */; }; CC24E5F51577E16B00A6D5B5 /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CC24E5F41577E16B00A6D5B5 /* Accounts.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; - CC70165B185A7536007B37DB /* InlineComposeView.xib in Resources */ = {isa = PBXBuildFile; fileRef = CC70165A185A7536007B37DB /* InlineComposeView.xib */; }; CCEF153114C9EA050001176D /* WPWebAppViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CCEF153014C9EA050001176D /* WPWebAppViewController.m */; }; CEBD3EAB0FF1BA3B00C1396E /* Blog.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBD3EAA0FF1BA3B00C1396E /* Blog.m */; }; E100C6BB1741473000AE48D8 /* WordPress-11-12.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = E100C6BA1741472F00AE48D8 /* WordPress-11-12.xcmappingmodel */; }; @@ -1039,7 +1038,6 @@ CC24E5F01577DBC300A6D5B5 /* AddressBook.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; CC24E5F21577DFF400A6D5B5 /* Twitter.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; }; CC24E5F41577E16B00A6D5B5 /* Accounts.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; }; - CC70165A185A7536007B37DB /* InlineComposeView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = InlineComposeView.xib; path = Resources/InlineComposeView.xib; sourceTree = ""; }; CCEF152F14C9EA050001176D /* WPWebAppViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WPWebAppViewController.h; sourceTree = ""; }; CCEF153014C9EA050001176D /* WPWebAppViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPWebAppViewController.m; sourceTree = ""; }; CEBD3EA90FF1BA3B00C1396E /* Blog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Blog.h; sourceTree = ""; }; @@ -2621,7 +2619,6 @@ 28AD735F0D9D9599002E5188 /* MainWindow.xib */, 30AF6CF413C2289600A29C00 /* AboutViewController.xib */, 3768BEF013041E7900E7C9A9 /* BetaFeedbackViewController.xib */, - CC70165A185A7536007B37DB /* InlineComposeView.xib */, 5DF94E311962B9D800359241 /* WPAlertView.xib */, 5DF94E321962B9D800359241 /* WPAlertViewSideBySide.xib */, ); @@ -2924,7 +2921,6 @@ 85ED988817DFA00000090D0B /* Images.xcassets in Resources */, 5DC02A3818E4C5BD009A1765 /* ThemeDetailsViewController.xib in Resources */, 313AE4A219E3F20400AAFABE /* CommentTableViewCell.xib in Resources */, - CC70165B185A7536007B37DB /* InlineComposeView.xib in Resources */, 3716E401167296D30035F8C4 /* ToastView.xib in Resources */, 5DA5BF3E18E32DCF005F11F9 /* EditMediaViewController.xib in Resources */, B5509A9519CA3B9F006D2E49 /* EditReplyViewController.xib in Resources */, From 1c388df72178f68408ff2b6258e0dddf4006b8bf Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 12:06:00 -0300 Subject: [PATCH 41/61] Updating nibs: switching over to RichTextView --- .../ViewRelated/Comments/CommentTableViewCell.xib | 4 ++-- .../Notifications/Notifications.storyboard | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib b/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib index 0e9829739b48..1b521406defd 100644 --- a/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib +++ b/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib @@ -1,5 +1,5 @@ - + @@ -66,7 +66,7 @@ - + diff --git a/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard b/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard index fefb0ef9e304..75d5c17597a3 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard +++ b/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard @@ -1,5 +1,5 @@ - + @@ -120,7 +120,7 @@ - + @@ -171,7 +171,7 @@ - - + + From ffa9a1e1050fb44557fe0b52da7924de4fa2baed Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 12:11:14 -0300 Subject: [PATCH 42/61] Notification Downloader: Updates signature --- .../Notifications/Tools/NotificationMediaDownloader.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift b/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift index 415914083bf9..c9d937285a8e 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift @@ -15,7 +15,9 @@ import Foundation } // MARK: - Public Helpers - public func downloadMediaWithUrls(urls: [NSURL], completion: (() -> ())) { + public typealias SuccessBlock = (()->()) + + public func downloadMediaWithUrls(urls: [NSURL], completion: SuccessBlock) { let missingUrls = urls.filter { self.shouldDownloadImageWithURL($0) } if missingUrls.count == 0 { return From 1188f4c9ddb965ad9363d5d9dfe45333cd08fb96 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 12:13:27 -0300 Subject: [PATCH 43/61] Notification Downloader: Updates callback sequence --- .../Tools/NotificationMediaDownloader.swift | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift b/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift index c9d937285a8e..5bc515ecfc32 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift @@ -23,19 +23,11 @@ import Foundation return } - let group = dispatch_group_create() for url in missingUrls { - - dispatch_group_enter(group) downloadImageWithURL(url, callback: { (NSError error, UIImage image) -> () in - dispatch_group_leave(group) + completion() }) } - - // Hit the callback when we're ready - dispatch_group_notify(group, dispatch_get_main_queue()) { () -> Void in - completion() - } } public func imagesForUrls(urls: [NSURL]) -> [NSURL: UIImage] { From 32fdf71f6910b12d55321686f3bafd285bca4cc2 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 12:14:47 -0300 Subject: [PATCH 44/61] RichTextView: Nukes redundant setters --- .../Notifications/RichTextView/RichTextView.swift | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift index 868f1da20fba..194b0413feea 100644 --- a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift @@ -35,19 +35,7 @@ import Foundation } - // MARK: - Properties - public override var frame: CGRect { - didSet { - setNeedsLayout() - } - } - - public override var bounds: CGRect { - didSet { - setNeedsLayout() - } - } - + // MARK: - Properties public var contentInset: UIEdgeInsets = UIEdgeInsetsZero { didSet { textView?.contentInset = contentInset From f10796e383cac054aca81443445ae5d131eea2ac Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 14:14:26 -0300 Subject: [PATCH 45/61] NotificationBlock: Compensates for Attachment Lengths --- .../NotificationBlock+Interface.swift | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift index 529d65917d72..c724d47225d3 100644 --- a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift +++ b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift @@ -67,7 +67,9 @@ extension NotificationBlock return theString } - let unwrappedMediaMap = mediaMap! + let unwrappedMediaMap = mediaMap! + var rangeDelta = Int(0) + for theMedia in media as [NotificationMedia] { let image = unwrappedMediaMap[theMedia.mediaURL] @@ -75,12 +77,22 @@ extension NotificationBlock continue } + // Proceed attaching the media let imageAttachment = NSTextAttachment() imageAttachment.bounds = CGRect(origin: CGPointZero, size: image!.size) imageAttachment.image = image! + // Each time we insert an attachment, we're changing the string length. Compensate for that! let attachmentString = NSAttributedString(attachment: imageAttachment) - theString.replaceCharactersInRange(theMedia.range, withAttributedString: attachmentString) + var correctedRange = theMedia.range + correctedRange.location += rangeDelta + + let lastPosition = correctedRange.location + correctedRange.length + if lastPosition <= theString.length { + theString.replaceCharactersInRange(correctedRange, withAttributedString: attachmentString) + } + + rangeDelta += attachmentString.length } return theString; From abe6c33bb4a389966cd4fa142b19a99c8be6670d Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 17:18:11 -0300 Subject: [PATCH 46/61] WPStyleGuide: Nukes unused method --- .../Notifications/Style/WPStyleGuide+Notifications.swift | 6 ------ 1 file changed, 6 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift b/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift index 5be5c72a4e79..c464e2357aac 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift @@ -92,12 +92,6 @@ extension WPStyleGuide } // Comment Helpers - public static func blockParagraphStyleWithIndentation(indentation: CGFloat) -> NSParagraphStyle { - let paragraph = blockParagraph.mutableCopy() as NSMutableParagraphStyle - paragraph.firstLineHeadIndent = indentation - return paragraph - } - public static func blockTextColorForComment(isApproved approved: Bool) -> UIColor { return approved ? blockTextColor : blockUnapprovedTextColor } From 236b45ba2a4b57083d6fa8ee066c4cdcb5948c28 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 17:18:24 -0300 Subject: [PATCH 47/61] Notifications: Fixes line height clipping glitch --- .../Classes/Extensions/NSParagraphStyle+Helpers.swift | 8 ++++++-- .../Notifications/Style/WPStyleGuide+Notifications.swift | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/WordPress/Classes/Extensions/NSParagraphStyle+Helpers.swift b/WordPress/Classes/Extensions/NSParagraphStyle+Helpers.swift index f9c2fd419cb1..efccda6515d4 100644 --- a/WordPress/Classes/Extensions/NSParagraphStyle+Helpers.swift +++ b/WordPress/Classes/Extensions/NSParagraphStyle+Helpers.swift @@ -3,11 +3,15 @@ import Foundation extension NSMutableParagraphStyle { - convenience init(minLineHeight: CGFloat, maxLineHeight: CGFloat, lineBreakMode: NSLineBreakMode, alignment: NSTextAlignment) { + convenience init(minLineHeight: CGFloat, lineBreakMode: NSLineBreakMode, alignment: NSTextAlignment) { self.init() self.minimumLineHeight = minLineHeight - self.maximumLineHeight = maxLineHeight self.lineBreakMode = lineBreakMode self.alignment = alignment } + + convenience init(minLineHeight: CGFloat, maxLineHeight: CGFloat, lineBreakMode: NSLineBreakMode, alignment: NSTextAlignment) { + self.init(minLineHeight: minLineHeight, lineBreakMode: lineBreakMode, alignment: alignment) + self.maximumLineHeight = maxLineHeight + } } diff --git a/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift b/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift index c464e2357aac..b7c2fb62e502 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Style/WPStyleGuide+Notifications.swift @@ -126,7 +126,7 @@ extension WPStyleGuide minLineHeight: subjectLineSize, maxLineHeight: subjectLineSize, lineBreakMode: .ByTruncatingTail, alignment: .Left ) private static let blockParagraph = NSMutableParagraphStyle( - minLineHeight: blockLineSize, maxLineHeight: blockLineSize, lineBreakMode: .ByWordWrapping, alignment: .Left + minLineHeight: blockLineSize, lineBreakMode: .ByWordWrapping, alignment: .Left ) private static let badgeParagraph = NSMutableParagraphStyle( minLineHeight: blockLineSize, maxLineHeight: blockLineSize, lineBreakMode: .ByWordWrapping, alignment: .Center From 043f6204a40947c7984217014da36554f43e44a7 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 17:20:28 -0300 Subject: [PATCH 48/61] Notifications Storyboard: Updates constraints --- .../ViewRelated/Notifications/Notifications.storyboard | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard b/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard index 75d5c17597a3..5d88acd1029b 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard +++ b/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard @@ -197,7 +197,7 @@ - + @@ -293,7 +293,7 @@ - + From b868541c92d4b3f6537a0cfb5c2cef4585fde04a Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 17:42:39 -0300 Subject: [PATCH 49/61] NotificationMediaDownloader: Prevents dupe urls --- WordPress/Classes/Models/Notifications/Notification.h | 2 +- WordPress/Classes/Models/Notifications/Notification.m | 4 ++-- .../Controllers/NotificationDetailsViewController.m | 2 +- .../Tools/NotificationMediaDownloader.swift | 9 +++++++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/WordPress/Classes/Models/Notifications/Notification.h b/WordPress/Classes/Models/Notifications/Notification.h index d32f41d4ffab..39e66b25cc09 100644 --- a/WordPress/Classes/Models/Notifications/Notification.h +++ b/WordPress/Classes/Models/Notifications/Notification.h @@ -96,7 +96,7 @@ typedef NS_ENUM(NSInteger, NoteBlockGroupType) @property (nonatomic, assign, readonly) NoteBlockGroupType type; - (NotificationBlock *)blockOfType:(NoteBlockType)type; -- (NSArray *)imageUrlsForBlocksOfTypes:(NSSet *)types; +- (NSSet *)imageUrlsForBlocksOfTypes:(NSSet *)types; @end diff --git a/WordPress/Classes/Models/Notifications/Notification.m b/WordPress/Classes/Models/Notifications/Notification.m index d824c0bf498b..9c7d57ba4ea8 100644 --- a/WordPress/Classes/Models/Notifications/Notification.m +++ b/WordPress/Classes/Models/Notifications/Notification.m @@ -390,9 +390,9 @@ - (NotificationBlock *)blockOfType:(NoteBlockType)type return nil; } -- (NSArray *)imageUrlsForBlocksOfTypes:(NSSet *)types +- (NSSet *)imageUrlsForBlocksOfTypes:(NSSet *)types { - NSMutableArray *urls = [NSMutableArray array]; + NSMutableSet *urls = [NSMutableSet set]; for (NotificationBlock *block in self.blocks) { if ([types containsObject:@(block.type)] == false) { diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m index 61cc08dfa846..1ed57eb8a98e 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m @@ -486,7 +486,7 @@ - (void)enqueueMediaDownloads:(NotificationBlockGroup *)group indexPath:(NSIndex { // Download Media: Only embeds for Text and Comment notifications NSSet *richBlockTypes = [NSSet setWithObjects:@(NoteBlockTypeText), @(NoteBlockTypeComment), nil]; - NSArray *imageUrls = [group imageUrlsForBlocksOfTypes:richBlockTypes]; + NSSet *imageUrls = [group imageUrlsForBlocksOfTypes:richBlockTypes]; __weak __typeof(self) weakSelf = self; [self.mediaDownloader downloadMediaWithUrls:imageUrls completion:^{ diff --git a/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift b/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift index 5bc515ecfc32..28386e47511d 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Tools/NotificationMediaDownloader.swift @@ -17,8 +17,13 @@ import Foundation // MARK: - Public Helpers public typealias SuccessBlock = (()->()) - public func downloadMediaWithUrls(urls: [NSURL], completion: SuccessBlock) { - let missingUrls = urls.filter { self.shouldDownloadImageWithURL($0) } + public func downloadMediaWithUrls(urls: NSSet, completion: SuccessBlock) { + let allUrls = urls.allObjects as? [NSURL] + if allUrls == nil { + return + } + + let missingUrls = allUrls!.filter { self.shouldDownloadImageWithURL($0) } if missingUrls.count == 0 { return } From b2db8fe355b66afa9368eba68d3ccc597dcab0c4 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 17:55:43 -0300 Subject: [PATCH 50/61] RichTextView: Updates autolayout settings --- .../ViewRelated/Notifications/RichTextView/RichTextView.swift | 1 - .../Notifications/Views/NoteBlockTextTableViewCell.swift | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift index 194b0413feea..81a469ef5ab7 100644 --- a/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift +++ b/WordPress/Classes/ViewRelated/Notifications/RichTextView/RichTextView.swift @@ -144,7 +144,6 @@ import Foundation addSubview(textView) // Setup Layout - setTranslatesAutoresizingMaskIntoConstraints(false) textView.setTranslatesAutoresizingMaskIntoConstraints(false) pinSubviewToAllEdges(textView) } diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift index 4ed4a07fe39e..87568742a416 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift @@ -61,6 +61,8 @@ import Foundation textView.dataDetectorTypes = .None textView.dataSource = self textView.delegate = self + + textView.setTranslatesAutoresizingMaskIntoConstraints(false) } public override func layoutSubviews() { From 4e55ba0910d50b398e2b1e24e8ca3c48b541cc91 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 18:09:32 -0300 Subject: [PATCH 51/61] Notification: Nukes titleOrUrl getter --- .../Classes/Models/Notifications/Notification.h | 1 - .../Classes/Models/Notifications/Notification.m | 9 --------- .../Controllers/NotificationDetailsViewController.m | 13 ++++++++----- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/WordPress/Classes/Models/Notifications/Notification.h b/WordPress/Classes/Models/Notifications/Notification.h index 39e66b25cc09..52f0f0cd7d27 100644 --- a/WordPress/Classes/Models/Notifications/Notification.h +++ b/WordPress/Classes/Models/Notifications/Notification.h @@ -120,7 +120,6 @@ typedef NS_ENUM(NSInteger, NoteBlockGroupType) @property (nonatomic, strong, readonly) NSNumber *metaCommentID; @property (nonatomic, strong, readonly) NSString *metaLinksHome; @property (nonatomic, strong, readonly) NSString *metaTitlesHome; -@property (nonatomic, strong, readonly) NSString *metaTitleOrUrl; // Overrides @property (nonatomic, strong, readwrite) NSString *textOverride; diff --git a/WordPress/Classes/Models/Notifications/Notification.m b/WordPress/Classes/Models/Notifications/Notification.m index 9c7d57ba4ea8..10d8052f6ef5 100644 --- a/WordPress/Classes/Models/Notifications/Notification.m +++ b/WordPress/Classes/Models/Notifications/Notification.m @@ -246,15 +246,6 @@ - (NSString *)metaTitlesHome return [[self.meta dictionaryForKey:NoteTitlesKey] stringForKey:NoteHomeKey]; } -- (NSString *)metaTitleOrUrl -{ - if ([self metaTitlesHome]) { - return [self metaTitlesHome]; - } - - return self.metaLinksHome.hostname; -} - - (NotificationRange *)notificationRangeWithUrl:(NSURL *)url { for (NotificationRange *range in self.ranges) { diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m index 1ed57eb8a98e..81402884836d 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m @@ -580,11 +580,14 @@ - (void)setupCommentCell:(NoteBlockCommentTableViewCell *)cell blockGroup:(Notif cell.attributedCommentText = [commentBlock richAttributedTextWithEmbeddedImages:mediaMap]; // Append bullet character if we have a site title or url to show - cell.timestamp = (userBlock.metaTitleOrUrl) ? - [[self.note.timestampAsDate shortString] stringByAppendingString:@" • "] - : [self.note.timestampAsDate shortString]; - cell.site = userBlock.metaTitleOrUrl; - + NSString *site = userBlock.metaTitlesHome ?: userBlock.metaLinksHome.hostname; + NSString *timestamp = [self.note.timestampAsDate shortString]; + if (site) { + timestamp = [timestamp stringByAppendingString:@" • "]; + } + + cell.timestamp = timestamp; + cell.site = site; cell.onUrlClick = ^(NSURL *url){ [weakSelf openURL:url]; From 6f833bd4140154021a2665691a0311803c4677e1 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 19:04:51 -0300 Subject: [PATCH 52/61] Decouples Image Embed Helpers --- .../NSAttributedString+Helpers.swift | 44 +++++++++++++ .../NotificationBlock+Interface.swift | 63 +++++++------------ .../NotificationDetailsViewController.m | 37 ++++++----- WordPress/WordPress.xcodeproj/project.pbxproj | 4 ++ 4 files changed, 94 insertions(+), 54 deletions(-) create mode 100644 WordPress/Classes/Extensions/NSAttributedString+Helpers.swift diff --git a/WordPress/Classes/Extensions/NSAttributedString+Helpers.swift b/WordPress/Classes/Extensions/NSAttributedString+Helpers.swift new file mode 100644 index 000000000000..8a0f982ca63d --- /dev/null +++ b/WordPress/Classes/Extensions/NSAttributedString+Helpers.swift @@ -0,0 +1,44 @@ +import Foundation + + +extension NSAttributedString +{ + /** + Note: + This method will embed a collection of assets, in the specified NSRange's. Since NSRange is an ObjC struct, + you'll need to wrap it up into a NSValue instance! + */ + public func stringByEmbeddingImageAttachments(embeds: [NSValue: UIImage]?) -> NSAttributedString { + // Allow nil embeds: behave as a simple NO-OP + if embeds == nil { + return self + } + + // Proceed embedding! + let unwrappedEmbeds = embeds! + let theString = self.mutableCopy() as NSMutableAttributedString + var rangeDelta = 0 + + for (value, image) in unwrappedEmbeds { + let imageAttachment = NSTextAttachment() + imageAttachment.bounds = CGRect(origin: CGPointZero, size: image.size) + imageAttachment.image = image + + // Each embed is expected to add 1 char to the string. Compensate for that + let attachmentString = NSAttributedString(attachment: imageAttachment) + var correctedRange = value.rangeValue + correctedRange.location += rangeDelta + + // Bounds Safety + let lastPosition = correctedRange.location + correctedRange.length + if lastPosition <= theString.length { + theString.replaceCharactersInRange(correctedRange, withAttributedString: attachmentString) + } + + rangeDelta += attachmentString.length + + } + + return theString + } +} diff --git a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift index c724d47225d3..6302939436b0 100644 --- a/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift +++ b/WordPress/Classes/Extensions/Notifications/NotificationBlock+Interface.swift @@ -4,7 +4,7 @@ import Foundation extension NotificationBlock { public func subjectAttributedText() -> NSAttributedString { - return textWithRangeStyles(isSubject: true, mediaMap: nil) + return textWithRangeStyles(isSubject: true) } public func snippetAttributedText() -> NSAttributedString { @@ -15,19 +15,37 @@ extension NotificationBlock return NSAttributedString(string: text, attributes: Styles.snippetRegularStyle) } - public func richAttributedTextWithEmbeddedImages(mediaMap: [NSURL: UIImage]?) -> NSAttributedString { + public func richAttributedText() -> NSAttributedString { // Operations such as editing a comment cause a lag between the REST and Simperium update. // TextOverride is a transient property meant to store, temporarily, the edited text if textOverride != nil { return NSAttributedString(string: textOverride, attributes: Styles.blockRegularStyle) } - return textWithRangeStyles(isSubject: false, mediaMap: mediaMap) + return textWithRangeStyles(isSubject: false) + } + + public func buildRangesToImagesMap(mediaMap: [NSURL: UIImage]?) -> [NSValue: UIImage]? { + // If we've got a text override: Ranges may not match, and the new text may not even contain ranges! + if mediaMap == nil || textOverride != nil { + return nil + } + + var ranges = [NSValue: UIImage]() + + for theMedia in media as [NotificationMedia] { + if let image = mediaMap![theMedia.mediaURL] { + let rangeValue = NSValue(range: theMedia.range) + ranges[rangeValue] = image + } + } + + return ranges } // MARK: - Private Helpers - private func textWithRangeStyles(#isSubject: Bool, mediaMap: [NSURL: UIImage]?) -> NSAttributedString { + private func textWithRangeStyles(#isSubject: Bool) -> NSAttributedString { if text == nil { return NSAttributedString() } @@ -62,42 +80,9 @@ extension NotificationBlock } } - // Embed the images, if needed - if mediaMap == nil { - return theString - } - - let unwrappedMediaMap = mediaMap! - var rangeDelta = Int(0) - - for theMedia in media as [NotificationMedia] { - - let image = unwrappedMediaMap[theMedia.mediaURL] - if theMedia.isImage == false || image == nil { - continue - } - - // Proceed attaching the media - let imageAttachment = NSTextAttachment() - imageAttachment.bounds = CGRect(origin: CGPointZero, size: image!.size) - imageAttachment.image = image! - - // Each time we insert an attachment, we're changing the string length. Compensate for that! - let attachmentString = NSAttributedString(attachment: imageAttachment) - var correctedRange = theMedia.range - correctedRange.location += rangeDelta - - let lastPosition = correctedRange.location + correctedRange.length - if lastPosition <= theString.length { - theString.replaceCharactersInRange(correctedRange, withAttributedString: attachmentString) - } - - rangeDelta += attachmentString.length - } - - return theString; + return theString } - private typealias Styles = WPStyleGuide.Notifications } + diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m index 81402884836d..0de6713f94bc 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationDetailsViewController.m @@ -560,13 +560,21 @@ - (void)setupCommentCell:(NoteBlockCommentTableViewCell *)cell blockGroup:(Notif NotificationBlock *commentBlock = [blockGroup blockOfType:NoteBlockTypeComment]; NotificationBlock *userBlock = [blockGroup blockOfType:NoteBlockTypeUser]; NotificationMedia *media = userBlock.media.firstObject; - NSDictionary *mediaMap = [self.mediaDownloader imagesForUrls:commentBlock.imageUrls]; - NSAssert(commentBlock, nil); NSAssert(userBlock, nil); - __weak __typeof(self) weakSelf = self; + // Merge the Attachments with their ranges: [NSRange: UIImage] + NSDictionary *mediaMap = [self.mediaDownloader imagesForUrls:commentBlock.imageUrls]; + NSDictionary *mediaRanges = [commentBlock buildRangesToImagesMap:mediaMap]; + + // Timestamp: Append bullet character if we have a site title or url to show + NSString *site = userBlock.metaTitlesHome ?: userBlock.metaLinksHome.hostname; + NSString *timestamp = [self.note.timestampAsDate shortString]; + if (site) { + timestamp = [timestamp stringByAppendingString:@" • "]; + } + // Setup the cell cell.isReplyEnabled = [UIDevice isPad] && [commentBlock isActionOn:NoteActionReplyKey]; cell.isLikeEnabled = [commentBlock isActionEnabled:NoteActionLikeKey]; cell.isApproveEnabled = [commentBlock isActionEnabled:NoteActionApproveKey]; @@ -577,18 +585,12 @@ - (void)setupCommentCell:(NoteBlockCommentTableViewCell *)cell blockGroup:(Notif cell.isApproveOn = [commentBlock isActionOn:NoteActionApproveKey]; cell.name = userBlock.text; - cell.attributedCommentText = [commentBlock richAttributedTextWithEmbeddedImages:mediaMap]; - - // Append bullet character if we have a site title or url to show - NSString *site = userBlock.metaTitlesHome ?: userBlock.metaLinksHome.hostname; - NSString *timestamp = [self.note.timestampAsDate shortString]; - if (site) { - timestamp = [timestamp stringByAppendingString:@" • "]; - } - + cell.attributedCommentText = [commentBlock.richAttributedText stringByEmbeddingImageAttachments:mediaRanges]; cell.timestamp = timestamp; cell.site = site; + // Setup the Callbacks + __weak __typeof(self) weakSelf = self; cell.onUrlClick = ^(NSURL *url){ [weakSelf openURL:url]; }; @@ -648,13 +650,18 @@ - (void)setupImageCell:(NoteBlockImageTableViewCell *)cell blockGroup:(Notificat - (void)setupTextCell:(NoteBlockTextTableViewCell *)cell blockGroup:(NotificationBlockGroup *)blockGroup { NotificationBlock *textBlock = blockGroup.blocks.firstObject; - NSDictionary *mediaMap = [self.mediaDownloader imagesForUrls:textBlock.imageUrls]; NSAssert(textBlock, nil); - __weak __typeof(self) weakSelf = self; + // Merge the Attachments with their ranges: [NSRange: UIImage] + NSDictionary *mediaMap = [self.mediaDownloader imagesForUrls:textBlock.imageUrls]; + NSDictionary *mediaRanges = [textBlock buildRangesToImagesMap:mediaMap]; - cell.attributedText = [textBlock richAttributedTextWithEmbeddedImages:mediaMap]; + // Setup the Cell + cell.attributedText = [textBlock.richAttributedText stringByEmbeddingImageAttachments:mediaRanges]; cell.isBadge = textBlock.isBadge; + + // Setup the Callbacks + __weak __typeof(self) weakSelf = self; cell.onUrlClick = ^(NSURL *url){ [weakSelf openURL:url]; }; diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index b326373e8a71..6814f81f0417 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -269,6 +269,7 @@ B532D4EE199D4418006E4DF6 /* NoteBlockImageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B532D4ED199D4418006E4DF6 /* NoteBlockImageTableViewCell.swift */; }; B53FDF6D19B8C336000723B6 /* UIScreen+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B53FDF6C19B8C336000723B6 /* UIScreen+Helpers.swift */; }; B548458219A258890077E7A5 /* UIActionSheet+Helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = B548458119A258890077E7A5 /* UIActionSheet+Helpers.m */; }; + B54866CA1A0D7042004AC79D /* NSAttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54866C91A0D7042004AC79D /* NSAttributedString+Helpers.swift */; }; B54E1DF01A0A7BAA00807537 /* ReplyBezierView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54E1DED1A0A7BAA00807537 /* ReplyBezierView.swift */; }; B54E1DF11A0A7BAA00807537 /* ReplyTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54E1DEE1A0A7BAA00807537 /* ReplyTextView.swift */; }; B54E1DF21A0A7BAA00807537 /* ReplyTextView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B54E1DEF1A0A7BAA00807537 /* ReplyTextView.xib */; }; @@ -961,6 +962,7 @@ B53FDF6C19B8C336000723B6 /* UIScreen+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIScreen+Helpers.swift"; sourceTree = ""; }; B548458019A258890077E7A5 /* UIActionSheet+Helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIActionSheet+Helpers.h"; sourceTree = ""; }; B548458119A258890077E7A5 /* UIActionSheet+Helpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIActionSheet+Helpers.m"; sourceTree = ""; }; + B54866C91A0D7042004AC79D /* NSAttributedString+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Helpers.swift"; sourceTree = ""; }; B54E1DED1A0A7BAA00807537 /* ReplyBezierView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyBezierView.swift; sourceTree = ""; }; B54E1DEE1A0A7BAA00807537 /* ReplyTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyTextView.swift; sourceTree = ""; }; B54E1DEF1A0A7BAA00807537 /* ReplyTextView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReplyTextView.xib; sourceTree = ""; }; @@ -2236,6 +2238,7 @@ B587797619B799D800E57C5A /* UITableViewCell+Helpers.swift */, B587797719B799D800E57C5A /* UIView+Helpers.swift */, B53FDF6C19B8C336000723B6 /* UIScreen+Helpers.swift */, + B54866C91A0D7042004AC79D /* NSAttributedString+Helpers.swift */, ); path = Extensions; sourceTree = ""; @@ -3207,6 +3210,7 @@ 834CAE7C122D528A003DDF49 /* UIImage+Resize.m in Sources */, 5D9B17C519998A430047A4A2 /* ReaderBlockedTableViewCell.m in Sources */, 834CAE9F122D56B1003DDF49 /* UIImage+Alpha.m in Sources */, + B54866CA1A0D7042004AC79D /* NSAttributedString+Helpers.swift in Sources */, 834CAEA0122D56B1003DDF49 /* UIImage+RoundedCorner.m in Sources */, E18EE95119349EC300B0A40C /* ReaderTopicServiceRemote.m in Sources */, B5FD4544199D0F2800286FBB /* NotificationsViewController.m in Sources */, From 65f395c5a9612e40ed430ab09f25057a9472666f Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Fri, 7 Nov 2014 19:47:47 -0300 Subject: [PATCH 53/61] Notifications: Caps Media Embeds size. If needed --- .../Views/NoteBlockTextTableViewCell.swift | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift index 87568742a416..0138569a8f03 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockTextTableViewCell.swift @@ -7,6 +7,7 @@ import Foundation public var onUrlClick: ((NSURL) -> Void)? public var attributedText: NSAttributedString? { didSet { + adjustAttachmentsSizeIfNeeded() textView.attributedText = attributedText setNeedsLayout() } @@ -71,13 +72,29 @@ import Foundation super.layoutSubviews() } + // MARK: - Private Helpers + private func adjustAttachmentsSizeIfNeeded() { + + // MaxWidth defined by the RichTextView onscreen! + let maxWidth = bounds.width - labelPadding.left - labelPadding.right + + attributedText?.enumerateAttachments { + (attachment: NSTextAttachment, range: NSRange) -> () in + + var attachmentSize = attachment.bounds.size + if attachmentSize.width > maxWidth { + attachmentSize.height = round(maxWidth * attachmentSize.height / attachmentSize.width) + attachmentSize.width = maxWidth + attachment.bounds.size = attachmentSize + } + } + } // MARK: - RichTextView Data Source public func textView(textView: UITextView, didPressLink link: NSURL) { onUrlClick?(link) } - // MARK: - Constants private let maxWidth = WPTableViewFixedWidth private let privateLabelPadding = UIEdgeInsets(top: 0, left: 12, bottom: 0, right: 12) From 11ef5aaceb1b960ecb93009b828af8a8e28bf140 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 10 Nov 2014 12:06:05 -0300 Subject: [PATCH 54/61] Notifications: Fixes Site flickering --- .../Comments/CommentTableViewCell.xib | 29 +++++++--------- .../Notifications/Notifications.storyboard | 33 +++++++++---------- .../Views/NoteBlockCommentTableViewCell.swift | 12 ++++--- 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib b/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib index 1b521406defd..4aa9a6639e64 100644 --- a/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib +++ b/WordPress/Classes/ViewRelated/Comments/CommentTableViewCell.xib @@ -3,7 +3,6 @@ - @@ -41,7 +40,7 @@ - + + + @@ -162,18 +156,19 @@ + - - + + @@ -181,11 +176,11 @@ - + @@ -208,11 +203,11 @@ - + diff --git a/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard b/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard index 5d88acd1029b..d56c40bdea17 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard +++ b/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard @@ -3,7 +3,6 @@ - @@ -180,24 +179,21 @@ - + + - + @@ -289,19 +285,20 @@ - - + + - + + @@ -313,7 +310,6 @@ - @@ -321,6 +317,7 @@ + @@ -332,11 +329,11 @@ - + diff --git a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockCommentTableViewCell.swift b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockCommentTableViewCell.swift index 76aba8d77fc1..3594379b70fa 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockCommentTableViewCell.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Views/NoteBlockCommentTableViewCell.swift @@ -32,7 +32,7 @@ import Foundation } public var site: String? { didSet { - btnSite.setTitle(site ?? String(), forState: .Normal) + siteLabel.text = site ?? String() } } public var isReplyEnabled: Bool = false { @@ -99,8 +99,12 @@ import Foundation // Setup Labels nameLabel.font = WPStyleGuide.Notifications.blockBoldFont timestampLabel.font = WPStyleGuide.Notifications.blockRegularFont - btnSite.titleLabel!.font = WPStyleGuide.Notifications.blockRegularFont + siteLabel.font = WPStyleGuide.Notifications.blockRegularFont + // Setup Recognizers + siteLabel.gestureRecognizers = [ UITapGestureRecognizer(target: self, action: "siteWasPressed:") ] + siteLabel.userInteractionEnabled = true + // Background approvalStatusView.backgroundColor = WPStyleGuide.Notifications.blockUnapprovedBgColor approvalSidebarView.backgroundColor = WPStyleGuide.Notifications.blockUnapprovedSideColor @@ -229,7 +233,7 @@ import Foundation separatorView.backgroundColor = WPStyleGuide.Notifications.blockSeparatorColorForComment(isApproved: isCommentApproved) nameLabel.textColor = WPStyleGuide.Notifications.blockTextColorForComment(isApproved: isCommentApproved) timestampLabel.textColor = WPStyleGuide.Notifications.blockTimestampColorForComment(isApproved: isCommentApproved) - btnSite.setTitleColor(WPStyleGuide.Notifications.blockTimestampColorForComment(isApproved: isCommentApproved), forState: .Normal) + siteLabel.textColor = WPStyleGuide.Notifications.blockTimestampColorForComment(isApproved: isCommentApproved) super.linkColor = WPStyleGuide.Notifications.blockLinkColorForComment(isApproved: isCommentApproved) super.attributedText = isCommentApproved ? attributedCommentText : attributedCommentUnapprovedText } @@ -267,8 +271,8 @@ import Foundation @IBOutlet private weak var gravatarImageView : UIImageView! @IBOutlet private weak var nameLabel : UILabel! @IBOutlet private weak var timestampLabel : UILabel! + @IBOutlet private weak var siteLabel : UILabel! @IBOutlet private weak var separatorView : UIView! - @IBOutlet private weak var btnSite : UIButton! @IBOutlet private weak var btnReply : UIButton! @IBOutlet private weak var btnLike : UIButton! @IBOutlet private weak var btnApprove : UIButton! From 3de21709b6e9a32fedf9a4f6ac781dd073551b49 Mon Sep 17 00:00:00 2001 From: Jorge Leandro Perez Date: Mon, 10 Nov 2014 12:42:39 -0300 Subject: [PATCH 55/61] Fixes autolayout warning --- .../Notifications/Notifications.storyboard | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard b/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard index d56c40bdea17..e52c89e615e0 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard +++ b/WordPress/Classes/ViewRelated/Notifications/Notifications.storyboard @@ -137,7 +137,7 @@ - + @@ -145,10 +145,10 @@ - + - + @@ -193,21 +193,21 @@ - + - +