diff --git a/Sources/WordPressData/Objective-C/include/ReaderPost.h b/Sources/WordPressData/Objective-C/include/ReaderPost.h index e380de41cda2..a2baf78ed5c3 100644 --- a/Sources/WordPressData/Objective-C/include/ReaderPost.h +++ b/Sources/WordPressData/Objective-C/include/ReaderPost.h @@ -2,6 +2,8 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + typedef NS_ENUM(NSUInteger, SourceAttributionStyle) { SourceAttributionStyleNone, SourceAttributionStylePost, @@ -20,19 +22,19 @@ extern NSString * const ReaderPostStoredCommentTextKey; @interface ReaderPost : BasePost -@property (nonatomic, strong) NSString *authorDisplayName; -@property (nonatomic, strong) NSString *authorEmail; -@property (nonatomic, strong) NSString *authorURL; -@property (nonatomic, strong) NSString *siteIconURL; -@property (nonatomic, strong) NSString *blogName; -@property (nonatomic, strong) NSString *blogDescription; -@property (nonatomic, strong) NSString *blogURL; -@property (nonatomic, strong) NSNumber *commentCount; +@property (nonatomic, strong, nullable) NSString *authorDisplayName; +@property (nonatomic, strong, nullable) NSString *authorEmail; +@property (nonatomic, strong, nullable) NSString *authorURL; +@property (nonatomic, strong, nullable) NSString *siteIconURL; +@property (nonatomic, strong, nullable) NSString *blogName; +@property (nonatomic, strong, nullable) NSString *blogDescription; +@property (nonatomic, strong, nullable) NSString *blogURL; +@property (nonatomic, strong, nullable) NSNumber *commentCount; @property (nonatomic) BOOL commentsOpen; -@property (nonatomic, strong) NSString *featuredImage; -@property (nonatomic, strong) NSNumber *feedID; -@property (nonatomic, strong) NSNumber *feedItemID; -@property (nonatomic, strong) NSString *globalID; +@property (nonatomic, strong, nullable) NSString *featuredImage; +@property (nonatomic, strong, nullable) NSNumber *feedID; +@property (nonatomic, strong, nullable) NSNumber *feedItemID; +@property (nonatomic, strong, nullable) NSString *globalID; @property (nonatomic) BOOL isBlogAtomic; @property (nonatomic) BOOL isBlogPrivate; @property (nonatomic) BOOL isFollowing; @@ -42,36 +44,36 @@ extern NSString * const ReaderPostStoredCommentTextKey; @property (nonatomic) BOOL isSavedForLater; @property (nonatomic) BOOL isSeen; @property (nonatomic) BOOL isSeenSupported; -@property (nonatomic, strong) NSNumber *organizationID; -@property (nonatomic, strong) NSNumber *likeCount; -@property (nonatomic, strong) NSNumber *score; -@property (nonatomic, strong) NSNumber *siteID; +@property (nonatomic) NSNumber *organizationID; +@property (nonatomic, strong, nullable) NSNumber *likeCount; +@property (nonatomic, strong, nullable) NSNumber *score; +@property (nonatomic, strong, nullable) NSNumber *siteID; // Normalizes sorting between offset or sortDate depending on the flavor of post. // Note that this can store a negative value. -@property (nonatomic, strong) NSNumber *sortRank; +@property (nonatomic) NSNumber *sortRank; // Normalizes the date to sort by depending on the flavor of post. -@property (nonatomic, strong) NSDate *sortDate; -@property (nonatomic, strong) NSString *summary; -@property (nonatomic, strong) NSSet *comments; -@property (nonatomic, strong) NSString *tags; -@property (nonatomic, strong) ReaderAbstractTopic *topic; -@property (nonatomic, strong) NSSet *card; +@property (nonatomic, strong, nullable) NSDate *sortDate; +@property (nonatomic, strong, nullable) NSString *summary; +@property (nonatomic, strong, nullable) NSSet *comments; +@property (nonatomic, strong, nullable) NSString *tags; +@property (nonatomic, strong, nullable) ReaderAbstractTopic *topic; +@property (nonatomic, strong, nullable) NSSet *card; @property (nonatomic) BOOL isLikesEnabled; @property (nonatomic) BOOL isSharingEnabled; @property (nonatomic) BOOL isSiteBlocked; -@property (nonatomic, strong) SourcePostAttribution *sourceAttribution; +@property (nonatomic, strong, nullable) SourcePostAttribution *sourceAttribution; @property (nonatomic) BOOL isSubscribedComments; @property (nonatomic) BOOL canSubscribeComments; @property (nonatomic) BOOL receivesCommentNotifications; -@property (nonatomic, strong) NSString *primaryTag; -@property (nonatomic, strong) NSString *primaryTagSlug; +@property (nonatomic, strong, nullable) NSString *primaryTag; +@property (nonatomic, strong, nullable) NSString *primaryTagSlug; @property (nonatomic) BOOL isExternal; @property (nonatomic) BOOL isJetpack; -@property (nonatomic) NSNumber *wordCount; -@property (nonatomic) NSNumber *readingTime; -@property (nonatomic, strong) ReaderCrossPostMeta *crossPostMeta; -@property (nonatomic, strong) NSString *railcar; +@property (nonatomic, strong, nullable) NSNumber *wordCount; +@property (nonatomic, strong, nullable) NSNumber *readingTime; +@property (nonatomic, strong, nullable) ReaderCrossPostMeta *crossPostMeta; +@property (nonatomic, strong, nullable) NSString *railcar; // Used for tracking when a post is rendered (displayed), and bumping the train tracks rendered event. @property (nonatomic) BOOL rendered; @@ -79,10 +81,10 @@ extern NSString * const ReaderPostStoredCommentTextKey; // When true indicates a post should not be deleted/cleaned-up as its currently being used. @property (nonatomic) BOOL inUse; -+ (instancetype)createOrReplaceFromRemotePost:(RemoteReaderPost *)remotePost forTopic:(ReaderAbstractTopic *)topic context:(NSManagedObjectContext *) managedObjectContext; ++ (instancetype)createOrReplaceFromRemotePost:(RemoteReaderPost *)remotePost forTopic:(nullable ReaderAbstractTopic *)topic context:(NSManagedObjectContext *) managedObjectContext; - (BOOL)contentIncludesFeaturedImage; -- (NSDictionary *)railcarDictionary; +- (nullable NSDictionary *)railcarDictionary; @end @@ -95,3 +97,4 @@ extern NSString * const ReaderPostStoredCommentTextKey; @end +NS_ASSUME_NONNULL_END diff --git a/Sources/WordPressData/Swift/ReaderCard+CoreDataClass.swift b/Sources/WordPressData/Swift/ReaderCard+CoreDataClass.swift index 8daaeeceacf1..22b6a31bd295 100644 --- a/Sources/WordPressData/Swift/ReaderCard+CoreDataClass.swift +++ b/Sources/WordPressData/Swift/ReaderCard+CoreDataClass.swift @@ -50,7 +50,12 @@ public class ReaderCard: NSManagedObject { switch remoteCard.type { case .post: - let post = ReaderPost.createOrReplace(fromRemotePost: remoteCard.post, for: nil, context: context) + let post: ReaderPost + if let remotePost = remoteCard.post { + post = ReaderPost.createOrReplace(fromRemotePost: remotePost, for: nil, context: context) + } else { + return nil + } // Check if a card already exists with this post to prevent duplicates if let existingCard = findExistingCard(with: post, context: context) { diff --git a/Sources/WordPressData/Swift/ReaderPost+PostContentProvider.swift b/Sources/WordPressData/Swift/ReaderPost+PostContentProvider.swift index 154a847ca153..d6c4eccff937 100644 --- a/Sources/WordPressData/Swift/ReaderPost+PostContentProvider.swift +++ b/Sources/WordPressData/Swift/ReaderPost+PostContentProvider.swift @@ -7,7 +7,8 @@ extension ReaderPost { } public var isP2Type: Bool { - guard let id = organizationID?.intValue, let type = SiteOrganizationType(rawValue: id) else { return false } + let id = organizationID.intValue + guard let type = SiteOrganizationType(rawValue: id) else { return false } return type == .p2 || type == .automattic } diff --git a/Tests/KeystoneTests/Tests/Services/CommentService+RepliesTests.swift b/Tests/KeystoneTests/Tests/Services/CommentService+RepliesTests.swift index 0cccc002ed56..f731e1cb24c4 100644 --- a/Tests/KeystoneTests/Tests/Services/CommentService+RepliesTests.swift +++ b/Tests/KeystoneTests/Tests/Services/CommentService+RepliesTests.swift @@ -269,11 +269,11 @@ final class CommentService_RepliesTests: CoreDataTestCase { } // All comments are visible - XCTAssertEqual(post.comments.count, 24) - XCTAssertEqual(post.comments.filter({ ($0 as! Comment).visibleOnReader }).count, 24) + XCTAssertEqual(post.comments?.count, 24) + XCTAssertEqual(post.comments?.filter({ ($0 as! Comment).visibleOnReader }).count, 24) // Mark a comment as spam - let spamComment = try XCTUnwrap(post.comments.first { ($0 as! Comment).commentID == 428668 }) as! Comment + let spamComment = try XCTUnwrap(post.comments?.first { ($0 as! Comment).commentID == 428668 }) as! Comment spamComment.status = CommentStatusType.spam.description contextManager.saveContextAndWait(mainContext) @@ -282,8 +282,8 @@ final class CommentService_RepliesTests: CoreDataTestCase { } // The spam comment and its two replies are no longer visible - XCTAssertEqual(post.comments.count, 24) - XCTAssertEqual(post.comments.filter({ ($0 as! Comment).visibleOnReader }).count, 21) + XCTAssertEqual(post.comments?.count, 24) + XCTAssertEqual(post.comments?.filter({ ($0 as! Comment).visibleOnReader }).count, 21) } } diff --git a/WordPress/Classes/Services/NotificationSyncMediator.swift b/WordPress/Classes/Services/NotificationSyncMediator.swift index c6e0892e3c32..779740d9f56f 100644 --- a/WordPress/Classes/Services/NotificationSyncMediator.swift +++ b/WordPress/Classes/Services/NotificationSyncMediator.swift @@ -539,7 +539,7 @@ private extension NotificationSyncMediator { fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [commentIDPredicate, siteIDPredicate]) if let post = try context.fetch(fetchRequest).first { post.isLiked = isLike - post.likeCount = NSNumber(value: post.likeCount.intValue + (post.isLiked ? 1 : -1)) + post.likeCount = NSNumber(value: max((post.likeCount?.intValue ?? 0) + (post.isLiked ? 1 : -1), 0)) } } catch { diff --git a/WordPress/Classes/Services/ReaderPostStreamService.swift b/WordPress/Classes/Services/ReaderPostStreamService.swift index 3f11b9120397..6b6ce07aa62e 100644 --- a/WordPress/Classes/Services/ReaderPostStreamService.swift +++ b/WordPress/Classes/Services/ReaderPostStreamService.swift @@ -39,7 +39,7 @@ class ReaderPostStreamService { posts.enumerated().forEach { index, remotePost in let post = ReaderPost.createOrReplace(fromRemotePost: remotePost, for: readerTopic, context: context) // To keep the API order - post?.sortRank = NSNumber(value: Date().timeIntervalSinceReferenceDate - Double(((self.pageNumber * Constants.paginationMultiplier) + index))) + post.sortRank = NSNumber(value: Date().timeIntervalSinceReferenceDate - Double(((self.pageNumber * Constants.paginationMultiplier) + index))) } // Clean up diff --git a/WordPress/Classes/ViewRelated/Comments/Controllers/Create/CommentCreateViewModel.swift b/WordPress/Classes/ViewRelated/Comments/Controllers/Create/CommentCreateViewModel.swift index f45ac5f07ad5..822618c16cc1 100644 --- a/WordPress/Classes/ViewRelated/Comments/Controllers/Create/CommentCreateViewModel.swift +++ b/WordPress/Classes/ViewRelated/Comments/Controllers/Create/CommentCreateViewModel.swift @@ -34,7 +34,7 @@ final class CommentCreateViewModel { wpAssert(siteID != 0, "missing required parameter siteID") self._save = save - self.suggestionsViewModel = SuggestionsListViewModel.make(siteID: post.siteID) + self.suggestionsViewModel = SuggestionsListViewModel.make(siteID: self.siteID) self.suggestionsViewModel?.enableProminentSuggestions(postAuthorID: post.authorID) } diff --git a/WordPress/Classes/ViewRelated/Likes/LikesListController.swift b/WordPress/Classes/ViewRelated/Likes/LikesListController.swift index e9546e606ec7..4a9d1798755f 100644 --- a/WordPress/Classes/ViewRelated/Likes/LikesListController.swift +++ b/WordPress/Classes/ViewRelated/Likes/LikesListController.swift @@ -129,13 +129,13 @@ class LikesListController: NSObject { /// init?(tableView: UITableView, post: ReaderPost, delegate: LikesListControllerDelegate? = nil) { - guard let postID = post.postID else { + guard let postID = post.postID, let siteID = post.siteID else { return nil } content = .post(id: postID) readerPost = post - siteID = post.siteID + self.siteID = siteID self.tableView = tableView self.delegate = delegate diff --git a/WordPress/Classes/ViewRelated/Reader/Cards/ReaderCrossPostCell.swift b/WordPress/Classes/ViewRelated/Reader/Cards/ReaderCrossPostCell.swift index 922dc01b1245..27aec1633203 100644 --- a/WordPress/Classes/ViewRelated/Reader/Cards/ReaderCrossPostCell.swift +++ b/WordPress/Classes/ViewRelated/Reader/Cards/ReaderCrossPostCell.swift @@ -138,13 +138,13 @@ private final class ReaderCrossPostView: UIView { } private func makeHeaderString(for post: ReaderPost) -> NSAttributedString? { - guard let meta = post.crossPostMeta else { + guard let meta = post.crossPostMeta, let blogURL = post.blogURL else { return nil } let template = meta.commentURL.isEmpty ? Strings.siteTemplate : Strings.commentTemplate let authorName: NSString = (post.authorForDisplay() ?? "") as NSString - let siteName = subdomainNameFromPath(post.blogURL) + let siteName = subdomainNameFromPath(blogURL) let originName = subdomainNameFromPath(meta.siteURL) let subtitle = NSString(format: template as NSString, authorName, originName, siteName) as String diff --git a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.swift b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.swift index e89cb53de6cc..6fc2c2e9f16b 100644 --- a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.swift @@ -329,8 +329,8 @@ final class ReaderCommentsViewController: UIViewController, WPContentSyncHelperD return wpAssertionFailure("post missing") } var linkURL = url - if let components = URLComponents(string: url.absoluteString), components.host == nil { - linkURL = components.url(relativeTo: URL(string: post.blogURL)) ?? linkURL + if let components = URLComponents(string: url.absoluteString), components.host == nil, let blogURL = post.blogURL { + linkURL = components.url(relativeTo: URL(string: blogURL)) ?? linkURL } let configuration = WebViewControllerConfiguration(url: linkURL) configuration.authenticateWithDefaultAccount() diff --git a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderCellConfiguration.swift b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderCellConfiguration.swift index 9e45dc99b734..530464920369 100644 --- a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderCellConfiguration.swift +++ b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderCellConfiguration.swift @@ -14,7 +14,7 @@ final class ReaderCellConfiguration { return } let post = posts[indexPath.row] - cell.setSiteName(post.blogName) + cell.setSiteName(post.blogName ?? "-") } func configureGapMarker(_ cell: ReaderGapMarkerCell, filling: Bool) { diff --git a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderHelpers.swift b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderHelpers.swift index 8802271ecfa7..ac25d23b8cc0 100644 --- a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderHelpers.swift +++ b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderHelpers.swift @@ -219,7 +219,8 @@ struct ReaderNotificationKeys { guard let siteID = post.siteID, let postID = post.postID, - let host = NSURL(string: post.blogURL)?.host else { + let blogURL = post.blogURL, + let host = URL(string: blogURL)?.host() else { return } diff --git a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderBlockSiteAction.swift b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderBlockSiteAction.swift index 6a41a30d7529..fb0fe32e2abb 100644 --- a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderBlockSiteAction.swift +++ b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderBlockSiteAction.swift @@ -11,8 +11,15 @@ final class ReaderBlockSiteAction { } func execute(with post: ReaderPost, context: NSManagedObjectContext, completion: (() -> Void)? = nil, failure: ((Error?) -> Void)? = nil) { + guard let siteID = post.siteID else { + DispatchQueue.main.async { + failure?(nil) + } + return + } + let service = ReaderSiteService(coreDataStack: ContextManager.shared) - service.flagSite(withID: post.siteID, + service.flagSite(withID: siteID, asBlocked: asBlocked, success: { WPAnalytics.trackReader(.readerBlogBlocked, properties: ["blogId": post.siteID as Any]) diff --git a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderHeaderAction.swift b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderHeaderAction.swift index 516da43e8fd7..6b882cf96055 100644 --- a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderHeaderAction.swift +++ b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderHeaderAction.swift @@ -3,7 +3,9 @@ import WordPressData final class ReaderHeaderAction { func execute(post: ReaderPost, origin: UIViewController, source: ReaderStreamViewController.StatSource? = nil) { - let controller = ReaderStreamViewController.controllerWithSiteID(post.siteID, isFeed: post.isExternal) + guard let siteID = post.siteID else { return } + + let controller = ReaderStreamViewController.controllerWithSiteID(siteID, isFeed: post.isExternal) if let source { controller.statSource = source } diff --git a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostBlockingController.swift b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostBlockingController.swift index d938f6e1924d..876c88877adf 100644 --- a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostBlockingController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostBlockingController.swift @@ -115,27 +115,27 @@ final class ReaderPostBlockingController { } @objc private func handleSiteBlockingWillBeginNotification(_ notification: Foundation.Notification) { - guard let post = notification.userInfo?[ReaderNotificationKeys.post] as? ReaderPost else { + guard let post = notification.userInfo?[ReaderNotificationKeys.post] as? ReaderPost, let siteID = post.siteID else { return } - self.ongoingSitesBlocking.insert(post.siteID) + self.ongoingSitesBlocking.insert(siteID) self.delegate?.readerSiteBlockingController(self, willBeginBlockingSiteOfPost: post) } @objc private func handleBlockSiteNotification(_ notification: Foundation.Notification) { - guard let post = notification.userInfo?[ReaderNotificationKeys.post] as? ReaderPost else { + guard let post = notification.userInfo?[ReaderNotificationKeys.post] as? ReaderPost, let siteID = post.siteID else { return } - self.ongoingSitesBlocking.remove(post.siteID) + self.ongoingSitesBlocking.remove(siteID) self.delegate?.readerSiteBlockingController(self, didBlockSiteOfPost: post, result: .success(())) } @objc private func handleSiteBlockingFailed(_ notification: Foundation.Notification) { - guard let post = notification.userInfo?[ReaderNotificationKeys.post] as? ReaderPost else { + guard let post = notification.userInfo?[ReaderNotificationKeys.post] as? ReaderPost, let siteID = post.siteID else { return } let error = (notification.userInfo?[ReaderNotificationKeys.error] as? Error) ?? UnknownError() - self.ongoingSitesBlocking.remove(post.siteID) + self.ongoingSitesBlocking.remove(siteID) self.delegate?.readerSiteBlockingController(self, didBlockSiteOfPost: post, result: .failure(error)) } diff --git a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift index bc577ae70955..ee9dcf32dfee 100644 --- a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift +++ b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift @@ -162,11 +162,11 @@ class ReaderDetailCoordinator { } func fetchLikes(for post: ReaderPost) { - guard let postID = post.postID else { return } + guard let postID = post.postID, let siteID = post.siteID else { return } // Fetch a full page of Likes but only return the `maxAvatarsDisplayed` number. // That way the first page will already be cached if the user displays the full Likes list. - postService.getLikesFor(postID: postID, siteID: post.siteID, success: { [weak self] users, totalLikes, _ in + postService.getLikesFor(postID: postID, siteID: siteID, success: { [weak self] users, totalLikes, _ in guard let self else { return } var filteredUsers = users @@ -201,7 +201,7 @@ class ReaderDetailCoordinator { guard let post, let likesAvatarURLs else { return } let viewModel = ReaderDetailLikesViewModel( - likeCount: post.likeCount.intValue, + likeCount: post.likeCount?.intValue ?? 0, avatarURLs: likesAvatarURLs, selfLikeAvatarURL: post.isLiked ? try? WPAccount.lookupDefaultWordPressComAccount(in: ContextManager.shared.mainContext)?.avatarURL : nil ) @@ -261,21 +261,21 @@ class ReaderDetailCoordinator { /// Show more about a specific site in Discovery /// func showMore() { - guard let post, post.sourceAttribution != nil else { + guard let post, let sourceAttribution = post.sourceAttribution else { return } - if let blogID = post.sourceAttribution.blogID { + if let blogID = sourceAttribution.blogID { let controller = ReaderStreamViewController.controllerWithSiteID(blogID, isFeed: false) viewController?.navigationController?.pushViewController(controller, animated: true) return } - var path: String? - if post.sourceAttribution.attributionType == SourcePostAttribution.post { - path = post.sourceAttribution.permalink + let path: String? + if sourceAttribution.attributionType == SourcePostAttribution.post { + path = sourceAttribution.permalink } else { - path = post.sourceAttribution.blogURL + path = sourceAttribution.blogURL } if let path, let linkURL = URL(string: path) { @@ -423,11 +423,11 @@ class ReaderDetailCoordinator { /// Shows the current post site posts in a new screen /// private func previewSite() { - guard let post else { + guard let post, let siteID = post.siteID else { return } - let controller = ReaderStreamViewController.controllerWithSiteID(post.siteID, isFeed: post.isExternal) + let controller = ReaderStreamViewController.controllerWithSiteID(siteID, isFeed: post.isExternal) viewController?.navigationController?.pushViewController(controller, animated: true) let properties = ReaderHelpers.statsPropertiesForPost(post, andValue: post.blogURL as AnyObject?, forKey: "URL") @@ -443,10 +443,15 @@ class ReaderDetailCoordinator { /// private func showTag() { guard let post else { + wpAssertionFailure("post is nil") + return + } + guard let primaryTagSlug = post.primaryTagSlug else { + wpAssertionFailure("post.primaryTagSlug is nil") return } - let controller = ReaderStreamViewController.controllerWithTagSlug(post.primaryTagSlug) + let controller = ReaderStreamViewController.controllerWithTagSlug(primaryTagSlug) viewController?.navigationController?.pushViewController(controller, animated: true) let properties = ReaderHelpers.statsPropertiesForPost(post, andValue: post.primaryTagSlug as AnyObject?, forKey: "tag") @@ -580,7 +585,7 @@ class ReaderDetailCoordinator { guard let post else { return } - let controller = ReaderDetailLikesListController(post: post, totalLikes: post.likeCount.intValue) + let controller = ReaderDetailLikesListController(post: post, totalLikes: post.likeCount?.intValue ?? 0) viewController?.navigationController?.pushViewController(controller, animated: true) } diff --git a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift index 2b1808314bdc..81ab8094a6d1 100644 --- a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift @@ -582,7 +582,7 @@ class ReaderDetailViewController: UIViewController, ReaderDetailView { guard isNewFeaturedImageEnabled else { return } - guard let post, let imageURL = URL(string: post.featuredImage), + guard let post, let imageURL = post.featuredImageURL, !post.contentIncludesFeaturedImage() else { return } @@ -872,12 +872,13 @@ class ReaderDetailViewController: UIViewController, ReaderDetailView { /// - Parameter post: a Reader Post /// - Returns: A `ReaderDetailViewController` instance @objc class func controllerWithPost(_ post: ReaderPost) -> ReaderDetailViewController { - if post.sourceAttributionStyle() == .post && - post.sourceAttribution.postID != nil && - post.sourceAttribution.blogID != nil { - return ReaderDetailViewController.controllerWithPostID(post.sourceAttribution.postID!, siteID: post.sourceAttribution.blogID!) - } else if post.isCrossPost { - return ReaderDetailViewController.controllerWithPostID(post.crossPostMeta.postID, siteID: post.crossPostMeta.siteID) + if post.sourceAttributionStyle() == .post, + let sourceAttribution = post.sourceAttribution, + let postID = sourceAttribution.postID, + let blogID = sourceAttribution.blogID { + return ReaderDetailViewController.controllerWithPostID(postID, siteID: blogID) + } else if post.isCrossPost, let crossPostMeta = post.crossPostMeta { + return ReaderDetailViewController.controllerWithPostID(crossPostMeta.postID, siteID: crossPostMeta.siteID) } else { let controller = ReaderDetailViewController.loadFromStoryboard() let coordinator = ReaderDetailCoordinator(view: controller) diff --git a/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailFeaturedImageView.swift b/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailFeaturedImageView.swift index 5fb746a219e5..5aee73c5c6e8 100644 --- a/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailFeaturedImageView.swift +++ b/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailFeaturedImageView.swift @@ -196,7 +196,7 @@ final class ReaderDetailFeaturedImageView: UIView { guard !isLoading, let post = self.post, - let imageURL = URL(string: post.featuredImage), + let imageURL = post.featuredImageURL, Self.shouldDisplayFeaturedImage(with: post) else { reset() @@ -255,7 +255,7 @@ final class ReaderDetailFeaturedImageView: UIView { } static func shouldDisplayFeaturedImage(with post: ReaderPost) -> Bool { - let imageURL = URL(string: post.featuredImage) + let imageURL = post.featuredImageURL return imageURL != nil && !post.contentIncludesFeaturedImage() } diff --git a/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailToolbar.swift b/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailToolbar.swift index 2ae7bd40f37a..6e369c877219 100644 --- a/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailToolbar.swift +++ b/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailToolbar.swift @@ -130,7 +130,7 @@ class ReaderDetailToolbar { private func makeCommentButton() -> UIBarButtonItem? { guard shouldShowCommentActionButton else { return nil } - let count = post?.commentCount.intValue ?? 0 + let count = post?.commentCount?.intValue ?? 0 let customButton = makeCustomButton( image: WPStyleGuide.ReaderDetail.commentToolbarIcon,