From 93957ca33e2fa35b7cc70d89e3d6b64161730bd0 Mon Sep 17 00:00:00 2001 From: Alex Grebenyuk Date: Thu, 22 Jan 2026 14:24:14 -0500 Subject: [PATCH] Add a nicer way to access post from the comment list --- .../Views/Detail/CommentTableHeaderView.swift | 138 ------------------ .../ReaderCommentsTableViewController.swift | 10 -- .../ReaderCommentsViewController.swift | 77 ++++++++-- 3 files changed, 63 insertions(+), 162 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Comments/Views/Detail/CommentTableHeaderView.swift diff --git a/WordPress/Classes/ViewRelated/Comments/Views/Detail/CommentTableHeaderView.swift b/WordPress/Classes/ViewRelated/Comments/Views/Detail/CommentTableHeaderView.swift deleted file mode 100644 index f3c2c935fc0c..000000000000 --- a/WordPress/Classes/ViewRelated/Comments/Views/Detail/CommentTableHeaderView.swift +++ /dev/null @@ -1,138 +0,0 @@ -import SwiftUI - -class CommentTableHeaderView: UITableViewHeaderFooterView, Reusable { - - enum Subtitle { - /// Subtext for a top-level comment on a post. - case post - - /// Subtext for a reply to a comment. - /// Requires a String describing the replied author's name. - case reply(String) - - /// Subtext for the comment threads. - case commentThread - - fileprivate var stringValue: String { - switch self { - case .post: - return Constants.postCommentSubText - case .reply(let authorName): - return String(format: Constants.replyCommentSubTextFormat, authorName) - case .commentThread: - return Constants.commentThreadSubText - } - } - } - - private let hostingController: UIHostingController - - init(title: String, - subtitle: Subtitle, - showsDisclosureIndicator: Bool = false, - reuseIdentifier: String? = CommentTableHeaderView.defaultReuseID, - action: @escaping () -> Void) { - let headerView = CommentHeaderView( - title: title, - subtitle: subtitle, - showsDisclosureIndicator: showsDisclosureIndicator, - action: action - ) - hostingController = .init(rootView: headerView) - super.init(reuseIdentifier: reuseIdentifier) - configureView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Private methods - -private extension CommentTableHeaderView { - - func configureView() { - hostingController.view.translatesAutoresizingMaskIntoConstraints = false - hostingController.view.backgroundColor = .clear - contentView.addSubview(hostingController.view) - contentView.pinSubviewToAllEdges(hostingController.view) - } - - enum Constants { - static let postCommentSubText = NSLocalizedString( - "comment.header.subText.post", - value: "Comment on", - comment: """ - Provides a hint that the current screen displays a comment on a post. - The title of the post will be displayed below this text. - Example: Comment on \n My First Post - """ - ) - - static let replyCommentSubTextFormat = NSLocalizedString( - "comment.header.subText.reply", - value: "Reply to %1$@", - comment: """ - Provides a hint that the current screen displays a reply to a comment. - %1$@ is a placeholder for the comment author's name that's been replied to. - Example: Reply to Pamela Nguyen - """ - ) - - static let commentThreadSubText = NSLocalizedString( - "comment.header.subText.commentThread", - value: "Comments on", - comment: """ - Sentence fragment. - The full phrase is 'Comments on' followed by the title of the post on a separate line. - """ - ) - } -} - -// MARK: - SwiftUI - -private struct CommentHeaderView: View { - - @State var title: String - @State var subtitle: CommentTableHeaderView.Subtitle - @State var showsDisclosureIndicator: Bool - - let action: () -> Void - - var body: some View { - Button(action: action) { - HStack { - text - Spacer() - if showsDisclosureIndicator { - disclosureIndicator - } - } - } - .padding(EdgeInsets(top: 10, leading: 16, bottom: 10, trailing: 16)) - .background(.ultraThinMaterial) - } - - var text: some View { - VStack(alignment: .leading) { - Text(subtitle.stringValue) - .lineLimit(1) - .font(.footnote) - .foregroundColor(Color(.secondaryLabel)) - Text(title) - .lineLimit(1) - .font(.subheadline) - .foregroundColor(Color(.label)) - } - } - - var disclosureIndicator: some View { - Image(systemName: "chevron.forward") - .renderingMode(.template) - .foregroundColor(Color(.secondaryLabel)) - .font(.caption.weight(.semibold)) - .imageScale(.large) - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsTableViewController.swift b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsTableViewController.swift index 34c1a9c70df4..f08e408bb5da 100644 --- a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsTableViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsTableViewController.swift @@ -201,16 +201,6 @@ final class ReaderCommentsTableViewController: UIViewController, UITableViewData return viewModel } - // MARK: - UITableViewDataDelegate - - func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - containerViewController?.getHeaderView() - } - - func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - containerViewController?.getHeaderView() == nil ? 0 : UITableView.automaticDimension - } - // MARK: - UIScrollViewDelegate func scrollViewDidScroll(_ scrollView: UIScrollView) { diff --git a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.swift b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.swift index 284ced77b339..6ee1f7d62cc1 100644 --- a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsViewController.swift @@ -105,8 +105,69 @@ final class ReaderCommentsViewController: UIViewController, WPContentSyncHelperD private func setupNavigationBar() { navigationItem.backButtonTitle = "" - title = Strings.title navigationItem.largeTitleDisplayMode = .never + updateNavigationTitle() + } + + private func updateNavigationTitle() { + guard allowsPushingPostDetails, let post else { + title = Strings.title + navigationItem.titleView = nil + return + } + + let titleButton = UIButton(type: .system) + titleButton.addTarget(self, action: #selector(navigationTitleTapped), for: .touchUpInside) + + // Container stack view + let stackView = UIStackView() + stackView.axis = .vertical + stackView.alignment = .center + stackView.spacing = 2 + stackView.isUserInteractionEnabled = false + + // Main title label + let titleLabel = UILabel() + titleLabel.text = Strings.title + titleLabel.font = .preferredFont(forTextStyle: .headline) + titleLabel.textColor = .label + titleLabel.textAlignment = .center + titleLabel.maximumContentSizeCategory = .extraLarge + + // Subtitle with post name and indicator + let subtitleContainer = UIStackView() + subtitleContainer.axis = .horizontal + subtitleContainer.alignment = .center + subtitleContainer.spacing = 4 + + let subtitleLabel = UILabel() + subtitleLabel.text = post.titleForDisplay() + subtitleLabel.font = .preferredFont(forTextStyle: .caption1) + subtitleLabel.textColor = .secondaryLabel + subtitleLabel.textAlignment = .center + subtitleLabel.maximumContentSizeCategory = .extraLarge + + let chevronImageView = UIImageView() + let chevronImage = UIImage(systemName: "chevron.right.circle")? + .withConfiguration(UIImage.SymbolConfiguration(pointSize: 12, weight: .regular)) + chevronImageView.image = chevronImage + chevronImageView.tintColor = UIAppColor.primary + chevronImageView.contentMode = .scaleAspectFit + + subtitleContainer.addArrangedSubview(subtitleLabel) + subtitleContainer.addArrangedSubview(chevronImageView) + + stackView.addArrangedSubview(titleLabel) + stackView.addArrangedSubview(subtitleContainer) + + titleButton.addSubview(stackView) + stackView.pinEdges() + + navigationItem.titleView = titleButton + } + + @objc private func navigationTitleTapped() { + handleHeaderTapped() } private func setupView() { @@ -120,19 +181,6 @@ final class ReaderCommentsViewController: UIViewController, WPContentSyncHelperD activityIndicator.pinCenter() } - func getHeaderView() -> UIView? { - guard allowsPushingPostDetails, let post else { - return nil - } - return CommentTableHeaderView( - title: post.titleForDisplay(), - subtitle: .commentThread, - showsDisclosureIndicator: allowsPushingPostDetails - ) { [weak self] in - self?.handleHeaderTapped() - } - } - // MARK: - Fetch Post private func fetchPost() { @@ -157,6 +205,7 @@ final class ReaderCommentsViewController: UIViewController, WPContentSyncHelperD private func configure(with post: ReaderPost) { self.post = post + updateNavigationTitle() if post.isWPCom || post.isJetpack { let tableVC = ReaderCommentsTableViewController(post: post)