Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix an issue with a missing "Mark as Unread" button in the More menu #23917

Merged
merged 4 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
-----
Expand Down
23 changes: 22 additions & 1 deletion WordPress/Classes/ViewRelated/Reader/Cards/ReaderPostCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -360,6 +370,17 @@ private final class ReaderPostCellView: UIView {
}
}

private func configureSeenCheckmarkIfNeeded() {
guard !isSeenCheckmarkConfigured else { return }
isSeenCheckmarkConfigured = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, why is a special flag used here? If the idea is to prevent repeated changes to image, maybe a lazy var is more appropriate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit cumbersome, but the view is created eagerly during the setup:

let headerView = UIStackView(alignment: .center, [buttonAuthor, dot, timeLabel, seenCheckmark])

Ideally, I should create it lazily and add it lazily to the stack view, but I felt it was simpler this way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you could make a lazy var seenCheckmar: UIImage so that this configuration function can be called repeatedly. Maybe it's personal preference, but I'm not a big fan of boolean flag type of states.


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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ final class ReaderPostCellViewModel {
// Content
let title: String
let details: String
let isSeen: Bool?
let imageURL: URL?

// Footer (Buttons)
Expand All @@ -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)
Expand Down Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ struct ReaderPostMenu {
share,
copyPostLink,
viewPostInBrowser,

post.isSeenSupported ? toggleSeen : nil
].compactMap { $0 })
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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")
}