diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 0d92999a6d5a..74811df9978a 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -22,6 +22,8 @@ * [*] Add a quick way to replace a featured image for a post [#23962] * [*] Fix an issue with posts in Reader sometimes showing incorrect covers [#23914] * [*] Fix non-stable order in Posts and Pages section in Stats [#23915] +* [*] (P2) Reader: Fix an issue with a missing "Mark as Read/Unread" button that was removed in the previous release [#23917] +* [*] (P2) Reader: Show "read" status for P2 posts in the feeds [#23917] 25.6 ----- diff --git a/WordPress/Classes/ViewRelated/Reader/Cards/ReaderPostCell.swift b/WordPress/Classes/ViewRelated/Reader/Cards/ReaderPostCell.swift index 811b48aab76a..3bca261a58ea 100644 --- a/WordPress/Classes/ViewRelated/Reader/Cards/ReaderPostCell.swift +++ b/WordPress/Classes/ViewRelated/Reader/Cards/ReaderPostCell.swift @@ -71,6 +71,7 @@ private final class ReaderPostCellView: UIView { let avatarView = ReaderAvatarView() let buttonAuthor = makeAuthorButton() let timeLabel = UILabel() + let seenCheckmark = UIImageView() let buttonMore = makeButton(systemImage: "ellipsis", font: .systemFont(ofSize: 13)) // Content @@ -100,6 +101,7 @@ private final class ReaderPostCellView: UIView { private var toolbarViewHeightConstraint: NSLayoutConstraint? private var imageViewConstraints: [NSLayoutConstraint] = [] + private var isSeenCheckmarkConfigured = false private var cancellables: [AnyCancellable] = [] override init(frame: CGRect) { @@ -155,7 +157,8 @@ private final class ReaderPostCellView: UIView { // These seems to be an issue with `lineBreakMode` in `UIButton.Configuration` // and `.firstLineBaseline`, so reserving to `.center`. - let headerView = UIStackView(alignment: .center, [buttonAuthor, dot, timeLabel]) + let headerView = UIStackView(alignment: .center, [buttonAuthor, dot, timeLabel, seenCheckmark]) + headerView.setCustomSpacing(4, after: timeLabel) for view in [avatarView, headerView, postPreview, buttonMore, toolbarView] { addSubview(view) @@ -308,6 +311,13 @@ private final class ReaderPostCellView: UIView { imageView.setImage(with: imageURL, size: preferredCoverSize) } + if viewModel.isSeen == true { + configureSeenCheckmarkIfNeeded() + seenCheckmark.isHidden = false + } else { + seenCheckmark.isHidden = true + } + if !viewModel.isToolbarHidden { configureToolbar(with: viewModel.toolbar) configureToolbarAccessibility(with: viewModel.toolbar) @@ -360,6 +370,17 @@ private final class ReaderPostCellView: UIView { } } + private func configureSeenCheckmarkIfNeeded() { + guard !isSeenCheckmarkConfigured else { return } + isSeenCheckmarkConfigured = true + + seenCheckmark.image = UIImage( + systemName: "checkmark", + withConfiguration: UIImage.SymbolConfiguration(font: .preferredFont(forTextStyle: .caption1).withWeight(.medium)) + ) + seenCheckmark.tintColor = .secondaryLabel + } + private static let authorAttributes = AttributeContainer([ .font: WPStyleGuide.fontForTextStyle(.footnote, fontWeight: .medium), .foregroundColor: UIColor.label diff --git a/WordPress/Classes/ViewRelated/Reader/Cards/ReaderPostCellViewModel.swift b/WordPress/Classes/ViewRelated/Reader/Cards/ReaderPostCellViewModel.swift index 91b6f8d48c85..8f6c24e1e6d6 100644 --- a/WordPress/Classes/ViewRelated/Reader/Cards/ReaderPostCellViewModel.swift +++ b/WordPress/Classes/ViewRelated/Reader/Cards/ReaderPostCellViewModel.swift @@ -10,6 +10,7 @@ final class ReaderPostCellViewModel { // Content let title: String let details: String + let isSeen: Bool? let imageURL: URL? // Footer (Buttons) @@ -34,9 +35,10 @@ final class ReaderPostCellViewModel { } else { self.author = post.blogNameForDisplay() ?? "" } - self.time = post.dateForDisplay()?.toShortString() ?? "–" + self.time = post.dateForDisplay()?.toShortString() ?? "" self.title = post.titleForDisplay() ?? "" self.details = post.contentPreviewForDisplay() ?? "" + self.isSeen = post.isSeenSupported ? post.isSeen : nil self.imageURL = post.featuredImageURLForDisplay() self.toolbar = ReaderPostToolbarViewModel.make(post: post) @@ -64,6 +66,7 @@ final class ReaderPostCellViewModel { self.avatarURL = URL(string: "https://picsum.photos/120/120.jpg") self.author = "WordPress Mobile Apps" self.time = "9d ago" + self.isSeen = nil self.title = "Discovering the Wonders of the Wild" self.details = "Lorem ipsum dolor sit amet. Non omnis quia et natus voluptatum et eligendi voluptate vel iusto fuga sit repellendus molestiae aut voluptatem blanditiis ad neque sapiente. Id galisum distinctio quo enim aperiam non veritatis vitae et ducimus rerum." self.imageURL = URL(string: "https://picsum.photos/1260/630.jpg") diff --git a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderPostMenu.swift b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderPostMenu.swift index 2d05fc714563..42fa44f212a2 100644 --- a/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderPostMenu.swift +++ b/WordPress/Classes/ViewRelated/Reader/Controllers/ReaderPostActions/ReaderPostMenu.swift @@ -22,7 +22,7 @@ struct ReaderPostMenu { share, copyPostLink, viewPostInBrowser, - + post.isSeenSupported ? toggleSeen : nil ].compactMap { $0 }) } @@ -116,6 +116,17 @@ struct ReaderPostMenu { } } + private var toggleSeen: UIAction { + UIAction(post.isSeen ? Strings.markUnread : Strings.markRead, systemImage: post.isSeen ? "circle" : "checkmark.circle") { + track(post.isSeen ? .markUnread : .markRead) + ReaderSeenAction().execute(with: post, context: context, completion: { + NotificationCenter.default.post(name: .ReaderPostSeenToggled, object: nil, userInfo: [ReaderNotificationKeys.post: post]) + }, failure: { _ in + UINotificationFeedbackGenerator().notificationOccurred(.error) + }) + } + } + // MARK: Block and Report private func makeBlockOrReportActions() -> UIMenu { @@ -195,6 +206,8 @@ private enum ReaderPostMenuAnalyticsButton: String { case blockUser = "block_user" case reportPost = "report_post" case reportUser = "report_user" + case markRead = "mark_read" + case markUnread = "mark_unread" } private enum Strings { @@ -209,4 +222,6 @@ private enum Strings { static let blockUser = NSLocalizedString("reader.postContextMenu.blockUser", value: "Block User", comment: "Context menu action") static let reportPost = NSLocalizedString("reader.postContextMenu.reportPost", value: "Report Post", comment: "Context menu action") static let reportUser = NSLocalizedString("reader.postContextMenu.reportUser", value: "Report User", comment: "Context menu action") + static let markRead = NSLocalizedString("reader.postContextMenu.markRead", value: "Mark as Read", comment: "Context menu action") + static let markUnread = NSLocalizedString("reader.postContextMenu.markUnread", value: "Mark as Unread", comment: "Context menu action") }