From 160eee70b44459b36b32ff02906d6974c88445fe Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 12:38:54 -0400 Subject: [PATCH 01/55] Remove ReaderSiteStreamHeader --- .../Reader/ReaderSiteStreamHeader.swift | 145 ------------------ .../Reader/ReaderSiteStreamHeader.xib | 101 ------------ .../Reader/WPStyleGuide+Reader.swift | 10 -- WordPress/WordPress.xcodeproj/project.pbxproj | 12 -- 4 files changed, 268 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderSiteStreamHeader.swift delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderSiteStreamHeader.xib diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderSiteStreamHeader.swift b/WordPress/Classes/ViewRelated/Reader/ReaderSiteStreamHeader.swift deleted file mode 100644 index e888dba1576f..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderSiteStreamHeader.swift +++ /dev/null @@ -1,145 +0,0 @@ -import Foundation -import WordPressShared -import Gridicons - -@objc open class ReaderSiteStreamHeader: UIView, ReaderStreamHeader { - @IBOutlet fileprivate weak var avatarImageView: UIImageView! - @IBOutlet fileprivate weak var titleLabel: UILabel! - @IBOutlet fileprivate weak var detailLabel: UILabel! - @IBOutlet fileprivate weak var followButton: UIButton! - @IBOutlet fileprivate weak var followCountLabel: UILabel! - @IBOutlet fileprivate weak var descriptionLabel: UILabel! - @IBOutlet fileprivate weak var descriptionLabelTopConstraint: NSLayoutConstraint! - - open weak var delegate: ReaderStreamHeaderDelegate? - - // MARK: - Lifecycle Methods - - open override func awakeFromNib() { - super.awakeFromNib() - - applyStyles() - } - - private func applyStyles() { - WPStyleGuide.applyReaderStreamHeaderTitleStyle(titleLabel) - WPStyleGuide.applyReaderStreamHeaderDetailStyle(detailLabel) - WPStyleGuide.applyReaderSiteStreamDescriptionStyle(descriptionLabel) - WPStyleGuide.applyReaderSiteStreamCountStyle(followCountLabel) - } - - open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) - - if previousTraitCollection?.preferredContentSizeCategory != traitCollection.preferredContentSizeCategory { - preferredContentSizeDidChange() - } - - if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) { - WPStyleGuide.applyReaderFollowButtonStyle(followButton) - } - } - - // MARK: - Configuration - - @objc open func configureHeader(_ topic: ReaderAbstractTopic) { - guard let siteTopic = topic as? ReaderSiteTopic else { - DDLogError("Topic must be a site topic") - return - } - - followButton.isSelected = topic.following - titleLabel.text = siteTopic.title - descriptionLabel.text = siteTopic.siteDescription - followCountLabel.text = formattedFollowerCountForTopic(siteTopic) - detailLabel.text = URL(string: siteTopic.siteURL)?.host - - configureHeaderImage(siteTopic) - - WPStyleGuide.applyReaderFollowButtonStyle(followButton) - - if siteTopic.siteDescription.isEmpty { - descriptionLabelTopConstraint.constant = 0.0 - } - } - - private func configureHeaderImage(_ siteTopic: ReaderSiteTopic) { - let placeholder = UIImage.siteIconPlaceholder - - guard let url = upscaledImageURL(urlString: siteTopic.siteBlavatar) else { - if siteTopic.isP2Type { - avatarImageView.tintColor = UIColor.secondaryLabel - avatarImageView.layer.borderColor = UIColor.separator.cgColor - avatarImageView.layer.borderWidth = .hairlineBorderWidth - avatarImageView.image = UIImage.gridicon(.p2) - return - } - - avatarImageView.image = placeholder - return - } - - avatarImageView.downloadImage(from: url, placeholderImage: placeholder) - } - - private func formattedFollowerCountForTopic(_ topic: ReaderSiteTopic) -> String { - let numberFormatter = NumberFormatter() - numberFormatter.numberStyle = .decimal - - let count = numberFormatter.string(from: topic.subscriberCount) ?? "0" - let pattern = NSLocalizedString( - "reader.blog.stream.subscribers", - value: "%@ subscribers", - comment: "The number of followers of a site. The '%@' is a placeholder for the numeric value. Example: `1000 followers`" - ) - let str = String(format: pattern, count) - - return str - } - - @objc open func enableLoggedInFeatures(_ enable: Bool) { - followButton.isHidden = !enable - } - - func preferredContentSizeDidChange() { - applyStyles() - } - - // MARK: - Actions - - @IBAction func didTapFollowButton(_ sender: UIButton) { - followButton.isUserInteractionEnabled = false - - delegate?.handleFollowActionForHeader(self) { [weak self] in - self?.followButton.isUserInteractionEnabled = true - } - } - - // MARK: - Private: Helpers - - /// Replaces the width query item (w) with an upscaled one for the image view - private func upscaledImageURL(urlString: String) -> URL? { - guard - let url = URL(string: urlString), - var components = URLComponents(url: url, resolvingAgainstBaseURL: true), - let host = components.host - else { - return nil - } - - // WP.com uses `w` and Gravatar uses `s` for the resizing query key - let widthKey = host.contains("gravatar") ? "s" : "w" - let width = Int(avatarImageView.bounds.width * UIScreen.main.scale) - let item = URLQueryItem(name: widthKey, value: "\(width)") - - var queryItems = components.queryItems ?? [] - - // Remove any existing size queries - queryItems.removeAll(where: { $0.name == widthKey}) - - queryItems.append(item) - components.queryItems = queryItems - - return components.url - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderSiteStreamHeader.xib b/WordPress/Classes/ViewRelated/Reader/ReaderSiteStreamHeader.xib deleted file mode 100644 index 83dacb7a3242..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderSiteStreamHeader.xib +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift b/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift index 6fb3a76b5d25..dc1bc377354e 100644 --- a/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift +++ b/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift @@ -128,16 +128,6 @@ extension WPStyleGuide { label.textColor = .secondaryLabel } - @objc public class func applyReaderSiteStreamDescriptionStyle(_ label: UILabel) { - label.font = fontForTextStyle(.body, fontWeight: .regular) - label.textColor = .label - } - - @objc public class func applyReaderSiteStreamCountStyle(_ label: UILabel) { - WPStyleGuide.configureLabel(label, textStyle: Cards.contentTextStyle) - label.textColor = .secondaryLabel - } - // MARK: - Button Styles and Text class func applyReaderActionButtonStyle(_ button: UIButton, titleColor: UIColor = .secondaryLabel, diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index c1871b030117..432b03704505 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -3712,10 +3712,8 @@ E6C0ED3B231DA23400A08B57 /* AccountService+MergeDuplicates.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6C0ED3A231DA23400A08B57 /* AccountService+MergeDuplicates.swift */; }; E6C892D61C601D55007AD612 /* SharingButtonsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6C892D51C601D55007AD612 /* SharingButtonsViewController.swift */; }; E6D170371EF9D8D10046D433 /* SiteInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D170361EF9D8D10046D433 /* SiteInfo.swift */; }; - E6D2E15F1B8A9C830000ED14 /* ReaderSiteStreamHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = E6D2E15E1B8A9C830000ED14 /* ReaderSiteStreamHeader.xib */; }; E6D2E1611B8AA4410000ED14 /* ReaderTagStreamHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = E6D2E1601B8AA4410000ED14 /* ReaderTagStreamHeader.xib */; }; E6D2E1631B8AAA340000ED14 /* ReaderListStreamHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = E6D2E1621B8AAA340000ED14 /* ReaderListStreamHeader.xib */; }; - E6D2E1651B8AAD7E0000ED14 /* ReaderSiteStreamHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D2E1641B8AAD7E0000ED14 /* ReaderSiteStreamHeader.swift */; }; E6D2E1671B8AAD8C0000ED14 /* ReaderTagStreamHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D2E1661B8AAD8C0000ED14 /* ReaderTagStreamHeader.swift */; }; E6D2E1691B8AAD9B0000ED14 /* ReaderListStreamHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D2E1681B8AAD9B0000ED14 /* ReaderListStreamHeader.swift */; }; E6D2E16C1B8B423B0000ED14 /* ReaderStreamHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D2E16B1B8B423B0000ED14 /* ReaderStreamHeader.swift */; }; @@ -4350,7 +4348,6 @@ FABB20602602FC2C00C8785C /* MediaSizeSliderCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = E14977191C0DCB6F0057CD60 /* MediaSizeSliderCell.xib */; }; FABB20622602FC2C00C8785C /* ReaderBlockedSiteCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = E65219F81B8D10C2000B1217 /* ReaderBlockedSiteCell.xib */; }; FABB20652602FC2C00C8785C /* SiteSegmentsCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D8C31CC52188490000A33B35 /* SiteSegmentsCell.xib */; }; - FABB20662602FC2C00C8785C /* ReaderSiteStreamHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = E6D2E15E1B8A9C830000ED14 /* ReaderSiteStreamHeader.xib */; }; FABB20692602FC2C00C8785C /* ReaderTopicsCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = C7192ECE25E8432D00C3020D /* ReaderTopicsCardCell.xib */; }; FABB206B2602FC2C00C8785C /* richEmbedTemplate.html in Resources */ = {isa = PBXBuildFile; fileRef = E61507E12220A0FE00213D33 /* richEmbedTemplate.html */; }; FABB206D2602FC2C00C8785C /* NoteBlockUserTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5C66B791ACF074600F68370 /* NoteBlockUserTableViewCell.xib */; }; @@ -4756,7 +4753,6 @@ FABB22882602FC2C00C8785C /* UserSuggestion+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0B68A9B252FA91E0001B28C /* UserSuggestion+CoreDataProperties.swift */; }; FABB228A2602FC2C00C8785C /* ReaderHeaderAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CC620AA85C1008E8AE8 /* ReaderHeaderAction.swift */; }; FABB228B2602FC2C00C8785C /* FancyAlerts+VerificationPrompt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 405B53FA1F83C369002E19BF /* FancyAlerts+VerificationPrompt.swift */; }; - FABB228C2602FC2C00C8785C /* ReaderSiteStreamHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6D2E1641B8AAD7E0000ED14 /* ReaderSiteStreamHeader.swift */; }; FABB228D2602FC2C00C8785C /* VideoUploadProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F126FDFD20A33BDB0010EB6E /* VideoUploadProcessor.swift */; }; FABB228E2602FC2C00C8785C /* PeopleCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E166FA1A1BB0656B00374B5B /* PeopleCellViewModel.swift */; }; FABB22902602FC2C00C8785C /* RegisterDomainDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 436D56192117312700CEAA33 /* RegisterDomainDetailsViewController.swift */; }; @@ -9263,10 +9259,8 @@ E6C0ED3A231DA23400A08B57 /* AccountService+MergeDuplicates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountService+MergeDuplicates.swift"; sourceTree = ""; }; E6C892D51C601D55007AD612 /* SharingButtonsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharingButtonsViewController.swift; sourceTree = ""; }; E6D170361EF9D8D10046D433 /* SiteInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SiteInfo.swift; sourceTree = ""; }; - E6D2E15E1B8A9C830000ED14 /* ReaderSiteStreamHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReaderSiteStreamHeader.xib; sourceTree = ""; }; E6D2E1601B8AA4410000ED14 /* ReaderTagStreamHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReaderTagStreamHeader.xib; sourceTree = ""; }; E6D2E1621B8AAA340000ED14 /* ReaderListStreamHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReaderListStreamHeader.xib; sourceTree = ""; }; - E6D2E1641B8AAD7E0000ED14 /* ReaderSiteStreamHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderSiteStreamHeader.swift; sourceTree = ""; }; E6D2E1661B8AAD8C0000ED14 /* ReaderTagStreamHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderTagStreamHeader.swift; sourceTree = ""; }; E6D2E1681B8AAD9B0000ED14 /* ReaderListStreamHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderListStreamHeader.swift; sourceTree = ""; }; E6D2E16B1B8B423B0000ED14 /* ReaderStreamHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderStreamHeader.swift; sourceTree = ""; }; @@ -17881,8 +17875,6 @@ E6D2E1681B8AAD9B0000ED14 /* ReaderListStreamHeader.swift */, E6D2E1621B8AAA340000ED14 /* ReaderListStreamHeader.xib */, 83A337A02A9FA525009ED60C /* ReaderSiteHeaderView.swift */, - E6D2E1641B8AAD7E0000ED14 /* ReaderSiteStreamHeader.swift */, - E6D2E15E1B8A9C830000ED14 /* ReaderSiteStreamHeader.xib */, E6D2E16B1B8B423B0000ED14 /* ReaderStreamHeader.swift */, 0C0BEEEA2CC02D2C0073F4E0 /* ReaderDiscoverHeaderView.swift */, E6D2E1661B8AAD8C0000ED14 /* ReaderTagStreamHeader.swift */, @@ -20200,7 +20192,6 @@ 1761F18326209AEE000815EF /* jetpack-green-icon-app-83.5x83.5@2x.png in Resources */, 0186358D2A810ABA00915532 /* support_chat_widget.js in Resources */, 9801E685274EEC19002FDDB6 /* ReaderDetailCommentsHeader.xib in Resources */, - E6D2E15F1B8A9C830000ED14 /* ReaderSiteStreamHeader.xib in Resources */, C7192ECF25E8432D00C3020D /* ReaderTopicsCardCell.xib in Resources */, 17222D8E261DDDF90047B163 /* black-classic-icon-app-76x76.png in Resources */, E61507E22220A0FE00213D33 /* richEmbedTemplate.html in Resources */, @@ -20737,7 +20728,6 @@ FABB20602602FC2C00C8785C /* MediaSizeSliderCell.xib in Resources */, FABB20622602FC2C00C8785C /* ReaderBlockedSiteCell.xib in Resources */, FABB20652602FC2C00C8785C /* SiteSegmentsCell.xib in Resources */, - FABB20662602FC2C00C8785C /* ReaderSiteStreamHeader.xib in Resources */, FABB20692602FC2C00C8785C /* ReaderTopicsCardCell.xib in Resources */, F465980928E66A5B00D5F49A /* white-on-blue-icon-app-76.png in Resources */, FABB206B2602FC2C00C8785C /* richEmbedTemplate.html in Resources */, @@ -22061,7 +22051,6 @@ D8212CC720AA85C1008E8AE8 /* ReaderHeaderAction.swift in Sources */, 405B53FB1F83C369002E19BF /* FancyAlerts+VerificationPrompt.swift in Sources */, 83E1E55F2A5CB8BF000B576F /* PostEditor+JetpackSocial.swift in Sources */, - E6D2E1651B8AAD7E0000ED14 /* ReaderSiteStreamHeader.swift in Sources */, F126FE0020A33BDB0010EB6E /* VideoUploadProcessor.swift in Sources */, E166FA1B1BB0656B00374B5B /* PeopleCellViewModel.swift in Sources */, 436D56292117312700CEAA33 /* RegisterDomainDetailsViewController.swift in Sources */, @@ -25008,7 +24997,6 @@ FABB228A2602FC2C00C8785C /* ReaderHeaderAction.swift in Sources */, FA4FE0B12BEA7FA800A635D3 /* RemotePost+Metadata.swift in Sources */, FABB228B2602FC2C00C8785C /* FancyAlerts+VerificationPrompt.swift in Sources */, - FABB228C2602FC2C00C8785C /* ReaderSiteStreamHeader.swift in Sources */, FABB228D2602FC2C00C8785C /* VideoUploadProcessor.swift in Sources */, FE34ACD02B1661EB00108B3C /* DashboardBloganuaryCardCell.swift in Sources */, FABB228E2602FC2C00C8785C /* PeopleCellViewModel.swift in Sources */, From 97a774e06019552f7073693dee0c196847099b30 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 12:49:22 -0400 Subject: [PATCH 02/55] Remove ReaderTabView --- .../Reader/Tab Navigation/ReaderTabView.swift | 292 ------------------ WordPress/WordPress.xcodeproj/project.pbxproj | 26 -- .../ReaderTabItemsStoreTests.swift | 88 ------ .../ReaderTabViewModelTests.swift | 219 ------------- .../WordPressTest/ReaderTabViewTests.swift | 7 - 5 files changed, 632 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift delete mode 100644 WordPress/WordPressTest/ReaderTabItemsStoreTests.swift delete mode 100644 WordPress/WordPressTest/ReaderTabViewModelTests.swift delete mode 100644 WordPress/WordPressTest/ReaderTabViewTests.swift diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift deleted file mode 100644 index da0a390312fd..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabView.swift +++ /dev/null @@ -1,292 +0,0 @@ -import UIKit - -class ReaderTabView: UIView { - - private let mainStackView: UIStackView - private var mainStackViewTopAnchor: NSLayoutConstraint? - private let containerView: UIView - private let buttonContainer: UIView - private lazy var navigationMenu: UIView = { - if !viewModel.itemsLoaded { - viewModel.fetchReaderMenu() - } - let view = UIView.embedSwiftUIView(ReaderNavigationMenu(viewModel: viewModel)) - view.translatesAutoresizingMaskIntoConstraints = false - return view - }() - private var isMenuHidden = false - - private let viewModel: ReaderTabViewModel - - private var filteredTabs: [(index: Int, topic: ReaderAbstractTopic)] = [] - private var previouslySelectedIndex: Int = 0 - private var currentTabItems: [ReaderTabItem] = [] - private weak var childController: UIViewController? - - private var discoverIndex: Int? { - return viewModel.tabItems.firstIndex(where: { $0.content.topicType == .discover }) - } - - private var p2Index: Int? { - return viewModel.tabItems.firstIndex(where: { ($0.content.topic as? ReaderTeamTopic)?.organizationID == SiteOrganizationType.p2.rawValue }) - } - - init(viewModel: ReaderTabViewModel) { - mainStackView = UIStackView() - containerView = UIView() - buttonContainer = UIView() - - self.viewModel = viewModel - - super.init(frame: .zero) - - viewModel.didSelectIndex = { [weak self] index in - guard let self else { - return - } - - if let existingFilter = filteredTabs.first(where: { $0.index == index }) { - if previouslySelectedIndex == discoverIndex { - addContentToContainerView(index: index) - } - viewModel.setFilterContent(topic: existingFilter.topic) - } else { - addContentToContainerView(index: index) - } - previouslySelectedIndex = index - } - - viewModel.onTabBarItemsDidChange { [weak self] tabItems, index in - if self?.childController != nil && self?.currentTabItems == tabItems { - return - } - self?.addContentToContainerView(index: index) - self?.currentTabItems = tabItems - } - - setupViewElements() - viewModel.fetchReaderMenu() - - NotificationCenter.default.addObserver(self, selector: #selector(topicUnfollowed(_:)), name: .ReaderTopicUnfollowed, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(siteFollowed(_:)), name: .ReaderSiteFollowed, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(filterUpdated(_:)), name: .ReaderFilterUpdated, object: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -// MARK: - UI setup - -extension ReaderTabView { - - private func setupViewElements() { - backgroundColor = UIColor(light: .white, dark: .black) - setupButtonContainer() - setupMainStackView() - activateConstraints() - } - - private func setupButtonContainer() { - buttonContainer.translatesAutoresizingMaskIntoConstraints = false - buttonContainer.addSubview(navigationMenu) - } - - private func setupMainStackView() { - mainStackView.translatesAutoresizingMaskIntoConstraints = false - mainStackView.axis = .vertical - addSubview(buttonContainer) - addSubview(mainStackView) - mainStackView.addArrangedSubview(containerView) - } - - private func setupHorizontalDivider(_ divider: UIView) { - divider.translatesAutoresizingMaskIntoConstraints = false - divider.backgroundColor = Appearance.dividerColor - } - - private func addContentToContainerView(index: Int) { - guard let controller = self.next as? UIViewController, - let childController = viewModel.makeChildContentViewController(at: index) else { - return - } - - if let childController = childController as? ReaderStreamViewController { - childController.navigationMenuDelegate = self - } - - containerView.translatesAutoresizingMaskIntoConstraints = false - childController.view.translatesAutoresizingMaskIntoConstraints = false - - controller.children.forEach { - $0.remove() - } - controller.add(childController) - containerView.pinSubviewToAllEdges(childController.view) - - self.childController = childController - } - - private func activateConstraints() { - mainStackViewTopAnchor = mainStackView.topAnchor.constraint(equalTo: buttonContainer.bottomAnchor) - guard let mainStackViewTopAnchor else { return } - NSLayoutConstraint.activate([ - navigationMenu.leadingAnchor.constraint(equalTo: buttonContainer.leadingAnchor, constant: 12.0), - navigationMenu.trailingAnchor.constraint(equalTo: buttonContainer.trailingAnchor, constant: -16.0), - navigationMenu.topAnchor.constraint(equalTo: buttonContainer.topAnchor, constant: 8.0), - navigationMenu.bottomAnchor.constraint(equalTo: buttonContainer.bottomAnchor, constant: -8.0), - buttonContainer.topAnchor.constraint(equalTo: safeTopAnchor), - buttonContainer.leadingAnchor.constraint(equalTo: safeLeadingAnchor), - buttonContainer.trailingAnchor.constraint(equalTo: safeTrailingAnchor), - mainStackViewTopAnchor, - mainStackView.trailingAnchor.constraint(equalTo: safeTrailingAnchor), - mainStackView.leadingAnchor.constraint(equalTo: safeLeadingAnchor), - mainStackView.bottomAnchor.constraint(equalTo: safeBottomAnchor), - ]) - } - - func applyFilter(for selectedTopic: ReaderAbstractTopic?) { - guard let selectedTopic = selectedTopic else { - return - } - - let selectedIndex = viewModel.selectedIndex - - // Remove any filters for selected index, then add new filter to array. - self.filteredTabs.removeAll(where: { $0.index == selectedIndex }) - self.filteredTabs.append((index: selectedIndex, topic: selectedTopic)) - } - - /// Disables the `scrollsToTop` property for the scroll views created from SwiftUI. - /// To preserve the native scroll-to-top behavior when the status bar is tapped, there could only be - /// one scroll view on screen with the `scrollsToTop` property set to `true`. - func disableScrollsToTop() { - var viewsToTraverse = navigationMenu.subviews - while viewsToTraverse.count > 0 { - let subview = viewsToTraverse.removeFirst() - if let scrollView = subview as? UIScrollView { - scrollView.scrollsToTop = false - } - viewsToTraverse.append(contentsOf: subview.subviews) - } - } - - private func updateMenuDisplay(hidden: Bool) { - guard isMenuHidden != hidden else { return } - - isMenuHidden = hidden - mainStackViewTopAnchor?.constant = hidden ? -buttonContainer.frame.height : 0 - UIView.animate(withDuration: Appearance.hideShowBarDuration) { - self.layoutIfNeeded() - } - } -} - -// MARK: - Actions - -private extension ReaderTabView { - - @objc func topicUnfollowed(_ notification: Foundation.Notification) { - guard let userInfo = notification.userInfo, - let topic = userInfo[ReaderNotificationKeys.topic] as? ReaderAbstractTopic, - let existingFilter = filteredTabs.first(where: { $0.topic == topic }) else { - return - } - - filteredTabs.removeAll(where: { $0 == existingFilter }) - } - - @objc func siteFollowed(_ notification: Foundation.Notification) { - guard let userInfo = notification.userInfo, - let site = userInfo[ReaderNotificationKeys.topic] as? ReaderSiteTopic, - site.organizationType == .p2, - p2Index == nil else { - return - } - - // If a P2 is followed but the P2 tab is not in the Reader tab bar, - // refresh the Reader menu to display it. - viewModel.fetchReaderMenu() - } - - @objc func filterUpdated(_ notification: Foundation.Notification) { - guard let userInfo = notification.userInfo, - let topic = userInfo[ReaderNotificationKeys.topic] as? ReaderTagTopic, - let filterProvider = viewModel.streamFilters.first(where: { $0.reuseIdentifier == FilterProvider.ReuseIdentifiers.tags }) else { - return - } - viewModel.setFilterContent(topic: topic) - viewModel.activeStreamFilter = (filterProvider.id, topic) - } - -} - -// MARK: - Appearance - -private extension ReaderTabView { - - enum Appearance { - static let barHeight: CGFloat = 48 - static let dividerColor: UIColor = .separator - static let hideShowBarDuration: CGFloat = 0.2 - } -} - -// MARK: - ReaderNavigationMenuDelegate - -extension ReaderTabView: ReaderNavigationMenuDelegate { - - func scrollViewDidScroll(_ scrollView: UIScrollView, velocity: CGPoint) { - let isContentOffsetNearTop = scrollView.contentOffset.y < scrollView.frame.height / 2 - let isContentOffsetAtTop = scrollView.contentOffset.y == .zero - let isUserScrollingDown = velocity.y < -400 - let isUserScrollingUp = velocity.y > 400 - - if !isMenuHidden && !isContentOffsetNearTop && isUserScrollingDown { - updateMenuDisplay(hidden: true) - } - - if isMenuHidden && isUserScrollingUp { - updateMenuDisplay(hidden: false) - } - - // Handles the native scroll-to-top behavior (by tapping the status bar). - // Somehow the `scrollViewDidScrollToTop` method is not called in the view controller - // containing the scroll view, so we'll need to put a custom logic here instead. - if isMenuHidden && isContentOffsetAtTop { - updateMenuDisplay(hidden: false) - } - - // Accounts for a user scrolling slowly enough to not trigger displaying the menu near the top of the content - if isMenuHidden && isContentOffsetNearTop && velocity.y > 0 { - updateMenuDisplay(hidden: false) - } - - } - - func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { - let isTargetContentNearTop = targetContentOffset.pointee.y < scrollView.frame.height / 2 - - // Accounts for the case where a user quickly swipes the scroll view without holding their - // finger on it. - // Note: velocity here is opposite of the velocity in `scrollViewDidScroll`. Positive values - // are scrolling down. The scale is also much different. - if !isMenuHidden && !isTargetContentNearTop && velocity.y > 0.5 { - updateMenuDisplay(hidden: true) - } - } - - func didTapDiscoverBlogs() { - guard let discoverIndex else { - return - } - viewModel.showTab(at: discoverIndex) - } - - func didScrollToTop() { - updateMenuDisplay(hidden: false) - } - -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 432b03704505..0344c9cec133 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -1078,7 +1078,6 @@ 374CB16215B93C0800DD0EBC /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */; }; 37EAAF4D1A11799A006D6306 /* CircularImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37EAAF4C1A11799A006D6306 /* CircularImageView.swift */; }; 3F09CCA82428FF3300D00A8C /* ReaderTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F09CCA72428FF3300D00A8C /* ReaderTabViewController.swift */; }; - 3F09CCAA2428FF8300D00A8C /* ReaderTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F09CCA92428FF8300D00A8C /* ReaderTabView.swift */; }; 3F09CCAE24292EFD00D00A8C /* ReaderTabItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */; }; 3F170E242655917400F6F670 /* UIView+SwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F170E232655917400F6F670 /* UIView+SwiftUI.swift */; }; 3F170E252655917400F6F670 /* UIView+SwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F170E232655917400F6F670 /* UIView+SwiftUI.swift */; }; @@ -1118,8 +1117,6 @@ 3F4D035128A56F9B00F0A4FD /* CircularImageButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F4D034F28A56F9B00F0A4FD /* CircularImageButton.swift */; }; 3F4D035328A5BFCE00F0A4FD /* JetpackWordPressLogoAnimation_ltr.json in Resources */ = {isa = PBXBuildFile; fileRef = 3F4D035228A5BFCE00F0A4FD /* JetpackWordPressLogoAnimation_ltr.json */; }; 3F4EB39228AC561600B8DD86 /* JetpackWordPressLogoAnimation_rtl.json in Resources */ = {isa = PBXBuildFile; fileRef = 3F4EB39128AC561600B8DD86 /* JetpackWordPressLogoAnimation_rtl.json */; }; - 3F50945B2454ECA000C4470B /* ReaderTabItemsStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F50945A2454ECA000C4470B /* ReaderTabItemsStoreTests.swift */; }; - 3F50945F245537A700C4470B /* ReaderTabViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F50945E245537A700C4470B /* ReaderTabViewModelTests.swift */; }; 3F56F55C2AEA2F67006BDCEA /* ReaderPostBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F56F55B2AEA2F67006BDCEA /* ReaderPostBuilder.swift */; }; 3F593FDD2A81DC6D00B29E86 /* NSError+TestInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F593FDC2A81DC6D00B29E86 /* NSError+TestInstance.swift */; }; 3F5AAC242877791900AEF5DD /* JetpackButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FFA5ED12876152E00830E28 /* JetpackButton.swift */; }; @@ -1146,7 +1143,6 @@ 3F759FBE2A2DB3280039A845 /* AccountSettingsRemoteInterfaceStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F759FBD2A2DB3280039A845 /* AccountSettingsRemoteInterfaceStub.swift */; }; 3F810A5A2616870C00ADDCC2 /* UnifiedPrologueIntroContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F810A592616870C00ADDCC2 /* UnifiedPrologueIntroContentView.swift */; }; 3F810A5B2616870C00ADDCC2 /* UnifiedPrologueIntroContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F810A592616870C00ADDCC2 /* UnifiedPrologueIntroContentView.swift */; }; - 3F82310F24564A870086E9B8 /* ReaderTabViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F82310E24564A870086E9B8 /* ReaderTabViewTests.swift */; }; 3F8513DF260D091500A4B938 /* RoundRectangleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8513DE260D091500A4B938 /* RoundRectangleView.swift */; }; 3F851415260D0A3300A4B938 /* UnifiedPrologueEditorContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F851414260D0A3300A4B938 /* UnifiedPrologueEditorContentView.swift */; }; 3F851428260D1EA300A4B938 /* CircledIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F851427260D1EA300A4B938 /* CircledIcon.swift */; }; @@ -5221,7 +5217,6 @@ FABB24BA2602FC2C00C8785C /* TenorGIF.swift in Sources */ = {isa = PBXBuildFile; fileRef = C81CCD60243AECA100A83E27 /* TenorGIF.swift */; }; FABB24BB2602FC2C00C8785C /* ThemeBrowserViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 596C035D1B84F21D00899EEB /* ThemeBrowserViewController.swift */; }; FABB24BC2602FC2C00C8785C /* RevisionOperationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4353BFA8219E0E820009CED3 /* RevisionOperationViewController.swift */; }; - FABB24BE2602FC2C00C8785C /* ReaderTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F09CCA92428FF8300D00A8C /* ReaderTabView.swift */; }; FABB24BF2602FC2C00C8785C /* EpilogueUserInfoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9808655B203D079A00D58786 /* EpilogueUserInfoCell.swift */; }; FABB24C02602FC2C00C8785C /* MenuItemTypeSelectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 08216FC51CDBF96000304BA7 /* MenuItemTypeSelectionView.m */; }; FABB24C12602FC2C00C8785C /* WordPressAppDelegate+openURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43B0BA952229927F00328C69 /* WordPressAppDelegate+openURL.swift */; }; @@ -6951,7 +6946,6 @@ 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 37EAAF4C1A11799A006D6306 /* CircularImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircularImageView.swift; sourceTree = ""; }; 3F09CCA72428FF3300D00A8C /* ReaderTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTabViewController.swift; sourceTree = ""; }; - 3F09CCA92428FF8300D00A8C /* ReaderTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTabView.swift; sourceTree = ""; }; 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTabItem.swift; sourceTree = ""; }; 3F170E232655917400F6F670 /* UIView+SwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+SwiftUI.swift"; sourceTree = ""; }; 3F1B66A223A2F54B0075F09E /* ReaderReblogActionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderReblogActionTests.swift; sourceTree = ""; }; @@ -6982,8 +6976,6 @@ 3F4D034F28A56F9B00F0A4FD /* CircularImageButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularImageButton.swift; sourceTree = ""; }; 3F4D035228A5BFCE00F0A4FD /* JetpackWordPressLogoAnimation_ltr.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = JetpackWordPressLogoAnimation_ltr.json; sourceTree = ""; }; 3F4EB39128AC561600B8DD86 /* JetpackWordPressLogoAnimation_rtl.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = JetpackWordPressLogoAnimation_rtl.json; sourceTree = ""; }; - 3F50945A2454ECA000C4470B /* ReaderTabItemsStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTabItemsStoreTests.swift; sourceTree = ""; }; - 3F50945E245537A700C4470B /* ReaderTabViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTabViewModelTests.swift; sourceTree = ""; }; 3F526C4D2538CF2A0069706C /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; 3F526C4F2538CF2A0069706C /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; 3F526C522538CF2A0069706C /* HomeWidgetToday.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeWidgetToday.swift; sourceTree = ""; }; @@ -7016,7 +7008,6 @@ 3F759FBB2A2DB2CF0039A845 /* TestError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestError.swift; sourceTree = ""; }; 3F759FBD2A2DB3280039A845 /* AccountSettingsRemoteInterfaceStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSettingsRemoteInterfaceStub.swift; sourceTree = ""; }; 3F810A592616870C00ADDCC2 /* UnifiedPrologueIntroContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnifiedPrologueIntroContentView.swift; sourceTree = ""; }; - 3F82310E24564A870086E9B8 /* ReaderTabViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTabViewTests.swift; sourceTree = ""; }; 3F8513DE260D091500A4B938 /* RoundRectangleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundRectangleView.swift; sourceTree = ""; }; 3F851414260D0A3300A4B938 /* UnifiedPrologueEditorContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnifiedPrologueEditorContentView.swift; sourceTree = ""; }; 3F851427260D1EA300A4B938 /* CircledIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircledIcon.swift; sourceTree = ""; }; @@ -11739,7 +11730,6 @@ 8352AC732B2A485100F8492C /* ReaderNavigationMenu.swift */, 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */, 3FC8D19A244F43B500495820 /* ReaderTabItemsStore.swift */, - 3F09CCA92428FF8300D00A8C /* ReaderTabView.swift */, 3F09CCA72428FF3300D00A8C /* ReaderTabViewController.swift */, 3F6975FE242D941E001F1807 /* ReaderTabViewModel.swift */, 3FF1A852242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift */, @@ -12031,16 +12021,6 @@ path = ViewModel; sourceTree = ""; }; - 3F5094592454EC7A00C4470B /* Tabbed Reader */ = { - isa = PBXGroup; - children = ( - 3F50945A2454ECA000C4470B /* ReaderTabItemsStoreTests.swift */, - 3F82310E24564A870086E9B8 /* ReaderTabViewTests.swift */, - 3F50945E245537A700C4470B /* ReaderTabViewModelTests.swift */, - ); - name = "Tabbed Reader"; - sourceTree = ""; - }; 3F526D2B2539F9D60069706C /* Views */ = { isa = PBXGroup; children = ( @@ -17862,7 +17842,6 @@ E6B9B8AE1B94FA1C0001B92F /* ReaderStreamViewControllerTests.swift */, 8B7F51CA24EED8A8008CF5B5 /* ReaderTrackerTests.swift */, 3F1B66A123A2F52A0075F09E /* ReaderPostActions */, - 3F5094592454EC7A00C4470B /* Tabbed Reader */, 08C42C30281807880034720B /* ReaderSubscribeCommentsActionTests.swift */, ); name = Reader; @@ -22840,7 +22819,6 @@ 596C035E1B84F21D00899EEB /* ThemeBrowserViewController.swift in Sources */, 4353BFA9219E0E820009CED3 /* RevisionOperationViewController.swift in Sources */, 803D90F7292F0188007CC0D0 /* JetpackRedirector.swift in Sources */, - 3F09CCAA2428FF8300D00A8C /* ReaderTabView.swift in Sources */, 9808655C203D079B00D58786 /* EpilogueUserInfoCell.swift in Sources */, 08216FD41CDBF96000304BA7 /* MenuItemTypeSelectionView.m in Sources */, 43B0BA962229927F00328C69 /* WordPressAppDelegate+openURL.swift in Sources */, @@ -24175,7 +24153,6 @@ F4EF4BAB291D3D4700147B61 /* SiteIconViewModelTests.swift in Sources */, FA6C32C02BF255FA00BBDDB4 /* AppUpdateCoordinatorTests.swift in Sources */, 59B48B621B99E132008EBB84 /* JSONObject.swift in Sources */, - 3F82310F24564A870086E9B8 /* ReaderTabViewTests.swift in Sources */, C3E42AB027F4D30E00546706 /* MenuItemsViewControllerTests.swift in Sources */, D842EA4021FABB1800210E96 /* SiteSegmentTests.swift in Sources */, C3C70C562835C5BB00DD2546 /* SiteDesignSectionLoaderTests.swift in Sources */, @@ -24319,7 +24296,6 @@ B09879792B5730BC0048256D /* StatsTrafficDatePickerViewModelTests.swift in Sources */, D821C81B21003AE9002ED995 /* FormattableContentGroupTests.swift in Sources */, 93D86B981C691E71003D8E3E /* LocalCoreDataServiceTests.m in Sources */, - 3F50945B2454ECA000C4470B /* ReaderTabItemsStoreTests.swift in Sources */, 0CD6299B2B9AAA9A00325EA4 /* Foundation+Extensions.swift in Sources */, 1DF7A0D32BA0B1810003CBA3 /* GutenbergContentParser.swift in Sources */, 8384C64428AAC85F00EABE26 /* KeychainUtilsTests.swift in Sources */, @@ -24340,7 +24316,6 @@ E1B921BC1C0ED5A3003EA3CB /* MediaSizeSliderCellTest.swift in Sources */, C314543B262770BE005B216B /* BlogServiceAuthorTests.swift in Sources */, FE34ACD22B174AE700108B3C /* DashboardBloganuaryCardCellTests.swift in Sources */, - 3F50945F245537A700C4470B /* ReaderTabViewModelTests.swift in Sources */, 0885A3671E837AFE00619B4D /* URLIncrementalFilenameTests.swift in Sources */, D848CBF920FEF82100A9038F /* NotificationsContentFactoryTests.swift in Sources */, FE1E201E2A49D59400CE7C90 /* JetpackSocialServiceTests.swift in Sources */, @@ -25806,7 +25781,6 @@ FABB24BB2602FC2C00C8785C /* ThemeBrowserViewController.swift in Sources */, FABB24BC2602FC2C00C8785C /* RevisionOperationViewController.swift in Sources */, 4A9B81E42921AE03007A05D1 /* ContextManager.swift in Sources */, - FABB24BE2602FC2C00C8785C /* ReaderTabView.swift in Sources */, F49B9A08293A21F4000CEFCE /* MigrationEvent.swift in Sources */, FABB24BF2602FC2C00C8785C /* EpilogueUserInfoCell.swift in Sources */, F4EDAA4D29A516EA00622D3D /* ReaderPostService.swift in Sources */, diff --git a/WordPress/WordPressTest/ReaderTabItemsStoreTests.swift b/WordPress/WordPressTest/ReaderTabItemsStoreTests.swift deleted file mode 100644 index d66aecf9e58d..000000000000 --- a/WordPress/WordPressTest/ReaderTabItemsStoreTests.swift +++ /dev/null @@ -1,88 +0,0 @@ -@testable import WordPress -import XCTest -import WordPressFlux -import CoreData - -class MockTopicService: ReaderTopicService { - - var success = true - var fetchReaderMenuExpectation: XCTestExpectation? - var fetchMenuSuccessExpectation: XCTestExpectation? - var fetchMenuFailureExpectation: XCTestExpectation? - var failureError: Error? - - override func fetchReaderMenu(success: (() -> Void)!, failure: ((Error?) -> Void)!) { - fetchReaderMenuExpectation?.fulfill() - - guard self.success else { - fetchMenuFailureExpectation?.fulfill() - failure(failureError) - return - } - fetchMenuSuccessExpectation?.fulfill() - success() - } -} - -class ReaderTabItemsStoreTests: CoreDataTestCase { - - private var subscription: Receipt? - private var store: ReaderTabItemsStore! - private var service: MockTopicService! - - private let mockError = NSError(domain: "mockContextDomain", code: -1, userInfo: nil) - - override func setUp() { - service = MockTopicService(coreDataStack: contextManager) - store = ReaderTabItemsStore(context: mainContext, service: service) - } - - override func tearDown() { - service = nil - subscription = nil - store = nil - } - - /// get items succeeds - func testGetItemsSuccess() { - // Given - - let stateChangeExpectation = expectation(description: "state change emitted") - stateChangeExpectation.expectedFulfillmentCount = 2 - - subscription = store.onChange { - stateChangeExpectation.fulfill() - } - // When - store.getItems() - // Then - waitForExpectations(timeout: 4) { error in - if let error = error { - XCTFail("waitForExpectationsWithTimeout errored: \(error)") - } - } - } - - /// remote service fetch fails - fetch local items - func testGetLocalItemsOnRemoteServiceFailure() { - // Given - service.success = false - service.fetchReaderMenuExpectation = expectation(description: "fetch menu items executed") - service.fetchMenuFailureExpectation = expectation(description: "fetch from remote service failed") - - let stateChangeExpectation = expectation(description: "state change emitted") - stateChangeExpectation.expectedFulfillmentCount = 2 - - subscription = store.onChange { - stateChangeExpectation.fulfill() - } - // When - store.getItems() - // Then - waitForExpectations(timeout: 4) { error in - if let error = error { - XCTFail("waitForExpectationsWithTimeout errored: \(error)") - } - } - } -} diff --git a/WordPress/WordPressTest/ReaderTabViewModelTests.swift b/WordPress/WordPressTest/ReaderTabViewModelTests.swift deleted file mode 100644 index 39eafec9670e..000000000000 --- a/WordPress/WordPressTest/ReaderTabViewModelTests.swift +++ /dev/null @@ -1,219 +0,0 @@ -@testable import WordPress -import XCTest -import WordPressFlux -import CoreData - -class ReaderTabViewModelTests: CoreDataTestCase { - - var makeContentControllerExpectation: XCTestExpectation? - - var store: MockItemsStore! - var viewModel: ReaderTabViewModel! - var settingsPresenter: MockSettingsPresenter! - - override func setUp() { - store = MockItemsStore() - settingsPresenter = MockSettingsPresenter() - viewModel = ReaderTabViewModel(readerContentFactory: readerContentControllerFactory(_:), - searchNavigationFactory: { }, - tabItemsStore: store, - settingsPresenter: settingsPresenter) - } - - override func tearDown() { - viewModel = nil - store = nil - settingsPresenter = nil - makeContentControllerExpectation = nil - } - - func testRefreshTabBar() { - // Given - let setTabBarItemsExpectation = expectation(description: "tab bar items were set") - store.getItemsExpectation = expectation(description: "Items were fetched") - // When - viewModel.onTabBarItemsDidChange { items, index in - setTabBarItemsExpectation.fulfill() - XCTAssertEqual(index, 0) - XCTAssertEqual(items.map { $0.title }, ["Subscriptions", "Subscriptions"]) - } - // Then - viewModel.fetchReaderMenu() - waitForExpectations(timeout: 4) { error in - if let error = error { - XCTFail("waitForExpectationsWithTimeout errored: \(error)") - } - } - } - - func testPresentManage() { - // Given - settingsPresenter.presentExpectation = expectation(description: "Settings screen was presented") - // When - let controller = UIViewController() - viewModel.presentManage(filter: makeFilterProvider(), from: controller) - // Then - waitForExpectations(timeout: 4) { error in - if let error = error { - XCTFail("waitForExpectationsWithTimeout errored: \(error)") - } - } - } - - func testPresentFilterFromView() { - // Given - let filter = makeFilterProvider() - let filterTappedExpectation = expectation(description: "Filter button was tapped") - viewModel.filterTapped = { filter, view, completion in - filterTappedExpectation.fulfill() - } - - // When - viewModel.didTapStreamFilterButton(with: filter) - // Then - waitForExpectations(timeout: 4) { error in - if let error = error { - XCTFail("waitForExpectationsWithTimeout errored: \(error)") - } - } - } - - func testResetFilter() { - // Given - let selectedTopic = ReaderAbstractTopic(context: mainContext) - selectedTopic.title = "selected topic" - viewModel.tabItems = [ReaderTabItem(ReaderContent(topic: selectedTopic))] - - let setContenttopicExpectation = expectation(description: "content topic was set") - viewModel.setContent = { - setContenttopicExpectation.fulfill() - XCTAssertEqual($0.topic!.title, "selected topic") - } - // When - viewModel.resetStreamFilter() - // Then - waitForExpectations(timeout: 4) { error in - if let error = error { - XCTFail("waitForExpectationsWithTimeout errored: \(error)") - } - } - } - - func testMakeChildContentController() { - // Given - makeContentControllerExpectation = expectation(description: "Content controller was constructed") - - let topic = ReaderAbstractTopic(context: mainContext) - topic.title = "content topic" - let content = ReaderContent(topic: topic) - store.items = [ReaderTabItem(content)] - viewModel.fetchReaderMenu() - // When - let controller = viewModel.makeChildContentViewController(at: 0) - viewModel.setContent?(content) - // Then - XCTAssert(controller is MockContentController) - waitForExpectations(timeout: 4) { error in - if let error = error { - XCTFail("waitForExpectationsWithTimeout errored: \(error)") - } - } - } - - // MARK: Persisted index - - func testPersistedSelectedIndex() { - // Given - let expectedSelectedIndex = 1 - viewModel.selectedIndex = expectedSelectedIndex - let getItemsExpectation = expectation(description: "Items were fetched") - store.getItemsExpectation = getItemsExpectation - - // When - viewModel.onTabBarItemsDidChange { items, index in - XCTAssertEqual(index, expectedSelectedIndex) - } - - // Then - viewModel.fetchReaderMenu() - - wait(for: [getItemsExpectation], timeout: 1) - } - - func testOutOfBoundsSelectedIndex() { - // Given - viewModel.selectedIndex = 99 // invalid, out-of-bounds index - let getItemsExpectation = expectation(description: "Items were fetched") - store.getItemsExpectation = getItemsExpectation - - // When - viewModel.onTabBarItemsDidChange { items, index in - XCTAssertEqual(index, 0) // the index should reset to 0. - } - - // Then - viewModel.fetchReaderMenu() - - wait(for: [getItemsExpectation], timeout: 1) - } -} - -// MARK: - Helpers -extension ReaderTabViewModelTests { - - private func readerContentControllerFactory(_ content: ReaderContent) -> ReaderContentViewController { - makeContentControllerExpectation?.fulfill() - let controller = MockContentController() - controller.setContentExpectation = expectation(description: "Topic was set") - return controller - } - - private func makeFilterProvider() -> FilterProvider { - return FilterProvider(title: { _ in "Test" }, - accessibilityIdentifier: "Test", - cellClass: UITableViewCell.self, - reuseIdentifier: "Cell", - emptyTitle: "Test", - section: .sites) { _, completion in - completion(.success([])) - } - } -} - -// MARK: - Mocks - -class MockItemsStore: ReaderTabItemsStoreProtocol { - let changeDispatcher = Dispatcher() - - var items: [ReaderTabItem] = [ReaderTabItem(ReaderContent(topic: nil, contentType: .saved))] - - var newItems = [ReaderTabItem(ReaderContent(topic: nil, contentType: .selfHostedFollowing)), ReaderTabItem(ReaderContent(topic: nil, contentType: .selfHostedFollowing))] - - var getItemsExpectation: XCTestExpectation? - - func getItems() { - items = newItems - getItemsExpectation?.fulfill() - emitChange() - } -} - -class MockContentController: UIViewController, ReaderContentViewController { - - var setContentExpectation: XCTestExpectation? - - func setContent(_ content: ReaderContent) { - setContentExpectation?.fulfill() - } -} - -class MockSettingsPresenter: ScenePresenter { - - var presentExpectation: XCTestExpectation? - - var presentedViewController: UIViewController? - - func present(on viewController: UIViewController, animated: Bool, completion: (() -> Void)?) { - presentExpectation?.fulfill() - } -} diff --git a/WordPress/WordPressTest/ReaderTabViewTests.swift b/WordPress/WordPressTest/ReaderTabViewTests.swift deleted file mode 100644 index bcc670a76b53..000000000000 --- a/WordPress/WordPressTest/ReaderTabViewTests.swift +++ /dev/null @@ -1,7 +0,0 @@ -@testable import WordPress -import XCTest -import CoreData - -class ReaderTabViewTests: CoreDataTestCase { - -} From a6c4abe8484386dca8278088d2513aec9c69c132 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 12:50:43 -0400 Subject: [PATCH 03/55] Remove ReaderNavigationButton --- .../Utility/Analytics/WPAnalyticsEvent.swift | 10 - .../ReaderNavigationButton.swift | 176 ------------------ WordPress/WordPress.xcodeproj/project.pbxproj | 6 - 3 files changed, 192 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderNavigationButton.swift diff --git a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift index c8e43ad4a768..f3c13a93d528 100644 --- a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift +++ b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift @@ -334,10 +334,6 @@ import Foundation case readerManageViewDisplayed case readerManageViewDismissed - // Reader: Navigation menu dropdown - case readerDropdownOpened - case readerDropdownItemTapped - // Reader: Tags Feed case readerTagsFeedShown case readerTagsFeedMoreFromTagTapped @@ -1224,12 +1220,6 @@ import Foundation case .readerManageViewDismissed: return "reader_manage_view_dismissed" - // Reader: Navigation menu dropdown - case .readerDropdownOpened: - return "reader_dropdown_menu_opened" - case .readerDropdownItemTapped: - return "reader_dropdown_menu_item_tapped" - case .readerTagsFeedShown: return "reader_tags_feed_shown" case .readerTagsFeedMoreFromTagTapped: diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderNavigationButton.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderNavigationButton.swift deleted file mode 100644 index 5f41f81e39ab..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderNavigationButton.swift +++ /dev/null @@ -1,176 +0,0 @@ -import SwiftUI - -struct ReaderNavigationButton: View { - - @ObservedObject var viewModel: ReaderTabViewModel - - var body: some View { - Menu { - ForEach(menuItemGroups, id: \.self) { group in - Section { - ForEach(group, id: \.self) { item in - menuButton(for: item) - } - if group == menuItemGroups.last && viewModel.listItems.count > 0 { - if !RemoteFeatureFlag.readerTagsFeed.enabled() { - Divider() - } - listMenuItem - } - } - } - } label: { - if let selectedItem = viewModel.selectedItem { - menuLabel(for: selectedItem) - } - } - .accessibilityIdentifier("reader-navigation-button") - .buttonStyle(PlainButtonStyle()) - .onTapGesture { - WPAnalytics.track(.readerDropdownOpened) - } - } - - private var menuItemGroups: [[ReaderTabItem]] { - var items: [[ReaderTabItem]] = [[]] - var currentGroup = 0 - for item in viewModel.filterItems { - if item.content.type == .saved || item.content.type == .tags { - currentGroup += 1 - items.append([item]) - continue - } - items[currentGroup].append(item) - } - - return items - } - - @ViewBuilder - private var listMenuItem: some View { - if viewModel.listItems.count > 2 { - Menu { - ForEach(viewModel.listItems, id: \.self) { item in - menuButton(for: item) - } - } label: { - HStack { - Text(Strings.lists) - Spacer() - Image("reader-menu-list") - } - } - } else { - ForEach(viewModel.listItems, id: \.self) { item in - menuButton(for: item) - } - } - } - - private func menuLabel(for item: ReaderTabItem) -> some View { - /// There's a bug/unexpected behavior with how `SwiftUI.Menu`'s label "twitches" when it's animated. - /// Using `ZStack` is a hack to prevent the "container" view from twitching during animation. - ZStack { - // This is used for the background component. - Capsule().fill(Colors.background) - - HStack(spacing: 4.0) { - item.image - .frame(width: 24.0, height: 24.0) - .foregroundColor(Colors.primary) - Text(item.title) - .foregroundStyle(Colors.primary) - .font(.subheadline.weight(.semibold)) - .minimumScaleFactor(0.1) // prevents the text from truncating while in transition. - .frame(minHeight: 24.0) - Image("reader-menu-chevron-down") - .frame(width: 16.0, height: 16.0) - .foregroundColor(Colors.primary) - } - .padding(.vertical, 6.0) - .padding(.leading, item.image == nil ? 16.0 : 8.0) - .padding(.trailing, 12.0) - } - } - - private func menuButton(for item: ReaderTabItem) -> some View { - let index = viewModel.tabItems.firstIndex(of: item) ?? 0 - let eventId = item.dropdownEventId - return Button { - viewModel.showTab(at: index) - WPAnalytics.track(.readerDropdownItemTapped, properties: ["id": eventId]) - } label: { - HStack { - Text(item.title) - Spacer() - item.image - } - } - .accessibilityIdentifier(item.accessibilityIdentifier) - } - - struct Colors { - static let primary: Color = Color(uiColor: .systemBackground) - static let background: Color = Color(uiColor: .label) - } - - struct Strings { - static let lists = NSLocalizedString( - "reader.navigation.menu.lists", - value: "Lists", - comment: "Reader navigation menu item for the lists menu group" - ) - } - -} - -extension ReaderTabItem { - - var image: Image? { - if content.type == .saved { - return Image("reader-menu-saved") - } else if content.type == .tags { - return Image("reader-menu-tags") - } - - switch content.topicType { - case .discover: - return Image("reader-menu-jetpack") - case .following: - return Image("reader-menu-subscriptions") - case .likes: - return Image("reader-menu-star-outline") - default: - return nil - } - } - - var dropdownEventId: String { - if let topic = content.topic as? ReaderTeamTopic, - topic.slug == ReaderTeamTopic.a8cSlug { - return "a8c" - } - - if content.topic is ReaderListTopic { - return "list" - } - - if content.type == .saved { - return "saved" - } else if content.type == .tags { - return "tags" - } - - switch content.topicType { - case .discover: - return "discover" - case .following: - return "following" - case .likes: - return "liked" - default: - return "unknown" - } - } - -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 0344c9cec133..b6c7720a9eed 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2423,8 +2423,6 @@ 834A49D32A0C23A90042ED3D /* TemplatePageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 834A49D12A0C23A90042ED3D /* TemplatePageTableViewCell.swift */; }; 834CE7341256D0DE0046A4A3 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 834CE7331256D0DE0046A4A3 /* CFNetwork.framework */; }; 8350E49611D2C71E00A7B073 /* Media.m in Sources */ = {isa = PBXBuildFile; fileRef = 8350E49511D2C71E00A7B073 /* Media.m */; }; - 8352AC712B2A185A00F8492C /* ReaderNavigationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8352AC702B2A185A00F8492C /* ReaderNavigationButton.swift */; }; - 8352AC722B2A185A00F8492C /* ReaderNavigationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8352AC702B2A185A00F8492C /* ReaderNavigationButton.swift */; }; 8352AC742B2A485100F8492C /* ReaderNavigationMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8352AC732B2A485100F8492C /* ReaderNavigationMenu.swift */; }; 8352AC752B2A485100F8492C /* ReaderNavigationMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8352AC732B2A485100F8492C /* ReaderNavigationMenu.swift */; }; 8355D7D911D260AA00A61362 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8355D7D811D260AA00A61362 /* CoreData.framework */; }; @@ -8000,7 +7998,6 @@ 8350E15911D28B4A00A7B073 /* WordPress.xcdatamodel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wrapper.xcdatamodel; path = WordPress.xcdatamodel; sourceTree = ""; }; 8350E49411D2C71E00A7B073 /* Media.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Media.h; sourceTree = ""; }; 8350E49511D2C71E00A7B073 /* Media.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Media.m; sourceTree = ""; }; - 8352AC702B2A185A00F8492C /* ReaderNavigationButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderNavigationButton.swift; sourceTree = ""; }; 8352AC732B2A485100F8492C /* ReaderNavigationMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderNavigationMenu.swift; sourceTree = ""; }; 8355D67D11D13EAD00A61362 /* MobileCoreServices.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 8355D7D811D260AA00A61362 /* CoreData.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; @@ -11726,7 +11723,6 @@ 3F09CCA62428FE8600D00A8C /* Tab Navigation */ = { isa = PBXGroup; children = ( - 8352AC702B2A185A00F8492C /* ReaderNavigationButton.swift */, 8352AC732B2A485100F8492C /* ReaderNavigationMenu.swift */, 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */, 3FC8D19A244F43B500495820 /* ReaderTabItemsStore.swift */, @@ -22551,7 +22547,6 @@ AB758D9E25EFDF9C00961C0B /* LikesListController.swift in Sources */, E1FD45E01C030B3800750F4C /* AccountSettingsService.swift in Sources */, 8BDC4C39249BA5CA00DE0A2D /* ReaderCSS.swift in Sources */, - 8352AC712B2A185A00F8492C /* ReaderNavigationButton.swift in Sources */, 80EF672527F3D63B0063B138 /* DashboardStatsStackView.swift in Sources */, 0C0F05532C6290670040390D /* ReaderFeedCell.swift in Sources */, 0CDA09032BD022130032D123 /* PostMediaUploadsView.swift in Sources */, @@ -25326,7 +25321,6 @@ 8B55F9DC2614D902007D618E /* CircledIcon.swift in Sources */, FABB23792602FC2C00C8785C /* ChangePasswordViewController.swift in Sources */, 3FE3D1FD26A6F34900F3CD10 /* WPStyleGuide+List.swift in Sources */, - 8352AC722B2A185A00F8492C /* ReaderNavigationButton.swift in Sources */, 175CC17D2723103000622FB4 /* WPAnalytics+Domains.swift in Sources */, FABB237A2602FC2C00C8785C /* LikeComment.swift in Sources */, 0C5A17212C74CFFA00EEF067 /* SidebarProfileView.swift in Sources */, From 5dffc5257ae46fe6c7157833f1aa1830e9dce610 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 12:51:38 -0400 Subject: [PATCH 04/55] Remove ReaderNavigationMenu --- .../Reader/ReaderStreamViewController.swift | 2 - .../Tab Navigation/ReaderNavigationMenu.swift | 167 ------------------ WordPress/WordPress.xcodeproj/project.pbxproj | 6 - 3 files changed, 175 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderNavigationMenu.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index f5f18437b7fc..08ef32e80832 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -43,8 +43,6 @@ import AutomatticTracks return tableViewController.tableView } - weak var navigationMenuDelegate: ReaderNavigationMenuDelegate? - private var syncHelpers: [ReaderAbstractTopic: WPContentSyncHelper] = [:] private var syncHelper: WPContentSyncHelper? { diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderNavigationMenu.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderNavigationMenu.swift deleted file mode 100644 index 318922654539..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderNavigationMenu.swift +++ /dev/null @@ -1,167 +0,0 @@ -import SwiftUI - -protocol ReaderNavigationMenuDelegate: AnyObject { - func scrollViewDidScroll(_ scrollView: UIScrollView, velocity: CGPoint) - func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) - func didTapDiscoverBlogs() - func didScrollToTop() -} - -struct ReaderNavigationMenu: View { - - @ObservedObject var viewModel: ReaderTabViewModel - - private var filters: [FilterProvider] { - if let activeStreamFilter = viewModel.activeStreamFilter, - let activeFilterProvider = viewModel.streamFilters.first(where: { $0.id == activeStreamFilter.filterID }) { - return [activeFilterProvider] - } - - return viewModel.streamFilters - } - - private var filterTitles: [String] { - filters.map { $0.title } - } - - private var hasActiveFilter: Bool { - return viewModel.activeStreamFilter != nil - } - - var body: some View { - HStack(spacing: 0) { - ScrollView(.horizontal, showsIndicators: false) { - HStack { - ReaderNavigationButton(viewModel: viewModel) - .frame(maxHeight: .infinity) - .zIndex(1) - .animation(.easeInOut, value: viewModel.selectedItem) - streamFilterView - // add some empty space so that the last filter chip doesn't get covered by the gradient mask. - Spacer(minLength: Metrics.gradientMaskWidth) - } - .fixedSize(horizontal: false, vertical: true) - } - .animation(.easeInOut, value: filterTitles) - .mask({ - HStack(spacing: .zero) { - Rectangle().fill(.black) - LinearGradient(gradient: Gradient(colors: [.black, .clear]), - startPoint: .leading, - endPoint: .trailing) - .frame(width: Metrics.gradientMaskWidth) - } - }) - Spacer(minLength: 0) - Button { - viewModel.navigateToSearch() - } label: { - Image(uiImage: .gridicon(.search) - .withRenderingMode(.alwaysTemplate)) - .foregroundStyle(Colors.searchIcon) - .padding(4.0) - } - .accessibilityLabel(Text(Strings.searchFilterAccessibilityLabel)) - } - } - - @ViewBuilder - var streamFilterView: some View { - ForEach(filters) { filter in - streamFilterChip(filter: filter, isSelected: hasActiveFilter) - .transition( - .asymmetric(insertion: .slide, removal: .move(edge: .leading)) - .combined(with: .opacity) - ) - } - } - - @ViewBuilder - func streamFilterChip(filter: FilterProvider, isSelected: Bool) -> some View { - HStack(alignment: .center, spacing: 8.0) { - Button { - viewModel.didTapStreamFilterButton(with: filter) - } label: { - Text(viewModel.activeStreamFilter?.topic.title ?? filter.title) - .font(.subheadline) - .fontWeight(.semibold) - .foregroundStyle(isSelected ? Colors.StreamFilter.selectedText : Colors.StreamFilter.text) - } - .accessibilityLabel(Text(filterAccessibilityLabel(for: filter))) - .accessibilityHint(Text(isSelected ? Strings.activeFilterAccessibilityHint : String())) - - if isSelected { - Button { - withAnimation(.easeInOut) { - viewModel.resetStreamFilter() - } - } label: { - Image("reader-menu-close") - .frame(width: 24.0, height: 24.0) - .foregroundStyle(Colors.StreamFilter.selectedText) - } - .accessibilityLabel(Text(Strings.resetFilterAccessibilityLabel)) - } - } - .padding(.vertical, 6.0) - .padding(.leading, 16.0) - .padding(.trailing, isSelected ? 8.0 : 16.0) - .frame(maxHeight: .infinity) - .background(isSelected ? Colors.StreamFilter.selectedBackground : Colors.StreamFilter.background) - .clipShape(Capsule()) - } - - private func filterAccessibilityLabel(for filter: FilterProvider) -> String { - guard let activeFilter = viewModel.activeStreamFilter else { - return filter.title - } - return String(format: Strings.activeFilterAccessibilityStringFormat, activeFilter.topic.title) - } - - struct Metrics { - static let gradientMaskWidth: CGFloat = 16.0 - } - - struct Colors { - static let searchIcon: Color = Color(uiColor: .label) - - struct StreamFilter { - static let text = Color.primary - static let background = Color(uiColor: .init(light: .secondarySystemBackground, dark: .tertiarySystemBackground)) - static let selectedText = Color(uiColor: .systemBackground) - static let selectedBackground = Color.primary - } - } - - struct Strings { - static let activeFilterAccessibilityStringFormat = NSLocalizedString( - "reader.navigation.menu.activeFilter.a11y.label", - value: "Filtered by %1$@", - comment: """ - Accessibility label for when the user has an active filter. - This informs the user that the currently displayed stream is being filtered. - """ - ) - - static let activeFilterAccessibilityHint = NSLocalizedString( - "reader.navigation.menu.filter.a11y.hint", - value: "Opens the filter list", - comment: """ - Accessibility hint that informs the user that the filter list will be opened when they interact - with the filter chip button. - """ - ) - - static let resetFilterAccessibilityLabel = NSLocalizedString( - "reader.navigation.menu.reset.a11y.label", - value: "Reset", - comment: "Accessibility label for the Close icon button, to reset the active filter." - ) - - static let searchFilterAccessibilityLabel = NSLocalizedString( - "reader.navigation.menu.search.a11y.label", - value: "Search", - comment: "Accessibility label for the Search icon." - ) - } -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index b6c7720a9eed..5b6060183529 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2423,8 +2423,6 @@ 834A49D32A0C23A90042ED3D /* TemplatePageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 834A49D12A0C23A90042ED3D /* TemplatePageTableViewCell.swift */; }; 834CE7341256D0DE0046A4A3 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 834CE7331256D0DE0046A4A3 /* CFNetwork.framework */; }; 8350E49611D2C71E00A7B073 /* Media.m in Sources */ = {isa = PBXBuildFile; fileRef = 8350E49511D2C71E00A7B073 /* Media.m */; }; - 8352AC742B2A485100F8492C /* ReaderNavigationMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8352AC732B2A485100F8492C /* ReaderNavigationMenu.swift */; }; - 8352AC752B2A485100F8492C /* ReaderNavigationMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8352AC732B2A485100F8492C /* ReaderNavigationMenu.swift */; }; 8355D7D911D260AA00A61362 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8355D7D811D260AA00A61362 /* CoreData.framework */; }; 835771352A7C2755006B2A3E /* JetpackSocialNoSharesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835771342A7C2755006B2A3E /* JetpackSocialNoSharesView.swift */; }; 835771362A7C2755006B2A3E /* JetpackSocialNoSharesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835771342A7C2755006B2A3E /* JetpackSocialNoSharesView.swift */; }; @@ -7998,7 +7996,6 @@ 8350E15911D28B4A00A7B073 /* WordPress.xcdatamodel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wrapper.xcdatamodel; path = WordPress.xcdatamodel; sourceTree = ""; }; 8350E49411D2C71E00A7B073 /* Media.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Media.h; sourceTree = ""; }; 8350E49511D2C71E00A7B073 /* Media.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Media.m; sourceTree = ""; }; - 8352AC732B2A485100F8492C /* ReaderNavigationMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderNavigationMenu.swift; sourceTree = ""; }; 8355D67D11D13EAD00A61362 /* MobileCoreServices.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 8355D7D811D260AA00A61362 /* CoreData.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 835771342A7C2755006B2A3E /* JetpackSocialNoSharesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackSocialNoSharesView.swift; sourceTree = ""; }; @@ -11723,7 +11720,6 @@ 3F09CCA62428FE8600D00A8C /* Tab Navigation */ = { isa = PBXGroup; children = ( - 8352AC732B2A485100F8492C /* ReaderNavigationMenu.swift */, 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */, 3FC8D19A244F43B500495820 /* ReaderTabItemsStore.swift */, 3F09CCA72428FF3300D00A8C /* ReaderTabViewController.swift */, @@ -23193,7 +23189,6 @@ 5D1181E71B4D6DEB003F3084 /* WPStyleGuide+Reader.swift in Sources */, 3250490724F988220036B47F /* Interpolation.swift in Sources */, 83F76F312BC9DEC400C4F2A1 /* ReaderPost+Display.swift in Sources */, - 8352AC742B2A485100F8492C /* ReaderNavigationMenu.swift in Sources */, 0CB424F62AE0416D0080B807 /* SolidColorActivityIndicator.swift in Sources */, 0C8FC9A12A8BC8630059DCE4 /* PHPickerController+Extensions.swift in Sources */, E17FEAD8221490F7006E1D2D /* PostEditorAnalyticsSession.swift in Sources */, @@ -24741,7 +24736,6 @@ 8BF1C81B27BC00AF00F1C203 /* BlogDashboardCardFrameView.swift in Sources */, FABB21D92602FC2C00C8785C /* SearchIdentifierGenerator.swift in Sources */, FABB21DA2602FC2C00C8785C /* StatsTwoColumnRow.swift in Sources */, - 8352AC752B2A485100F8492C /* ReaderNavigationMenu.swift in Sources */, 982DDF91263238A6002B3904 /* LikeUser+CoreDataClass.swift in Sources */, FABB21DD2602FC2C00C8785C /* NSAttributedString+StyledHTML.swift in Sources */, FABB21DE2602FC2C00C8785C /* Accessible.swift in Sources */, From 827eee6f6b4d541e320c083d6764c97299f143db Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 12:53:49 -0400 Subject: [PATCH 05/55] Remove WPScrollableViewController (Objective-C) --- .../Classes/Extensions/UINavigationController+Helpers.swift | 6 +++++- WordPress/Classes/System/WordPress-Bridging-Header.h | 1 - .../NotificationsViewController.swift | 2 +- .../Reader/Tab Navigation/ReaderTabViewController.swift | 3 +-- .../Classes/ViewRelated/System/WPScrollableViewController.h | 5 ----- WordPress/Classes/ViewRelated/System/WPTabBarController.m | 1 - WordPress/WordPress.xcodeproj/project.pbxproj | 2 -- 7 files changed, 7 insertions(+), 13 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/System/WPScrollableViewController.h diff --git a/WordPress/Classes/Extensions/UINavigationController+Helpers.swift b/WordPress/Classes/Extensions/UINavigationController+Helpers.swift index 02ed47a0509a..bbb1b44fb2c7 100644 --- a/WordPress/Classes/Extensions/UINavigationController+Helpers.swift +++ b/WordPress/Classes/Extensions/UINavigationController+Helpers.swift @@ -4,7 +4,7 @@ extension UINavigationController { @objc func scrollContentToTopAnimated(_ animated: Bool) { guard viewControllers.count == 1 else { return } - if let topViewController = topViewController as? WPScrollableViewController { + if let topViewController = topViewController as? ScrollableViewController { topViewController.scrollViewToTop() } else if let scrollView = topViewController?.view as? UIScrollView { // If the view controller's view is a scrollview @@ -40,3 +40,7 @@ extension UINavigationController { self.pushViewController(viewController, animated: animated) } } + +protocol ScrollableViewController { + func scrollViewToTop() +} diff --git a/WordPress/Classes/System/WordPress-Bridging-Header.h b/WordPress/Classes/System/WordPress-Bridging-Header.h index 5ddb2468354a..4b2beb4c3dfb 100644 --- a/WordPress/Classes/System/WordPress-Bridging-Header.h +++ b/WordPress/Classes/System/WordPress-Bridging-Header.h @@ -88,7 +88,6 @@ #import "WPUploadStatusButton.h" #import "WPError.h" #import "WPImageViewController.h" -#import "WPScrollableViewController.h" #import "WPStyleGuide+Pages.h" #import "WPStyleGuide+WebView.h" #import "WPTableViewHandler.h" diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController/NotificationsViewController.swift b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController/NotificationsViewController.swift index 7254b469f629..73bcabbe794c 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController/NotificationsViewController.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController/NotificationsViewController.swift @@ -1962,7 +1962,7 @@ extension NotificationsViewController: UIViewControllerTransitioningDelegate { // MARK: - Scrolling // -extension NotificationsViewController: WPScrollableViewController { +extension NotificationsViewController: ScrollableViewController { // Used to scroll view to top when tapping on tab bar item when VC is already visible. func scrollViewToTop() { if isViewLoaded { diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift index 43c9ede06538..416579cb528f 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift @@ -163,8 +163,7 @@ extension ReaderTabViewController { } } -// MARK: - WPScrollableViewController conformance -extension ReaderTabViewController: WPScrollableViewController { +extension ReaderTabViewController: ScrollableViewController { /// Scrolls the first child VC to the top if it's a `ReaderStreamViewController`. func scrollViewToTop() { guard let readerStreamVC = children.first as? ReaderStreamViewController else { diff --git a/WordPress/Classes/ViewRelated/System/WPScrollableViewController.h b/WordPress/Classes/ViewRelated/System/WPScrollableViewController.h deleted file mode 100644 index 614a4b43cf09..000000000000 --- a/WordPress/Classes/ViewRelated/System/WPScrollableViewController.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@protocol WPScrollableViewController -- (void)scrollViewToTop; -@end diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController.m b/WordPress/Classes/ViewRelated/System/WPTabBarController.m index ff3b7d25636b..7d053faa1c06 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController.m +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController.m @@ -6,7 +6,6 @@ #import "Blog.h" #import "BlogDetailsViewController.h" -#import "WPScrollableViewController.h" #import "WPAppAnalytics.h" #import "WordPress-Swift.h" diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 5b6060183529..5f2282715497 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -7600,7 +7600,6 @@ 5DB767401588F64D00EBE36C /* postPreview.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = postPreview.html; path = Resources/HTML/postPreview.html; sourceTree = ""; }; 5DBCD9D318F35D7500B32229 /* ReaderTopicService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReaderTopicService.h; sourceTree = ""; }; 5DBCD9D418F35D7500B32229 /* ReaderTopicService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReaderTopicService.m; sourceTree = ""; }; - 5DBFC8AA1A9C0EEF00E00DE4 /* WPScrollableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WPScrollableViewController.h; sourceTree = ""; }; 5DE471B71B4C710E00665C44 /* ReaderPostContentProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ReaderPostContentProvider.h; sourceTree = ""; }; 5DE8A0401912D95B00B2FF59 /* ReaderPostServiceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ReaderPostServiceTest.m; sourceTree = ""; }; 5DED0E161B432E0400431FCD /* SourcePostAttribution.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SourcePostAttribution.h; sourceTree = ""; }; @@ -14693,7 +14692,6 @@ 1746D7761D2165AE00B11D77 /* ForcePopoverPresenter.swift */, E1DD4CCA1CAE41B800C3863E /* PagedViewController.swift */, E1DD4CCC1CAE41C800C3863E /* PagedViewController.xib */, - 5DBFC8AA1A9C0EEF00E00DE4 /* WPScrollableViewController.h */, 310186691A373B01008F7DF6 /* WPTabBarController.h */, 3101866A1A373B01008F7DF6 /* WPTabBarController.m */, 17A28DC2205001A900EA6D9E /* FilterTabBar.swift */, From 6ab2061cef6575541c1e69801c631c379f9bca6b Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:02:11 -0400 Subject: [PATCH 06/55] Remove ReaderTabViewController --- .../Utility/Analytics/WPAnalyticsEvent.swift | 13 -- .../BuildInformation/RemoteFeatureFlag.swift | 7 - .../ReaderTabViewController.swift | 174 ------------------ ...TabBarController+ReaderTabNavigation.swift | 9 - .../CreateButtonCoordinator.swift | 7 +- .../ViewRelated/System/WPTabBarController.m | 5 +- WordPress/WordPress.xcodeproj/project.pbxproj | 6 - 7 files changed, 3 insertions(+), 218 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift diff --git a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift index f3c13a93d528..e934b14726e5 100644 --- a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift +++ b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift @@ -339,11 +339,6 @@ import Foundation case readerTagsFeedMoreFromTagTapped case readerTagsFeedHeaderTapped - // Reader: Floating Button Experiment - case readerFloatingButtonShown - case readerCreateSheetAnswerPromptTapped - case readerCreateSheetPromptHelpTapped - // App Settings case settingsDidChange @@ -1227,14 +1222,6 @@ import Foundation case .readerTagsFeedHeaderTapped: return "reader_tags_feed_header_tapped" - // Reader: Floating Button Experiment - case .readerFloatingButtonShown: - return "reader_create_fab_shown" - case .readerCreateSheetAnswerPromptTapped: - return "my_site_create_sheet_answer_prompt_tapped" - case .readerCreateSheetPromptHelpTapped: - return "my_site_create_sheet_prompt_help_tapped" - // App Settings case .settingsDidChange: return "settings_did_change" diff --git a/WordPress/Classes/Utility/BuildInformation/RemoteFeatureFlag.swift b/WordPress/Classes/Utility/BuildInformation/RemoteFeatureFlag.swift index fbb2123628d2..86547942840c 100644 --- a/WordPress/Classes/Utility/BuildInformation/RemoteFeatureFlag.swift +++ b/WordPress/Classes/Utility/BuildInformation/RemoteFeatureFlag.swift @@ -31,7 +31,6 @@ enum RemoteFeatureFlag: Int, CaseIterable { case readerAnnouncementCard case inAppUpdates case readerTagsFeed - case readerFloatingButton var defaultValue: Bool { switch self { @@ -93,8 +92,6 @@ enum RemoteFeatureFlag: Int, CaseIterable { return false case .readerTagsFeed: return true - case .readerFloatingButton: - return BuildConfiguration.current ~= [.localDeveloper, .a8cBranchTest] } } @@ -159,8 +156,6 @@ enum RemoteFeatureFlag: Int, CaseIterable { return "in_app_updates" case .readerTagsFeed: return "reader_tags_feed" - case .readerFloatingButton: - return "reader_floating_button" } } @@ -224,8 +219,6 @@ enum RemoteFeatureFlag: Int, CaseIterable { return "In-App Updates" case .readerTagsFeed: return "Reader Tags Feed" - case .readerFloatingButton: - return "Reader Floating Button" } } diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift deleted file mode 100644 index 416579cb528f..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift +++ /dev/null @@ -1,174 +0,0 @@ -import UIKit -import Gridicons - -class ReaderTabViewController: UIViewController { - - private let viewModel: ReaderTabViewModel - - private let makeReaderTabView: (ReaderTabViewModel) -> ReaderTabView - - private var createButtonCoordinator: CreateButtonCoordinator? - - private var isFABTracked: Bool = false - - private lazy var readerTabView: ReaderTabView = { [unowned viewModel] in - return makeReaderTabView(viewModel) - }() - - init(viewModel: ReaderTabViewModel, readerTabViewFactory: @escaping (ReaderTabViewModel) -> ReaderTabView) { - self.viewModel = viewModel - self.makeReaderTabView = readerTabViewFactory - super.init(nibName: nil, bundle: nil) - - title = ReaderTabConstants.title - - ReaderCardService.removeAllCards() - - viewModel.filterTapped = { [weak self] (filter, fromView, completion) in - guard let self = self else { - return - } - - self.viewModel.presentFilter(filter: filter, from: self, sourceView: fromView) { [weak self] topic in - self?.dismiss(animated: true, completion: nil) - completion(topic) - } - } - - NotificationCenter.default.addObserver(self, selector: #selector(defaultAccountDidChange(_:)), name: NSNotification.Name.WPAccountDefaultWordPressComAccountChanged, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) - - viewModel.fetchReaderMenu() - } - - required init?(coder: NSCoder) { - fatalError(ReaderTabConstants.storyBoardInitError) - } - - deinit { - NotificationCenter.default.removeObserver(self) - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - ReaderTracker.shared.start(.main) - readerTabView.disableScrollsToTop() - - createFABIfNeeded() - - if AppConfiguration.showsWhatIsNew { - RootViewCoordinator.shared.presentWhatIsNew(on: self) - } - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - navigationController?.setNavigationBarHidden(true, animated: animated) - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - ReaderTracker.shared.stop(.main) - - createButtonCoordinator?.removeCreateButton() - - navigationController?.setNavigationBarHidden(false, animated: animated) - } - - override func loadView() { - view = readerTabView - - navigationItem.largeTitleDisplayMode = .never - navigationController?.navigationBar.prefersLargeTitles = false - } - - @objc func willEnterForeground() { - guard isViewOnScreen() else { - return - } - - ReaderTracker.shared.start(.main) - } - - // MARK: - Reader FAB - - private func createFABIfNeeded() { - // ensure that the button is truly removed before showing a new one. - createButtonCoordinator?.removeCreateButton() - - guard RemoteFeatureFlag.readerFloatingButton.enabled(), - let blog = RootViewCoordinator.sharedPresenter.currentOrLastBlog(), - let window = UIApplication.shared.mainWindow else { - return - } - - createButtonCoordinator = makeCreateButtonCoordinator(for: blog) - createButtonCoordinator?.add(to: window, - trailingAnchor: view.safeAreaLayoutGuide.trailingAnchor, - bottomAnchor: view.safeAreaLayoutGuide.bottomAnchor) - - if !isFABTracked { - // we only need to track this once since it will remain visible everytime Reader is opened - // once a user gets the feature. For clickthrough, refer to `create_sheet_shown` with source: `reader`. - WPAnalytics.track(.readerFloatingButtonShown) - isFABTracked.toggle() - } - - // Should we hide when the onboarding is shown? - createButtonCoordinator?.showCreateButton(for: blog) - } - - private func makeCreateButtonCoordinator(for blog: Blog) -> CreateButtonCoordinator { - let source = "reader" - - let postAction = PostAction(handler: { - let presenter = RootViewCoordinator.sharedPresenter - presenter.showPostEditor() - }, source: source) - - return CreateButtonCoordinator(self, actions: [postAction], source: source, blog: blog) - } -} - -// MARK: - Notifications -extension ReaderTabViewController { - // Ensure that topics and sites are synced when account changes - @objc private func defaultAccountDidChange(_ notification: Foundation.Notification) { - loadView() - } -} - -// MARK: - Constants -extension ReaderTabViewController { - private enum ReaderTabConstants { - static let title = NSLocalizedString("Reader", comment: "The default title of the Reader") - static let settingsButtonIdentifier = "ReaderSettingsButton" - static let settingsButtonAccessibilityLabel = NSLocalizedString( - "reader.navigation.settings.button.label", - value: "Reader Settings", - comment: "Reader settings button accessibility label." - ) - static let searchButtonAccessibilityIdentifier = "ReaderSearchBarButton" - static let searchButtonAccessibilityLabel = NSLocalizedString( - "reader.navigation.search.button.label", - value: "Search", - comment: "Reader search button accessibility label." - ) - static let storyBoardInitError = "Storyboard instantiation not supported" - static let discoverIndex = 0 - static let settingsButtonContentEdgeInsets = UIEdgeInsets(top: 2, left: 0, bottom: 0, right: 0) - } -} - -extension ReaderTabViewController: ScrollableViewController { - /// Scrolls the first child VC to the top if it's a `ReaderStreamViewController`. - func scrollViewToTop() { - guard let readerStreamVC = children.first as? ReaderStreamViewController else { - return - } - readerStreamVC.scrollViewToTop() - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift index a91fbab243a2..6d257e8768f1 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift @@ -5,15 +5,6 @@ protocol ReaderContentViewController: UIViewController { // MARK: - Reader Factory extension WPTabBarController { - @objc func makeReaderTabViewController() -> ReaderTabViewController { - return ReaderTabViewController(viewModel: readerTabViewModel) { [weak self] viewModel in - guard let self else { - return ReaderTabView(viewModel: viewModel) - } - return self.makeReaderTabView(viewModel) - } - } - @objc func makeReaderTabViewModel() -> ReaderTabViewModel { let viewModel = ReaderTabViewModel( readerContentFactory: { content in diff --git a/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift b/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift index 89b344924a59..5e5dc3437a4b 100644 --- a/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift +++ b/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift @@ -46,9 +46,7 @@ import WordPressUI super.init() // Only fetch the prompt if it is actually needed, i.e. on the FAB that has multiple actions. - // Temporarily show the sheet when the FAB is tapped on the Reader tab. - // TODO: (dvdchr) clean up once `readerFloatingButton` is removed. - if actions.count > 1 || source == Strings.readerSource { + if actions.count > 1 { fetchBloggingPrompt() } } @@ -93,8 +91,7 @@ import WordPressUI } // Temporarily show the sheet when the FAB is tapped on the Reader tab. - // TODO: (dvdchr) clean up once `readerFloatingButton` is removed. - if actions.count == 1, source != Strings.readerSource { + if actions.count == 1 { actions.first?.handler() } else { let actionSheetVC = actionSheetController(with: viewController.traitCollection) diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController.m b/WordPress/Classes/ViewRelated/System/WPTabBarController.m index 7d053faa1c06..4e66d68c44b2 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController.m +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController.m @@ -129,12 +129,9 @@ - (UINavigationController *)readerNavigationController if (self.shouldUseStaticScreens) { UIViewController *rootVC = [[MovedToJetpackViewController alloc] initWithSource:MovedToJetpackSourceReader]; _readerNavigationController = [[UINavigationController alloc] initWithRootViewController:rootVC]; - } else if ([Feature enabled:FeatureFlagReaderReset]) { + } else { _readerPresenter = [[ReaderPresenter alloc] init]; _readerNavigationController = [_readerPresenter prepareForTabBarPresentation]; - } else { - UIViewController *rootVC = self.makeReaderTabViewController; - _readerNavigationController = [[UINavigationController alloc] initWithRootViewController:rootVC]; } _readerNavigationController.view.backgroundColor = [UIColor systemBackgroundColor]; diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 5f2282715497..350734440efa 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -1077,7 +1077,6 @@ 37022D931981C19000F322B7 /* VerticallyStackedButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 37022D901981BF9200F322B7 /* VerticallyStackedButton.m */; }; 374CB16215B93C0800DD0EBC /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */; }; 37EAAF4D1A11799A006D6306 /* CircularImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37EAAF4C1A11799A006D6306 /* CircularImageView.swift */; }; - 3F09CCA82428FF3300D00A8C /* ReaderTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F09CCA72428FF3300D00A8C /* ReaderTabViewController.swift */; }; 3F09CCAE24292EFD00D00A8C /* ReaderTabItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */; }; 3F170E242655917400F6F670 /* UIView+SwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F170E232655917400F6F670 /* UIView+SwiftUI.swift */; }; 3F170E252655917400F6F670 /* UIView+SwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F170E232655917400F6F670 /* UIView+SwiftUI.swift */; }; @@ -4418,7 +4417,6 @@ FABB20E52602FC2C00C8785C /* SiteStatsInformation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9874767221963D320080967F /* SiteStatsInformation.swift */; }; FABB20E62602FC2C00C8785C /* TitleSubtitleHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 738B9A4B21B85CF20005062B /* TitleSubtitleHeader.swift */; }; FABB20E82602FC2C00C8785C /* AppAppearance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17C64BD1248E26A200AF09D7 /* AppAppearance.swift */; }; - FABB20E92602FC2C00C8785C /* ReaderTabViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F09CCA72428FF3300D00A8C /* ReaderTabViewController.swift */; }; FABB20EA2602FC2C00C8785C /* ActivityTypeSelectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B1E62D525758AAF009A0F80 /* ActivityTypeSelectorViewController.swift */; }; FABB20EB2602FC2C00C8785C /* ActivityActionsParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E4123CB20F418A500DF8486 /* ActivityActionsParser.swift */; }; FABB20ED2602FC2C00C8785C /* Routes+Me.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17F0E1D920EBDC0A001E9514 /* Routes+Me.swift */; }; @@ -6941,7 +6939,6 @@ 37022D901981BF9200F322B7 /* VerticallyStackedButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VerticallyStackedButton.m; sourceTree = ""; }; 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 37EAAF4C1A11799A006D6306 /* CircularImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircularImageView.swift; sourceTree = ""; }; - 3F09CCA72428FF3300D00A8C /* ReaderTabViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTabViewController.swift; sourceTree = ""; }; 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTabItem.swift; sourceTree = ""; }; 3F170E232655917400F6F670 /* UIView+SwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+SwiftUI.swift"; sourceTree = ""; }; 3F1B66A223A2F54B0075F09E /* ReaderReblogActionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderReblogActionTests.swift; sourceTree = ""; }; @@ -11721,7 +11718,6 @@ children = ( 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */, 3FC8D19A244F43B500495820 /* ReaderTabItemsStore.swift */, - 3F09CCA72428FF3300D00A8C /* ReaderTabViewController.swift */, 3F6975FE242D941E001F1807 /* ReaderTabViewModel.swift */, 3FF1A852242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift */, ); @@ -21470,7 +21466,6 @@ 738B9A5821B85CF20005062B /* TitleSubtitleHeader.swift in Sources */, FA70024C29DC3B5500E874FD /* DashboardActivityLogCardCell.swift in Sources */, 17C64BD2248E26A200AF09D7 /* AppAppearance.swift in Sources */, - 3F09CCA82428FF3300D00A8C /* ReaderTabViewController.swift in Sources */, 8B1E62D625758AAF009A0F80 /* ActivityTypeSelectorViewController.swift in Sources */, 7E4123CC20F418A500DF8486 /* ActivityActionsParser.swift in Sources */, FAB37D4627ED84BC00CA993C /* DashboardStatsNudgeView.swift in Sources */, @@ -24391,7 +24386,6 @@ FE7B9A8B2A6BD20200488791 /* PrepublishingSocialAccountsTableFooterView.swift in Sources */, FABB20E62602FC2C00C8785C /* TitleSubtitleHeader.swift in Sources */, FABB20E82602FC2C00C8785C /* AppAppearance.swift in Sources */, - FABB20E92602FC2C00C8785C /* ReaderTabViewController.swift in Sources */, FE4DC5A8293A84E6008F322F /* MigrationDeepLinkRouter.swift in Sources */, 77DFF0892B68386800FA561D /* BooleanUserDefaultsDebugViewModel.swift in Sources */, 80DB57992AF99E0900C728FF /* BlogListConfiguration.swift in Sources */, From 6767f45f29b71928ce2b3e6e107b4311f7c7b094 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:09:48 -0400 Subject: [PATCH 07/55] Remove ReaderTabViewModel --- .../Classes/System/WordPressAppDelegate.swift | 10 + .../Utility/Analytics/WPAnalyticsEvent.swift | 16 - .../Tab Navigation/ReaderTabViewModel.swift | 349 ------------------ ...TabBarController+ReaderTabNavigation.swift | 36 +- .../ViewRelated/System/WPTabBarController.h | 2 - .../ViewRelated/System/WPTabBarController.m | 10 - WordPress/WordPress.xcodeproj/project.pbxproj | 6 - 7 files changed, 16 insertions(+), 413 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewModel.swift diff --git a/WordPress/Classes/System/WordPressAppDelegate.swift b/WordPress/Classes/System/WordPressAppDelegate.swift index b8ce3e0cf642..fd8b8149b149 100644 --- a/WordPress/Classes/System/WordPressAppDelegate.swift +++ b/WordPress/Classes/System/WordPressAppDelegate.swift @@ -683,6 +683,7 @@ extension WordPressAppDelegate { removeNotificationExtensionConfiguration() windowManager.showFullscreenSignIn() stopObservingAppleIDCredentialRevoked() + clearReaderStuff() } toggleExtraDebuggingIfNeeded() @@ -693,6 +694,15 @@ extension WordPressAppDelegate { @objc fileprivate func handleLowMemoryWarningNotification(_ notification: NSNotification) { WPAnalytics.track(.lowMemoryWarning) } + + private func clearReaderStuff() { + ReaderPostService(coreDataStack: ContextManager.shared).deletePostsWithNoTopic() + ReaderTopicService(coreDataStack: ContextManager.shared).deleteAllTopics() + ReaderPostService(coreDataStack: ContextManager.shared).clearInUseFlags() + ReaderTopicService(coreDataStack: ContextManager.shared).clearInUseFlags() + ReaderPostService(coreDataStack: ContextManager.shared).clearSavedPostFlags() + ReaderSearchSuggestionService(coreDataStack: ContextManager.sharedInstance()).deleteAllSuggestions() + } } // MARK: - Extensions diff --git a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift index e934b14726e5..6cf5712b08cc 100644 --- a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift +++ b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift @@ -324,12 +324,6 @@ import Foundation case readerDiscoverChannelSelected case readerDiscoverEditInterestsTapped - // Reader: Filter Sheet - case readerFilterSheetDisplayed - case readerFilterSheetDismissed - case readerFilterSheetItemSelected - case readerFilterSheetCleared - // Reader: Manage case readerManageViewDisplayed case readerManageViewDismissed @@ -1199,16 +1193,6 @@ import Foundation case .readerDiscoverEditInterestsTapped: return "reader_discover_edit_interests_tapped" - // Reader: Filter Sheet - case .readerFilterSheetDisplayed: - return "reader_filter_sheet_displayed" - case .readerFilterSheetDismissed: - return "reader_filter_sheet_dismissed" - case .readerFilterSheetItemSelected: - return "reader_filter_sheet_item_selected" - case .readerFilterSheetCleared: - return "reader_filter_sheet_cleared" - // Reader: Manage View case .readerManageViewDisplayed: return "reader_manage_view_displayed" diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewModel.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewModel.swift deleted file mode 100644 index b3cd00903429..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewModel.swift +++ /dev/null @@ -1,349 +0,0 @@ -import WordPressFlux -import WordPressUI -import Combine - -@objc class ReaderTabViewModel: NSObject, ObservableObject { - - // MARK: - Properties - /// tab bar items - private let tabItemsStore: ReaderTabItemsStoreProtocol - private var subscription: Receipt? - private let persistentRepository: UserPersistentRepository - private var onTabBarItemsDidChange: [(([ReaderTabItem], Int) -> Void)] = [] - - var tabItems: [ReaderTabItem] = [] { - didSet { - filterItems = tabItems.filter { !($0.content.topic is ReaderListTopic) } - listItems = tabItems.filter { $0.content.topic is ReaderListTopic } - } - } - - @Published var filterItems: [ReaderTabItem] = [] - @Published var listItems: [ReaderTabItem] = [] - - /// completion handler for an external call that changes the tab index - var didSelectIndex: ((Int) -> Void)? - var selectedIndex = 0 - var selectedItem: ReaderTabItem? { - tabItems[safe: selectedIndex] - } - - var lastVisitedIndex: Int { - persistentRepository.integer(forKey: Constants.lastVisitedStreamIndexKey) - } - - /// completion handler for a tap on a tab on the toolbar - var setContent: ((ReaderContent) -> Void)? - - /// Creates an instance of ReaderContentViewController that gets installed in the ContentView - var makeReaderContentViewController: (ReaderContent) -> ReaderContentViewController - - /// if items are loaded - var itemsLoaded: Bool { - return tabItems.count > 0 - } - - /// Completion handler for selecting a filter from the available filter list - var filterTapped: ((FilterProvider, UIView?, @escaping (ReaderAbstractTopic?) -> Void) -> Void)? - - /// search - var navigateToSearch: () -> Void - - /// Settings - private let settingsPresenter: ScenePresenter - - private var receipts = [Receipt]() - - /// The available filters for the current stream. - @Published var streamFilters = [FilterProvider]() { - didSet { - // clear the receipts each time we replace these with new filters. - receipts = [] - - // refresh the filter list immediately upon update. - streamFilters.forEach { [weak self] filter in - filter.refresh() - - // listen to internal filter changes so that we can "force" the view model - // to push changes down to the SwiftUI view. This is to ensure that the strings - // are up-to-date (e.g., after subscribing to new blogs or tags from the manage flow.) - self?.receipts.append(filter.onChange { - self?.objectWillChange.send() - }) - } - } - } - - /// The active stream filter for the stream. - /// - /// The `FilterProvider`'s ID is stored to identify where the `ReaderAbstractTopic` is coming from. - /// When this property is nil, it means the stream is in an unfiltered state. - @Published var activeStreamFilter: (filterID: FilterProvider.ID, topic: ReaderAbstractTopic)? - - init(readerContentFactory: @escaping (ReaderContent) -> ReaderContentViewController, - searchNavigationFactory: @escaping () -> Void, - tabItemsStore: ReaderTabItemsStoreProtocol, - settingsPresenter: ScenePresenter, - persistentRepository: UserPersistentRepository = UserPersistentStoreFactory.instance()) { - self.makeReaderContentViewController = readerContentFactory - self.navigateToSearch = searchNavigationFactory - self.tabItemsStore = tabItemsStore - self.settingsPresenter = settingsPresenter - self.persistentRepository = persistentRepository - super.init() - - // show the last visited index as default. - selectedIndex = lastVisitedIndex - - subscription = tabItemsStore.onChange { [weak self] in - guard let self else { - return - } - if self.tabItems != self.tabItemsStore.items { - self.tabItems = self.tabItemsStore.items - self.reloadStreamFilters() - } - - // reset if the selectedIndex is out of bounds to avoid showing a blank screen. - if self.selectedIndex >= self.tabItems.count { - self.selectedIndex = 0 - } - - self.onTabBarItemsDidChange.forEach { $0(self.tabItemsStore.items, self.selectedIndex) } - } - addNotificationsObservers() - observeNetworkStatus() - } -} - -// MARK: - Tab bar items -extension ReaderTabViewModel { - - func onTabBarItemsDidChange(completion: @escaping ([ReaderTabItem], Int) -> Void) { - onTabBarItemsDidChange.append(completion) - } - - func fetchReaderMenu() { - tabItemsStore.getItems() - } -} - -// MARK: - Tab selection -extension ReaderTabViewModel { - - private enum Constants { - static let lastVisitedStreamIndexKey = "readerLastVisitedStreamIndexDefaultsKey" - } - - func showTab(at index: Int) { - guard index < tabItems.count else { - return - } - selectedIndex = index - - if tabItems[index].content.type == .saved { - setContent?(tabItems[index].content) - } - - // reload filters for the new stream. - reloadStreamFilters() - - // save the last visited index. - persistentRepository.set(index, forKey: Constants.lastVisitedStreamIndexKey) - - didSelectIndex?(index) - } - - /// switch to the tab whose topic matches the given predicate - func switchToTab(where predicate: (ReaderAbstractTopic) -> Bool) { - guard let index = tabItems.firstIndex(where: { item in - guard let topic = item.content.topic else { - return false - } - return predicate(topic) - }) else { - return - } - showTab(at: index) - } - - /// switch to the tab whose title matches the given predicate - func switchToTab(where predicate: (String) -> Bool) { - guard let index = tabItems.firstIndex(where: { - predicate($0.title) - }) else { - return - } - showTab(at: index) - } -} - -// MARK: - Filter -extension ReaderTabViewModel { - - func reloadStreamFilters() { - guard let selectedStream = tabItems[safe: selectedIndex] else { - return - } - - // always reset active stream filters - activeStreamFilter = nil - - // remove stream filters if the current stream does not allow filtering. - if selectedStream.shouldHideStreamFilters { - streamFilters = [] - return - } - - let siteType: SiteOrganizationType = { - if let teamTopic = selectedStream.content.topic as? ReaderTeamTopic { - return teamTopic.organizationType - } - return .none - }() - - var filters = [FilterProvider]() - - if !selectedStream.shouldHideTagFilter { - filters.append(ReaderTagTopic.filterProvider()) - } - - if !selectedStream.shouldHideBlogFilter { - filters.append(ReaderSiteTopic.filterProvider(for: siteType)) - } - - streamFilters = filters - } - - func presentFilter(filter: FilterProvider, - from: UIViewController, - sourceView: UIView?, - completion: @escaping (ReaderAbstractTopic?) -> Void) { - let viewController = makeFilterSheetViewController(filter: filter, completion: completion) - let bottomSheet = BottomSheetViewController(childViewController: viewController) - bottomSheet.additionalSafeAreaInsetsRegular = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0) - bottomSheet.show(from: from, sourceView: sourceView, arrowDirections: .up) - - WPAnalytics.track(.readerFilterSheetDisplayed, properties: ["source": filter.reuseIdentifier]) - } - - func presentManage(filter: FilterProvider, from: UIViewController) { - guard let managePresenter = settingsPresenter as? ReaderManageScenePresenter else { - settingsPresenter.present(on: from, animated: true, completion: nil) - return - } - - managePresenter.present(on: from, selectedSection: filter.section, animated: true, completion: nil) - } - - func didTapStreamFilterButton(with filter: FilterProvider) { - // TODO: @dvdchr Figure out the source rect. - filterTapped?(filter, nil) { [weak self, filterID = filter.id] topic in - guard let topic else { - return - } - self?.setFilterContent(topic: topic) - self?.activeStreamFilter = (filterID, topic) - } - } - - // Reset filter - func resetStreamFilter() { - guard let currentTab = tabItems[safe: selectedIndex] else { - return - } - - let type = activeStreamFilter?.topic is ReaderSiteTopic ? "site" : "topic" - WPAnalytics.track(.readerFilterSheetCleared, properties: ["type": type]) - activeStreamFilter = nil - setContent?(currentTab.content) - } - - func setFilterContent(topic: ReaderAbstractTopic) { - let type = ((topic as? ReaderSiteTopic) != nil) ? "site" : "topic" - WPAnalytics.track(.readerFilterSheetItemSelected, properties: ["type": type]) - - setContent?(ReaderContent(topic: topic)) - } - -} - -// MARK: - Bottom Sheet -extension ReaderTabViewModel { - private func makeFilterSheetViewController(filter: FilterProvider, - completion: @escaping (ReaderAbstractTopic) -> Void) -> FilterSheetViewController { - return FilterSheetViewController(filter: filter, changedFilter: completion) { [weak self] viewController in - self?.presentManage(filter: filter, from: viewController) - } - } -} - -// MARK: - Reader Content -extension ReaderTabViewModel { - - func makeChildContentViewController(at index: Int) -> ReaderContentViewController? { - guard let tabItem = tabItems[safe: index] else { - return tabItems.isEmpty ? makeReaderContentViewController(ReaderContent(topic: nil, contentType: .contentError)) : nil - } - let controller = makeReaderContentViewController(tabItem.content) - - setContent = { [weak controller] configuration in - controller?.setContent(configuration) - } - return controller - } -} - -extension ReaderTabViewModel: NetworkStatusReceiver, NetworkStatusDelegate { - func networkStatusDidChange(active: Bool) { - guard active, tabItems.isEmpty else { - return - } - fetchReaderMenu() - } -} - -// MARK: - Cleanup tasks -extension ReaderTabViewModel { - - private func addNotificationsObservers() { - NotificationCenter.default.addObserver(self, selector: #selector(handleAppTerminationNotification), name: UIApplication.willTerminateNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(handleAccountChangedNotification), name: .WPAccountDefaultWordPressComAccountChanged, object: nil) - } - - @objc private func handleAppTerminationNotification() { - clearTopics(removeAllTopics: false) - clearFlags() - } - - @objc private func handleAccountChangedNotification() { - clearFlags() - clearSavedPosts() - clearTopics(removeAllTopics: true) - clearSearchSuggestions() - selectedIndex = 0 - } - - private func clearFlags() { - ReaderPostService(coreDataStack: ContextManager.shared).clearInUseFlags() - ReaderTopicService(coreDataStack: ContextManager.shared).clearInUseFlags() - } - - private func clearTopics(removeAllTopics removeAll: Bool) { - ReaderPostService(coreDataStack: ContextManager.shared).deletePostsWithNoTopic() - - if removeAll { - ReaderTopicService(coreDataStack: ContextManager.shared).deleteAllTopics() - } else { - ReaderTopicService(coreDataStack: ContextManager.shared).deleteNonMenuTopics() - } - } - - private func clearSavedPosts() { - ReaderPostService(coreDataStack: ContextManager.shared).clearSavedPostFlags() - } - - private func clearSearchSuggestions() { - ReaderSearchSuggestionService(coreDataStack: ContextManager.sharedInstance()).deleteAllSuggestions() - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift index 6d257e8768f1..0de7988c1b40 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift @@ -3,33 +3,6 @@ protocol ReaderContentViewController: UIViewController { func setContent(_ content: ReaderContent) } -// MARK: - Reader Factory -extension WPTabBarController { - @objc func makeReaderTabViewModel() -> ReaderTabViewModel { - let viewModel = ReaderTabViewModel( - readerContentFactory: { content in - if content.topicType == .discover, let topic = content.topic { - return ReaderDiscoverViewController(topic: topic) - } else if let topic = content.topic { - return ReaderStreamViewController.controllerWithTopic(topic) - } else { - return ReaderStreamViewController.controllerForContentType(content.type) - } - }, - searchNavigationFactory: { [weak self] in - self?.showReader(path: .search) - }, - tabItemsStore: ReaderTabItemsStore(), - settingsPresenter: ReaderManageScenePresenter() - ) - return viewModel - } - - private func makeReaderTabView(_ viewModel: ReaderTabViewModel) -> ReaderTabView { - return ReaderTabView(viewModel: self.readerTabViewModel) - } -} - // MARK: - Reader Navigation extension WPTabBarController { func showReader(path: ReaderNavigationPath?) { @@ -42,11 +15,14 @@ extension WPTabBarController { private func navigate(to path: ReaderNavigationPath) { switch path { case .recent: - readerTabViewModel.switchToTab(where: ReaderHelpers.topicIsFollowing) + // TODO: (reader) implement + break case .discover: - readerTabViewModel.switchToTab(where: ReaderHelpers.topicIsDiscover) + // TODO: (reader) implement + break case .likes: - readerTabViewModel.switchToTab(where: ReaderHelpers.topicIsLiked) + // TODO: (reader) implement + break case .search: showReaderDetails(ReaderSearchViewController.controller()) case .subscriptions: diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController.h b/WordPress/Classes/ViewRelated/System/WPTabBarController.h index 4c8497a360c9..ee20f6a3ba16 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController.h +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController.h @@ -15,7 +15,6 @@ extern NSNotificationName const WPTabBarHeightChangedNotification; @class MeViewController; @class MySitesCoordinator; @class NotificationsViewController; -@class ReaderTabViewModel; @protocol ScenePresenter; @interface WPTabBarController : UITabBarController @@ -25,7 +24,6 @@ extern NSNotificationName const WPTabBarHeightChangedNotification; @property (nonatomic, strong, readonly, nonnull) MeViewController *meViewController; @property (nonatomic, strong, readonly, nonnull) UINavigationController *meNavigationController; @property (nonatomic, strong, readonly, nonnull) MySitesCoordinator *mySitesCoordinator; -@property (nonatomic, strong, readonly) ReaderTabViewModel *readerTabViewModel; @property (nonatomic, assign) BOOL shouldUseStaticScreens; - (instancetype)initWithStaticScreens:(BOOL)shouldUseStaticScreens; diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController.m b/WordPress/Classes/ViewRelated/System/WPTabBarController.m index 4e66d68c44b2..e15030e1b758 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController.m +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController.m @@ -41,8 +41,6 @@ @interface WPTabBarController () @property (nonatomic, strong) MeViewController *meViewController; @property (nonatomic, strong) UINavigationController *meNavigationController; -@property (nonatomic, strong) ReaderTabViewModel *readerTabViewModel; - @property (nonatomic, strong, nullable) MySitesCoordinator *mySitesCoordinator; @property (nonatomic, strong, nullable) ReaderPresenter *readerPresenter; @@ -204,14 +202,6 @@ - (UIEdgeInsets)tabBarIconImageInsets return UIEdgeInsetsMake(offset, 0, -offset, 0); } -- (ReaderTabViewModel *)readerTabViewModel -{ - if (!_readerTabViewModel) { - _readerTabViewModel = [self makeReaderTabViewModel]; - } - return _readerTabViewModel; -} - - (void)reloadTabs { _readerPresenter = nil; diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 350734440efa..30f61ec0e834 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -1126,7 +1126,6 @@ 3F5C865D25C9EBEF00BABE64 /* HomeWidgetAllTimeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F5C861925C9EA2500BABE64 /* HomeWidgetAllTimeData.swift */; }; 3F662C4A24DC9FAC00CAEA95 /* WhatIsNewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F662C4924DC9FAC00CAEA95 /* WhatIsNewViewController.swift */; }; 3F685B6A26D431FA001C6808 /* DomainSuggestionViewControllerWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FAF9CC426D03C7400268EA2 /* DomainSuggestionViewControllerWrapper.swift */; }; - 3F6975FF242D941E001F1807 /* ReaderTabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F6975FE242D941E001F1807 /* ReaderTabViewModel.swift */; }; 3F6A7E92251BC1DC005B6A61 /* RootViewCoordinator+WhatIsNew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F6A7E91251BC1DC005B6A61 /* RootViewCoordinator+WhatIsNew.swift */; }; 3F6AD0562502A91400080F3B /* AnnouncementsCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F6AD0552502A91400080F3B /* AnnouncementsCache.swift */; }; 3F6DA04125646F96002AB88F /* HomeWidgetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F6DA04025646F96002AB88F /* HomeWidgetData.swift */; }; @@ -5148,7 +5147,6 @@ FABB24712602FC2C00C8785C /* CollapsableHeaderFilterBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 469EB16724D9AD8B00C764CB /* CollapsableHeaderFilterBar.swift */; }; FABB24722602FC2C00C8785C /* AutomatedTransferHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40247E012120FE3600AE1C3C /* AutomatedTransferHelper.swift */; }; FABB24732602FC2C00C8785C /* PostTagService.m in Sources */ = {isa = PBXBuildFile; fileRef = 082AB9D81C4EEEF4000CA523 /* PostTagService.m */; }; - FABB24742602FC2C00C8785C /* ReaderTabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F6975FE242D941E001F1807 /* ReaderTabViewModel.swift */; }; FABB24752602FC2C00C8785C /* ReaderSearchSuggestionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E62079E01CF7A61200F5CD46 /* ReaderSearchSuggestionService.swift */; }; FABB24762602FC2C00C8785C /* RootViewCoordinator+WhatIsNew.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F6A7E91251BC1DC005B6A61 /* RootViewCoordinator+WhatIsNew.swift */; }; FABB24772602FC2C00C8785C /* CachedAnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF8A04DF1D9BFE7400523BC4 /* CachedAnimatedImageView.swift */; }; @@ -6987,7 +6985,6 @@ 3F5C86BF25CA197500BABE64 /* HomeWidgetAllTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeWidgetAllTime.swift; sourceTree = ""; }; 3F63B93B258179D100F581BE /* StatsWidgetEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsWidgetEntry.swift; sourceTree = ""; }; 3F662C4924DC9FAC00CAEA95 /* WhatIsNewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhatIsNewViewController.swift; sourceTree = ""; }; - 3F6975FE242D941E001F1807 /* ReaderTabViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTabViewModel.swift; sourceTree = ""; }; 3F6A7E91251BC1DC005B6A61 /* RootViewCoordinator+WhatIsNew.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RootViewCoordinator+WhatIsNew.swift"; sourceTree = ""; }; 3F6AD0552502A91400080F3B /* AnnouncementsCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementsCache.swift; sourceTree = ""; }; 3F6DA04025646F96002AB88F /* HomeWidgetData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeWidgetData.swift; sourceTree = ""; }; @@ -11718,7 +11715,6 @@ children = ( 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */, 3FC8D19A244F43B500495820 /* ReaderTabItemsStore.swift */, - 3F6975FE242D941E001F1807 /* ReaderTabViewModel.swift */, 3FF1A852242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift */, ); path = "Tab Navigation"; @@ -22704,7 +22700,6 @@ 8BF281FC27CEB69C00AF8CF3 /* DashboardFailureCardCell.swift in Sources */, 017C57BB2B2B5555001E7687 /* DomainSelectionViewController.swift in Sources */, 082AB9D91C4EEEF4000CA523 /* PostTagService.m in Sources */, - 3F6975FF242D941E001F1807 /* ReaderTabViewModel.swift in Sources */, E62079E11CF7A61200F5CD46 /* ReaderSearchSuggestionService.swift in Sources */, 3F6A7E92251BC1DC005B6A61 /* RootViewCoordinator+WhatIsNew.swift in Sources */, 3FAE0652287C8FC500F46508 /* JPScrollViewDelegate.swift in Sources */, @@ -25654,7 +25649,6 @@ 0C9A79022CB9724A0092D80E /* ReaderPostCellViewModel.swift in Sources */, FABB24732602FC2C00C8785C /* PostTagService.m in Sources */, DC772AF4282009BA00664C02 /* StatsLineChartConfiguration.swift in Sources */, - FABB24742602FC2C00C8785C /* ReaderTabViewModel.swift in Sources */, FADFBD27265F580500039C41 /* MultilineButton.swift in Sources */, FABB24752602FC2C00C8785C /* ReaderSearchSuggestionService.swift in Sources */, FABB24762602FC2C00C8785C /* RootViewCoordinator+WhatIsNew.swift in Sources */, From 52853c249ba3acf9f1c947e676c171010f74ef12 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:16:18 -0400 Subject: [PATCH 08/55] Remove ReaderTagCardCell --- .../Utility/Analytics/WPAnalyticsEvent.swift | 12 -- .../Utility/App Configuration/AppColor.swift | 3 - .../BuildInformation/RemoteFeatureFlag.swift | 7 - .../Reader/ReaderStreamViewController.swift | 29 +-- .../Reader/ReaderTableConfiguration.swift | 13 -- .../Reader/ReaderTagCardCell.swift | 202 ------------------ .../ViewRelated/Reader/ReaderTagCardCell.xib | 68 ------ .../Reader/Tab Navigation/ReaderTabItem.swift | 1 - WordPress/WordPress.xcodeproj/project.pbxproj | 12 -- 9 files changed, 3 insertions(+), 344 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderTagCardCell.swift delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderTagCardCell.xib diff --git a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift index 6cf5712b08cc..57c099fcf559 100644 --- a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift +++ b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift @@ -328,11 +328,6 @@ import Foundation case readerManageViewDisplayed case readerManageViewDismissed - // Reader: Tags Feed - case readerTagsFeedShown - case readerTagsFeedMoreFromTagTapped - case readerTagsFeedHeaderTapped - // App Settings case settingsDidChange @@ -1199,13 +1194,6 @@ import Foundation case .readerManageViewDismissed: return "reader_manage_view_dismissed" - case .readerTagsFeedShown: - return "reader_tags_feed_shown" - case .readerTagsFeedMoreFromTagTapped: - return "reader_tags_feed_more_from_tag_tapped" - case .readerTagsFeedHeaderTapped: - return "reader_tags_feed_header_tapped" - // App Settings case .settingsDidChange: return "settings_did_change" diff --git a/WordPress/Classes/Utility/App Configuration/AppColor.swift b/WordPress/Classes/Utility/App Configuration/AppColor.swift index d55f47c19ad4..4d110b912672 100644 --- a/WordPress/Classes/Utility/App Configuration/AppColor.swift +++ b/WordPress/Classes/Utility/App Configuration/AppColor.swift @@ -137,9 +137,6 @@ struct UIAppColor { static let appBarTint = UIColor.systemOrange static let appBarText = UIColor.systemOrange - static let placeholderElement = UIColor(light: .systemGray5, dark: .systemGray4) - static let placeholderElementFaded: UIColor = UIColor(light: .systemGray6, dark: .systemGray5) - static let prologueBackground = UIColor(light: blue(.shade0), dark: .systemBackground) static let switchStyle: SwitchToggleStyle = SwitchToggleStyle(tint: Color(UIAppColor.brand)) diff --git a/WordPress/Classes/Utility/BuildInformation/RemoteFeatureFlag.swift b/WordPress/Classes/Utility/BuildInformation/RemoteFeatureFlag.swift index 86547942840c..803062d4cd10 100644 --- a/WordPress/Classes/Utility/BuildInformation/RemoteFeatureFlag.swift +++ b/WordPress/Classes/Utility/BuildInformation/RemoteFeatureFlag.swift @@ -30,7 +30,6 @@ enum RemoteFeatureFlag: Int, CaseIterable { case readingPreferencesFeedback case readerAnnouncementCard case inAppUpdates - case readerTagsFeed var defaultValue: Bool { switch self { @@ -90,8 +89,6 @@ enum RemoteFeatureFlag: Int, CaseIterable { return AppConfiguration.isJetpack case .inAppUpdates: return false - case .readerTagsFeed: - return true } } @@ -154,8 +151,6 @@ enum RemoteFeatureFlag: Int, CaseIterable { return "reader_announcement_card" case .inAppUpdates: return "in_app_updates" - case .readerTagsFeed: - return "reader_tags_feed" } } @@ -217,8 +212,6 @@ enum RemoteFeatureFlag: Int, CaseIterable { return "Reader Announcement Card" case .inAppUpdates: return "In-App Updates" - case .readerTagsFeed: - return "Reader Tags Feed" } } diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 08ef32e80832..177ee43dd2d8 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -186,9 +186,6 @@ import AutomatticTracks if oldValue != .saved, contentType == .saved { updateContent(synchronize: false) trackSavedListAccessed() - } else if oldValue != .tags, contentType == .tags { - updateContent(synchronize: false) - // TODO: Analytics } showConfirmation = contentType != .saved } @@ -199,7 +196,6 @@ import AutomatticTracks enum StatSource: String { case reader case notif_like_list_user_profile - case tagsFeed = "tags_feed" } var statSource: StatSource = .reader @@ -211,12 +207,6 @@ import AutomatticTracks private var showConfirmation = true - // NOTE: This is currently a workaround for the 'Your Tags' stream use case. - // - // The set object flags each tag in the stream so that we know whether or not we've fetched the remote data for the tag. - // We need to ensure that we only fetch the remote data once per tag to avoid the resultsController from refreshing the table view indefinitely. - private var tagStreamSyncTracker = Set() - lazy var selectInterestsViewController: ReaderSelectInterestsViewController = { let title = NSLocalizedString( "reader.select.tags.title", @@ -368,7 +358,7 @@ import AutomatticTracks return } - if readerTopic != nil || contentType == .saved || contentType == .tags { + if readerTopic != nil || contentType == .saved { // Do not perform a sync since a sync will be executed in viewWillAppear anyway. This // prevents a possible internet connection error being shown twice. updateContent(synchronize: false) @@ -621,8 +611,6 @@ import AutomatticTracks displayNoResultsView() } else if contentType == .saved, content.isEmpty { displayNoResultsView() - } else if contentType == .tags, content.isEmpty { - showSelectInterestsView() } } @@ -926,12 +914,6 @@ import AutomatticTracks return } - if isTagsFeed { - didBumpStats = true - WPAnalytics.trackReader(.readerTagsFeedShown) - return - } - guard let topic = readerTopic, let properties = topicPropertyForStats() else { return @@ -1870,13 +1852,10 @@ extension ReaderStreamViewController { } func hideSelectInterestsView(showLoadingStream: Bool = true) { - let isTagsFeed = contentType == .tags guard selectInterestsViewController.parent != nil else { if shouldForceRefresh { scrollViewToTop() - if !isTagsFeed { - displayLoadingStream() - } + displayLoadingStream() syncIfAppropriate(forceSync: true) shouldForceRefresh = false } @@ -1885,9 +1864,7 @@ extension ReaderStreamViewController { } scrollViewToTop() - if !isTagsFeed { - displayLoadingStream() - } + displayLoadingStream() syncIfAppropriate(forceSync: true) UIView.animate(withDuration: 0.2, animations: { diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift index 2061147b29bc..c0a2cf0aae19 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift @@ -9,8 +9,6 @@ final class ReaderTableConfiguration { private let readerGapMarkerCellReuseIdentifier = "ReaderGapMarkerCellReuseIdentifier" private let readerCrossPostCellNibName = "ReaderCrossPostCell" private let readerCrossPostCellReuseIdentifier = "ReaderCrossPostCellReuseIdentifier" - private let readerTagCardCellNibName = "ReaderTagCardCell" - private let readerTagCardCellReuseIdentifier = "ReaderTagCellReuseIdentifier" private let rowHeight = CGFloat(415.0) @@ -21,7 +19,6 @@ final class ReaderTableConfiguration { setUpBlockerCell(tableView) setUpGapMarkerCell(tableView) setUpCrossPostCell(tableView) - setUpTagCell(tableView) tableView.register(ReaderPostCell.self, forCellReuseIdentifier: readerPostCellReuseIdentifier) } @@ -55,11 +52,6 @@ final class ReaderTableConfiguration { tableView.register(nib, forCellReuseIdentifier: readerCrossPostCellReuseIdentifier) } - private func setUpTagCell(_ tableView: UITableView) { - let nib = UINib(nibName: readerTagCardCellNibName, bundle: nil) - tableView.register(nib, forCellReuseIdentifier: readerTagCardCellReuseIdentifier) - } - func footer() -> PostListFooterView { guard let footer = Bundle.main.loadNibNamed(footerViewNibName, owner: nil, options: nil)?.first as? PostListFooterView else { assertionFailure("Failed to load view from nib named \(footerViewNibName)") @@ -91,9 +83,4 @@ final class ReaderTableConfiguration { func blockedSiteCell(_ tableView: UITableView) -> ReaderBlockedSiteCell { return tableView.dequeueReusableCell(withIdentifier: readerBlockedCellReuseIdentifier) as! ReaderBlockedSiteCell } - - func tagCell(_ tableView: UITableView) -> ReaderTagCardCell { - return tableView.dequeueReusableCell(withIdentifier: readerTagCardCellReuseIdentifier) as! ReaderTagCardCell - } - } diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCell.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCell.swift deleted file mode 100644 index 483e9f244f1d..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCell.swift +++ /dev/null @@ -1,202 +0,0 @@ -import WordPressUI - -class ReaderTagCardCell: UITableViewCell { - - @IBOutlet private weak var tagButton: UIButton! - @IBOutlet private weak var collectionView: UICollectionView! - @IBOutlet private weak var collectionViewHeightConstraint: NSLayoutConstraint! - - // A 'fake' collection view that's displayed over the actual collection view. - // This view will be displaying the loading animation while the cell is in loading state. - // - // We can't call our ghost functions on the actual collection view because it uses a - // diffable data source, which cannot be "hot-swapped". - // See: https://developer.apple.com/documentation/uikit/uicollectionviewdiffabledatasource - private lazy var ghostableCollectionView: UICollectionView = { - let layout = UICollectionViewFlowLayout() - layout.scrollDirection = .horizontal - - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - collectionView.translatesAutoresizingMaskIntoConstraints = false - collectionView.clipsToBounds = false - - let cellNibName = ReaderTagCell.classNameWithoutNamespaces() - let nib = UINib(nibName: cellNibName, bundle: nil) - collectionView.register(nib, forCellWithReuseIdentifier: cellNibName) - - return collectionView - }() - - private var viewModel: ReaderTagCardCellViewModel? - - var cellSize: CGSize { - let isAccessibilityCategory = traitCollection.preferredContentSizeCategory.isAccessibilityCategory - let isPad = traitCollection.userInterfaceIdiom == .pad - - switch (isAccessibilityCategory, isPad) { - case (true, true): - return Constants.padLargeCellSize - case (false, true): - return Constants.padDefaultCellSize - case (true, false): - return Constants.phoneLargeCellSize - case (false, false): - return Constants.phoneDefaultCellSize - } - } - - override func awakeFromNib() { - super.awakeFromNib() - registerCells() - setupButtonStyles() - accessibilityElements = [tagButton, collectionView].compactMap { $0 } - collectionViewHeightConstraint.constant = cellSize.height - - // disable ghost animation on the actual collection view to prevent its data source and delegate - // from being overridden. - collectionView?.isGhostableDisabled = true - } - - override func prepareForReuse() { - super.prepareForReuse() - collectionViewHeightConstraint.constant = cellSize.height - hideGhostLoading() // clean up attached ghost views, if any - } - - func configure(parent: UIViewController, tag: ReaderTagTopic, isLoggedIn: Bool, shouldSyncRemotely: Bool = false) { - if viewModel?.slug == tag.slug { - return - } - resetScrollPosition() - weak var weakSelf = self - viewModel = ReaderTagCardCellViewModel(parent: parent, - tag: tag, - collectionView: collectionView, - isLoggedIn: isLoggedIn, - viewDelegate: self, - cellSize: weakSelf?.cellSize) - viewModel?.fetchTagPosts(syncRemotely: shouldSyncRemotely) - tagButton.setTitle(tag.title, for: .normal) - } - - @IBAction private func onTagButtonTapped(_ sender: Any) { - viewModel?.onTagButtonTapped(source: .header) - } - - struct Constants { - static let phoneDefaultCellSize = CGSize(width: 300, height: 150) - static let phoneLargeCellSize = CGSize(width: 300, height: 300) - static let padDefaultCellSize = CGSize(width: 480, height: 206) - static let padLargeCellSize = CGSize(width: 480, height: 400) - } - -} - -// MARK: - ReaderTagCardCellViewModelDelegate - -extension ReaderTagCardCell: ReaderTagCardCellViewModelDelegate { - func showLoading() { - showGhostLoading() - } - - func hideLoading() { - hideGhostLoading() - } -} - -// MARK: - Private methods - -private extension ReaderTagCardCell { - - func setupButtonStyles() { - var buttonConfig = UIButton.Configuration.filled() - buttonConfig.cornerStyle = .capsule - buttonConfig.baseForegroundColor = .label - buttonConfig.baseBackgroundColor = UIColor(light: .secondarySystemBackground, - dark: .tertiarySystemBackground) - buttonConfig.contentInsets = NSDirectionalEdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16) - let font = WPStyleGuide.fontForTextStyle(.subheadline, fontWeight: .semibold) - buttonConfig.titleTextAttributesTransformer = .transformer(with: font) - tagButton.configuration = buttonConfig - } - - func registerCells() { - let tagCell = UINib(nibName: ReaderTagCell.classNameWithoutNamespaces(), bundle: nil) - let footerView = UINib(nibName: ReaderTagFooterView.classNameWithoutNamespaces(), bundle: nil) - collectionView.register(ReaderTagCardEmptyCell.self, forCellWithReuseIdentifier: ReaderTagCardEmptyCell.defaultReuseID) - collectionView.register(tagCell, forCellWithReuseIdentifier: ReaderTagCell.classNameWithoutNamespaces()) - collectionView.register(footerView, - forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, - withReuseIdentifier: ReaderTagFooterView.classNameWithoutNamespaces()) - } - - /// Injects a "fake" UICollectionView for the loading state animation. - func showGhostLoading() { - guard let collectionView, - let containerView = collectionView.superview, - ghostableCollectionView.superview == nil else { - return - } - - // setup the 'fake' collection view. - containerView.addSubview(ghostableCollectionView) - - // pin it directly over the current collection view. - NSLayoutConstraint.activate([ - ghostableCollectionView.leadingAnchor.constraint(equalTo: collectionView.leadingAnchor), - ghostableCollectionView.trailingAnchor.constraint(equalTo: collectionView.trailingAnchor), - ghostableCollectionView.topAnchor.constraint(equalTo: collectionView.topAnchor), - ghostableCollectionView.bottomAnchor.constraint(equalTo: collectionView.bottomAnchor) - ]) - - // Important: since the size are fixed, we want to make sure that we feed the exact item size - // so that it perfectly overlays on top of the "actual" collection view. - if let flowLayout = ghostableCollectionView.collectionViewLayout as? UICollectionViewFlowLayout { - flowLayout.itemSize = cellSize - } - - let options = GhostOptions(reuseIdentifier: ReaderTagCell.classNameWithoutNamespaces(), rowsPerSection: [3]) - let style = GhostStyle(beatDuration: GhostStyle.Defaults.beatDuration, - beatStartColor: UIAppColor.placeholderElement, - beatEndColor: UIAppColor.placeholderElementFaded) - - ghostableCollectionView.removeGhostContent() - ghostableCollectionView.displayGhostContent(options: options, style: style) - ghostableCollectionView.isScrollEnabled = false - } - - func hideGhostLoading() { - // ensure that the ghostable collection view is present in the view hierarchy. - guard ghostableCollectionView.superview != nil else { - return - } - - ghostableCollectionView.removeGhostContent() - ghostableCollectionView.removeFromSuperview() - } - - func resetScrollPosition() { - let isRTL = UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft - if isRTL { - collectionView.scrollToEnd(animated: false) - } else { - collectionView.scrollToStart(animated: false) - } - } -} - -private extension UIScrollView { - func scrollToEnd(animated: Bool) { - let endOffset = CGPoint(x: contentSize.width - bounds.size.width, y: 0) - if endOffset.x > 0 { - setContentOffset(endOffset, animated: animated) - layoutIfNeeded() - } - } - - func scrollToStart(animated: Bool) { - let startOffset = CGPoint(x: 0, y: 0) - setContentOffset(startOffset, animated: animated) - layoutIfNeeded() - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCell.xib b/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCell.xib deleted file mode 100644 index 6c00eeb63be1..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCell.xib +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift index 132937a073d9..e0c0fdac0fda 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift @@ -81,7 +81,6 @@ enum ReaderContentType { case selfHostedFollowing case contentError case saved - case tags case topic } diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 30f61ec0e834..6fbdb1386fcb 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2403,10 +2403,6 @@ 8320BDE5283D9359009DF2DE /* BlogService+BloggingPrompts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8320BDE4283D9359009DF2DE /* BlogService+BloggingPrompts.swift */; }; 8320BDE6283D9359009DF2DE /* BlogService+BloggingPrompts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8320BDE4283D9359009DF2DE /* BlogService+BloggingPrompts.swift */; }; 8323789928526E6E003F4443 /* AppConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA25F9FD2609AA830005E08F /* AppConfiguration.swift */; }; - 83317ED62BC71BA8001AD2F4 /* ReaderTagCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83317ED52BC71BA8001AD2F4 /* ReaderTagCardCell.swift */; }; - 83317ED72BC71BA8001AD2F4 /* ReaderTagCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83317ED52BC71BA8001AD2F4 /* ReaderTagCardCell.swift */; }; - 83317ED92BC71CEB001AD2F4 /* ReaderTagCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83317ED82BC71CEB001AD2F4 /* ReaderTagCardCell.xib */; }; - 83317EDA2BC71CEB001AD2F4 /* ReaderTagCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83317ED82BC71CEB001AD2F4 /* ReaderTagCardCell.xib */; }; 83317EDC2BC72DB7001AD2F4 /* ReaderTagCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83317EDB2BC72DB7001AD2F4 /* ReaderTagCell.swift */; }; 83317EDD2BC72DB7001AD2F4 /* ReaderTagCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83317EDB2BC72DB7001AD2F4 /* ReaderTagCell.swift */; }; 83317EDF2BC72DED001AD2F4 /* ReaderTagCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83317EDE2BC72DED001AD2F4 /* ReaderTagCell.xib */; }; @@ -7974,8 +7970,6 @@ 8313B9F92995A03C000AF26E /* JetpackRemoteInstallCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackRemoteInstallCardView.swift; sourceTree = ""; }; 83204EDB2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderPostCardCellViewModel.swift; sourceTree = ""; }; 8320BDE4283D9359009DF2DE /* BlogService+BloggingPrompts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BlogService+BloggingPrompts.swift"; sourceTree = ""; }; - 83317ED52BC71BA8001AD2F4 /* ReaderTagCardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTagCardCell.swift; sourceTree = ""; }; - 83317ED82BC71CEB001AD2F4 /* ReaderTagCardCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReaderTagCardCell.xib; sourceTree = ""; }; 83317EDB2BC72DB7001AD2F4 /* ReaderTagCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTagCell.swift; sourceTree = ""; }; 83317EDE2BC72DED001AD2F4 /* ReaderTagCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReaderTagCell.xib; sourceTree = ""; }; 8332D7442ADF263400EB97EF /* UIConfigurationTextAttributesTransformer+Font.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIConfigurationTextAttributesTransformer+Font.swift"; sourceTree = ""; }; @@ -13368,8 +13362,6 @@ 83204EDB2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift */, 3234BB322530EA980068DA40 /* ReaderRecommendedSiteCardCell.swift */, 3234BB332530EA980068DA40 /* ReaderRecommendedSiteCardCell.xib */, - 83317ED52BC71BA8001AD2F4 /* ReaderTagCardCell.swift */, - 83317ED82BC71CEB001AD2F4 /* ReaderTagCardCell.xib */, 83BF48BA2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift */, 83317EDB2BC72DB7001AD2F4 /* ReaderTagCell.swift */, 83317EDE2BC72DED001AD2F4 /* ReaderTagCell.xib */, @@ -20225,7 +20217,6 @@ E61507E42220A13B00213D33 /* richEmbedScript.js in Resources */, 17222D96261DDDF90047B163 /* pink-icon-app-60x60@3x.png in Resources */, 1761F18226209AEE000815EF /* jetpack-green-icon-app-60x60@3x.png in Resources */, - 83317ED92BC71CEB001AD2F4 /* ReaderTagCardCell.xib in Resources */, FE3E83E626A58646008CE851 /* ListSimpleOverlayView.xib in Resources */, B038A81C2BD70FCA00763731 /* StatsSubscribersChartCell.xib in Resources */, 401A3D022027DBD80099A127 /* PluginListCell.xib in Resources */, @@ -20571,7 +20562,6 @@ FABB1FE82602FC2C00C8785C /* TitleBadgeDisclosureCell.xib in Resources */, FABB1FE92602FC2C00C8785C /* TextWithAccessoryButtonCell.xib in Resources */, F465976E28E4669200D5F49A /* cool-green-icon-app-76@2x.png in Resources */, - 83317EDA2BC71CEB001AD2F4 /* ReaderTagCardCell.xib in Resources */, F41E4EC028F22932001880C6 /* spectrum-icon-app-83.5@2x.png in Resources */, FABB1FEA2602FC2C00C8785C /* SiteStatsDetailTableViewController.storyboard in Resources */, FABB1FED2602FC2C00C8785C /* InlineEditableNameValueCell.xib in Resources */, @@ -22729,7 +22719,6 @@ 177076211EA206C000705A4A /* PlayIconView.swift in Sources */, 57BAD50C225CCE1A006139EC /* WPTabBarController+Swift.swift in Sources */, E1468DE71E794A4D0044D80F /* LanguageSelectorViewController.swift in Sources */, - 83317ED62BC71BA8001AD2F4 /* ReaderTagCardCell.swift in Sources */, E14694071F3459E2004052C8 /* PluginListViewController.swift in Sources */, FAD3DE812AE2965A00A3B031 /* AbstractPostMenuHelper.swift in Sources */, 4A26E9952C90EEBF00C1D5DE /* ReaderPresenter.swift in Sources */, @@ -26248,7 +26237,6 @@ FABB26182602FC2C00C8785C /* RegisterDomainDetailsViewModel+SectionDefinitions.swift in Sources */, C395FB272822148400AE7C11 /* RemoteSiteDesign+Thumbnail.swift in Sources */, 0CD382842A4B699E00612173 /* DashboardBlazeCardCellViewModel.swift in Sources */, - 83317ED72BC71BA8001AD2F4 /* ReaderTagCardCell.swift in Sources */, 9815D0B426B49A0600DF7226 /* Comment+CoreDataProperties.swift in Sources */, FABB261A2602FC2C00C8785C /* AppSettingsViewController.swift in Sources */, 4A82C43228D321A300486CFF /* Blog+Post.swift in Sources */, From 7171a5ae8eeb7794390dadbc5851d51d3258e953 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:17:14 -0400 Subject: [PATCH 09/55] Remove ReaderTagCardEmptyCell --- .../Reader/ReaderTagCardCellViewModel.swift | 64 --------- .../Reader/ReaderTagCardEmptyCell.swift | 121 ------------------ WordPress/WordPress.xcodeproj/project.pbxproj | 6 - 3 files changed, 191 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderTagCardEmptyCell.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCellViewModel.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCellViewModel.swift index 518e081d15ca..f5dfc9559437 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCellViewModel.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCellViewModel.swift @@ -203,67 +203,3 @@ private extension ReaderTagCardCellViewModel { return dataSource } } - -// MARK: - NSFetchedResultsControllerDelegate - -extension ReaderTagCardCellViewModel: NSFetchedResultsControllerDelegate { - func controller(_ controller: NSFetchedResultsController, - didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) { - dataSource?.apply(collectionViewSnapshot(from: snapshot), animatingDifferences: false) { [weak self] in - self?.viewDelegate?.hideLoading() - } - } - -} - -// MARK: - UICollectionViewDelegate - -extension ReaderTagCardCellViewModel: UICollectionViewDelegate { - - func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard let section = dataSource?.sectionIdentifier(for: indexPath.section), - section == .posts, - let sectionInfo = resultsController.sections?[safe: indexPath.section], - indexPath.row < sectionInfo.numberOfObjects else { - return - } - let post = resultsController.object(at: indexPath) - let controller = ReaderDetailViewController.controllerWithPost(post) - - WPAnalytics.trackReader(.readerPostCardTapped, - properties: ["source": ReaderStreamViewController.StatSource.tagsFeed.rawValue]) - parentViewController?.navigationController?.pushViewController(controller, animated: true) - } - -} - -// MARK: - UICollectionViewDelegateFlowLayout - -extension ReaderTagCardCellViewModel: UICollectionViewDelegateFlowLayout { - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - guard let section = dataSource?.sectionIdentifier(for: indexPath.section), - let size = cellSize() else { - return .zero - } - - switch section { - case .emptyState: - return CGSize(width: collectionView.frame.width, height: size.height) - case .posts: - return size - } - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { - guard let sectionIdentifier = dataSource?.sectionIdentifier(for: section), - sectionIdentifier == .posts else { - return .zero - } - - var viewSize = cellSize() ?? .zero - viewSize.width = Constants.footerWidth - return viewSize - } - -} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTagCardEmptyCell.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTagCardEmptyCell.swift deleted file mode 100644 index dd82518606e2..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTagCardEmptyCell.swift +++ /dev/null @@ -1,121 +0,0 @@ -import SwiftUI -import DesignSystem - -class ReaderTagCardEmptyCell: UICollectionViewCell, Reusable { - - var tagTitle: String { - get { - swiftUIView.tagTitle - } - set { - swiftUIView.tagTitle = newValue - } - } - - var retryHandler: (() -> Void)? = nil - - private lazy var swiftUIView: ReaderTagCardEmptyCellView = { - ReaderTagCardEmptyCellView(buttonTapped: { [weak self] in - self?.retryHandler?() - }) - }() - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override init(frame: CGRect) { - super.init(frame: .zero) - - let viewToEmbed = UIView.embedSwiftUIView(swiftUIView) - contentView.addSubview(viewToEmbed) - contentView.pinSubviewToAllEdges(viewToEmbed) - } - - override func prepareForReuse() { - tagTitle = String() - retryHandler = nil - super.prepareForReuse() - } - - func configure(tagTitle: String, retryHandler: (() -> Void)?) { - self.tagTitle = tagTitle - self.retryHandler = retryHandler - } -} - -// MARK: - SwiftUI - -private struct ReaderTagCardEmptyCellView: View { - - var tagTitle = String() - var buttonTapped: (() -> Void)? = nil - - @ScaledMetric(relativeTo: Font.TextStyle.callout) - private var iconLength = 32.0 - - var body: some View { - VStack(spacing: .DS.Padding.single) { - Image(systemName: "wifi.slash") - .resizable() - .frame(width: iconLength, height: iconLength) - .foregroundStyle(Color.secondary) - - // added to double the padding between the Image and the VStack. - Spacer().frame(height: .hairlineBorderWidth) - - VStack(spacing: .DS.Padding.half) { - Text(Strings.title) - .font(.callout) - .fontWeight(.semibold) - - Text(Strings.body) - .font(.callout) - .foregroundStyle(.secondary) - .multilineTextAlignment(.center) - .fixedSize(horizontal: false, vertical: true) - } - - Button { - buttonTapped?() - } label: { - Text(Strings.buttonTitle) - .font(.callout) - .padding(.vertical, .DS.Padding.half) - .padding(.horizontal, .DS.Padding.single) - } - } - .padding(.DS.Padding.single) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) - } - - private struct Strings { - static let title = NSLocalizedString( - "reader.tagStream.cards.emptyView.error.title", - value: "Posts failed to load", - comment: """ - The title of an empty state component for one of the tags in the tag stream. - This empty state component is displayed only when the app fails to load posts under this tag. - """ - ) - - static let body = NSLocalizedString( - "reader.tagStream.cards.emptyView.error.body", - value: "We couldn't load posts from this tag right now", - comment: """ - The body text of an empty state component for one of the tags in the tag stream. - This empty state component is displayed only when the app fails to load posts under this tag. - """ - ) - - static let buttonTitle = NSLocalizedString( - "reader.tagStream.cards.emptyView.button", - value: "Retry", - comment: """ - Verb. The button title of an empty state component for one of the tags in the tag stream. - This empty state component is displayed only when the app fails to load posts under this tag. - When tapped, the app will try to reload posts under this tag. - """ - ) - } -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 6fbdb1386fcb..d6d1175a7c9a 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -5616,8 +5616,6 @@ FE23EB4A26E7C91F005A1698 /* richCommentTemplate.html in Resources */ = {isa = PBXBuildFile; fileRef = FE23EB4726E7C91F005A1698 /* richCommentTemplate.html */; }; FE23EB4B26E7C91F005A1698 /* richCommentStyle.css in Resources */ = {isa = PBXBuildFile; fileRef = FE23EB4826E7C91F005A1698 /* richCommentStyle.css */; }; FE23EB4C26E7C91F005A1698 /* richCommentStyle.css in Resources */ = {isa = PBXBuildFile; fileRef = FE23EB4826E7C91F005A1698 /* richCommentStyle.css */; }; - FE2590992BE3F4E2005690E9 /* ReaderTagCardEmptyCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE2590982BE3F4E2005690E9 /* ReaderTagCardEmptyCell.swift */; }; - FE25909A2BE3F4E2005690E9 /* ReaderTagCardEmptyCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE2590982BE3F4E2005690E9 /* ReaderTagCardEmptyCell.swift */; }; FE25C235271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE25C234271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift */; }; FE25C236271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE25C234271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift */; }; FE29EFCD29A91160007CE034 /* WPAdminConvertibleRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE29EFCC29A91160007CE034 /* WPAdminConvertibleRouter.swift */; }; @@ -9730,7 +9728,6 @@ FE1E201D2A49D59400CE7C90 /* JetpackSocialServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackSocialServiceTests.swift; sourceTree = ""; }; FE23EB4726E7C91F005A1698 /* richCommentTemplate.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = richCommentTemplate.html; path = Resources/HTML/richCommentTemplate.html; sourceTree = ""; }; FE23EB4826E7C91F005A1698 /* richCommentStyle.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = richCommentStyle.css; path = Resources/HTML/richCommentStyle.css; sourceTree = ""; }; - FE2590982BE3F4E2005690E9 /* ReaderTagCardEmptyCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTagCardEmptyCell.swift; sourceTree = ""; }; FE25C234271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderCommentsNotificationSheetViewController.swift; sourceTree = ""; }; FE29EFCC29A91160007CE034 /* WPAdminConvertibleRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WPAdminConvertibleRouter.swift; sourceTree = ""; }; FE2E3728281C839C00A1E82A /* BloggingPromptsServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloggingPromptsServiceTests.swift; sourceTree = ""; }; @@ -13368,7 +13365,6 @@ 83BF48BD2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift */, 83A8A2922BDC557E001F9133 /* ReaderTagFooterView.swift */, 83A8A2932BDC557E001F9133 /* ReaderTagFooterView.xib */, - FE2590982BE3F4E2005690E9 /* ReaderTagCardEmptyCell.swift */, ); name = Cards; sourceTree = ""; @@ -22486,7 +22482,6 @@ E62CE58E26B1D14200C9D147 /* AccountService+Cookies.swift in Sources */, 3F4A4C232AD3FA2E00DE5DF8 /* MySiteViewModel.swift in Sources */, FACF66D02ADD6CD8008C3E13 /* PostListItemViewModel.swift in Sources */, - FE2590992BE3F4E2005690E9 /* ReaderTagCardEmptyCell.swift in Sources */, B0F2EFBF259378E600C7EB6D /* SiteSuggestionService.swift in Sources */, 4388FF0020A4E19C00783948 /* NotificationsViewController+PushPrimer.swift in Sources */, 800035BD291DD0D7007D2D26 /* JetpackFullscreenOverlayGeneralViewModel+Analytics.swift in Sources */, @@ -25654,7 +25649,6 @@ 0CED200D2B68425A00E6DD52 /* WebKitView.swift in Sources */, FABB247F2602FC2C00C8785C /* StockPhotosPageable.swift in Sources */, FABB24802602FC2C00C8785C /* JetpackRestoreStatusViewController.swift in Sources */, - FE25909A2BE3F4E2005690E9 /* ReaderTagCardEmptyCell.swift in Sources */, B038A81E2BD70FCA00763731 /* StatsSubscribersChartCell.swift in Sources */, FABB24812602FC2C00C8785C /* BindableTapGestureRecognizer.swift in Sources */, FABB24822602FC2C00C8785C /* ReaderSearchSuggestion.swift in Sources */, From 00e0cc5cf337afa7122561de9a8589ccf56066c2 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:17:40 -0400 Subject: [PATCH 10/55] Remove ReaderTagFooterView --- .../Reader/ReaderTagFooterView.swift | 46 --------- .../Reader/ReaderTagFooterView.xib | 93 ------------------- WordPress/WordPress.xcodeproj/project.pbxproj | 12 --- 3 files changed, 151 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderTagFooterView.swift delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderTagFooterView.xib diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTagFooterView.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTagFooterView.swift deleted file mode 100644 index 3834b290e521..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTagFooterView.swift +++ /dev/null @@ -1,46 +0,0 @@ - -class ReaderTagFooterView: UICollectionReusableView { - - @IBOutlet private weak var contentStackView: UIStackView! - @IBOutlet private weak var arrowButton: UIButton! - @IBOutlet private weak var moreLabel: UILabel! - - private var onTapped: (() -> Void)? - - override func awakeFromNib() { - super.awakeFromNib() - setupStyles() - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onViewTapped)) - addGestureRecognizer(tapGesture) - isAccessibilityElement = true - accessibilityTraits = .button - } - - func configure(with slug: String, onTapped: @escaping () -> Void) { - let moreText = String(format: Constants.moreText, slug) - moreLabel.setText(moreText) - accessibilityLabel = moreText - self.onTapped = onTapped - } - - @objc func onViewTapped() { - onTapped?() - } - - @IBAction func onArrowButtonTapped(_ sender: Any) { - onTapped?() - } - - private func setupStyles() { - moreLabel.font = WPStyleGuide.fontForTextStyle(.subheadline, fontWeight: .semibold) - arrowButton.configuration?.background.backgroundColor = UIColor(light: .secondarySystemBackground, - dark: .tertiarySystemBackground) - } - - private struct Constants { - static let moreText = NSLocalizedString("reader.tags.footer.more", - value: "More from %1$@", - comment: "Label for an action to open more content from a specified Reader tag. %1$@ is the Reader tag.") - } - -} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTagFooterView.xib b/WordPress/Classes/ViewRelated/Reader/ReaderTagFooterView.xib deleted file mode 100644 index 7c374b796aad..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTagFooterView.xib +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index d6d1175a7c9a..fad7b8c2546d 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2469,10 +2469,6 @@ 83A1B1A328AFE89F00E737AC /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1D690141F828FF000200E30 /* BuildConfiguration.swift */; }; 83A337A12A9FA525009ED60C /* ReaderSiteHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83A337A02A9FA525009ED60C /* ReaderSiteHeaderView.swift */; }; 83A337A22A9FA525009ED60C /* ReaderSiteHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83A337A02A9FA525009ED60C /* ReaderSiteHeaderView.swift */; }; - 83A8A2942BDC557F001F9133 /* ReaderTagFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83A8A2922BDC557E001F9133 /* ReaderTagFooterView.swift */; }; - 83A8A2952BDC557F001F9133 /* ReaderTagFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83A8A2922BDC557E001F9133 /* ReaderTagFooterView.swift */; }; - 83A8A2962BDC557F001F9133 /* ReaderTagFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83A8A2932BDC557E001F9133 /* ReaderTagFooterView.xib */; }; - 83A8A2972BDC557F001F9133 /* ReaderTagFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83A8A2932BDC557E001F9133 /* ReaderTagFooterView.xib */; }; 83B1D037282C62620061D911 /* BloggingPromptsAttribution.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83B1D036282C62620061D911 /* BloggingPromptsAttribution.swift */; }; 83B1D038282C62620061D911 /* BloggingPromptsAttribution.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83B1D036282C62620061D911 /* BloggingPromptsAttribution.swift */; }; 83BF48BB2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BF48BA2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift */; }; @@ -8010,8 +8006,6 @@ 839435922847F2200019A94F /* WordPress 143.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 143.xcdatamodel"; sourceTree = ""; }; 839B150A2795DEE0009F5E77 /* UIView+Margins.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Margins.swift"; sourceTree = ""; }; 83A337A02A9FA525009ED60C /* ReaderSiteHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderSiteHeaderView.swift; sourceTree = ""; }; - 83A8A2922BDC557E001F9133 /* ReaderTagFooterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderTagFooterView.swift; sourceTree = ""; }; - 83A8A2932BDC557E001F9133 /* ReaderTagFooterView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ReaderTagFooterView.xib; sourceTree = ""; }; 83B1D036282C62620061D911 /* BloggingPromptsAttribution.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloggingPromptsAttribution.swift; sourceTree = ""; }; 83BF48BA2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTagCardCellViewModel.swift; sourceTree = ""; }; 83BF48BD2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTagCellViewModel.swift; sourceTree = ""; }; @@ -13363,8 +13357,6 @@ 83317EDB2BC72DB7001AD2F4 /* ReaderTagCell.swift */, 83317EDE2BC72DED001AD2F4 /* ReaderTagCell.xib */, 83BF48BD2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift */, - 83A8A2922BDC557E001F9133 /* ReaderTagFooterView.swift */, - 83A8A2932BDC557E001F9133 /* ReaderTagFooterView.xib */, ); name = Cards; sourceTree = ""; @@ -19988,7 +19980,6 @@ 406A0EF0224D39C50016AD6A /* Flags.xcassets in Resources */, 985793C922F23D7000643DBF /* CustomizeInsightsCell.xib in Resources */, 1761F17926209AEE000815EF /* wordpress-dark-icon-app-60x60@2x.png in Resources */, - 83A8A2962BDC557F001F9133 /* ReaderTagFooterView.xib in Resources */, 2FAE970D0E33B21600CA8540 /* xhtmlValidatorTemplate.xhtml in Resources */, 9826AE8821B5C73400C851FA /* PostingActivityDay.xib in Resources */, 8BB185CC24B6058600A4CCE8 /* reader-cards.json in Resources */, @@ -20627,7 +20618,6 @@ FABB202F2602FC2C00C8785C /* CountriesMapView.xib in Resources */, F465978528E65E1800D5F49A /* blue-on-white-icon-app-60@2x.png in Resources */, FABB20302602FC2C00C8785C /* OverviewCell.xib in Resources */, - 83A8A2972BDC557F001F9133 /* ReaderTagFooterView.xib in Resources */, F46597E928E6698D00D5F49A /* spectrum-on-black-icon-app-83.5@2x.png in Resources */, FABB20322602FC2C00C8785C /* JetpackRemoteInstallStateView.xib in Resources */, FABB20352602FC2C00C8785C /* TemplatePreviewViewController.xib in Resources */, @@ -22367,7 +22357,6 @@ 931215F2267FE162008C3B69 /* ReferrerDetailsSpamActionRow.swift in Sources */, E66EB6F91C1B7A76003DABC5 /* ReaderSpacerView.swift in Sources */, FAFF7A222B695801006A7CB2 /* WebServerLogsView.swift in Sources */, - 83A8A2942BDC557F001F9133 /* ReaderTagFooterView.swift in Sources */, AE2F3125270B6DA000B2A9C2 /* Scanner+QuotedText.swift in Sources */, B560914C208A671F00399AE4 /* WPStyleGuide+SiteCreation.swift in Sources */, 014ACD142A1E5034008A706C /* WebKitViewController+SandboxStore.swift in Sources */, @@ -26082,7 +26071,6 @@ 8BE6F92D27EE27DB0008BDC7 /* BlogDashboardPostCardGhostCell.swift in Sources */, 3FF15A5C291ED21100E1B4E5 /* MigrationNotificationsCenterView.swift in Sources */, FABB25B32602FC2C00C8785C /* ReaderVisitSiteAction.swift in Sources */, - 83A8A2952BDC557F001F9133 /* ReaderTagFooterView.swift in Sources */, FABB25B42602FC2C00C8785C /* ReaderCard+CoreDataProperties.swift in Sources */, FABB25B52602FC2C00C8785C /* GutenbergViewController+MoreActions.swift in Sources */, FABB25B62602FC2C00C8785C /* Product.swift in Sources */, From 18ff7f5ab4a9f68950362d7f86e8276a1cb2d287 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:19:27 -0400 Subject: [PATCH 11/55] Remove ReaderTagCardCellViewModel --- .../ViewRelated/Reader/ReaderHelpers.swift | 2 - .../Reader/ReaderTagCardCellViewModel.swift | 205 ------------------ WordPress/WordPress.xcodeproj/project.pbxproj | 6 - 3 files changed, 213 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderTagCardCellViewModel.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift b/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift index 426ef526f4fa..9bd2f36ce73e 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift @@ -22,8 +22,6 @@ extension NSNotification.Name { static let ReaderUserBlockingWillBegin = NSNotification.Name(rawValue: "ReaderUserBlockingWillBegin") // Sent when the user blocking request is complete static let ReaderUserBlockingDidEnd = NSNotification.Name(rawValue: "ReaderUserBlockingDidEnd") - // Sent when the filter from a feed is updated - static let ReaderFilterUpdated = NSNotification.Name(rawValue: "ReaderFilterUpdated") } struct ReaderNotificationKeys { diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCellViewModel.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCellViewModel.swift deleted file mode 100644 index f5dfc9559437..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTagCardCellViewModel.swift +++ /dev/null @@ -1,205 +0,0 @@ - -protocol ReaderTagCardCellViewModelDelegate: NSObjectProtocol { - func showLoading() - func hideLoading() -} - -class ReaderTagCardCellViewModel: NSObject { - - enum TagButtonSource { - case header - case footer - - var event: WPAnalyticsEvent { - switch self { - case .header: - return .readerTagsFeedHeaderTapped - case .footer: - return .readerTagsFeedMoreFromTagTapped - } - } - } - - enum Section: Int { - case emptyState = 101 - case posts - } - - enum CardCellItem: Hashable { - case empty - case post(id: NSManagedObjectID) - } - - private typealias DataSource = UICollectionViewDiffableDataSource - private typealias Snapshot = NSDiffableDataSourceSnapshot - - let slug: String - weak var viewDelegate: ReaderTagCardCellViewModelDelegate? = nil - - private let tag: ReaderAbstractTopic - private let coreDataStack: CoreDataStackSwift - private weak var parentViewController: UIViewController? - private weak var collectionView: UICollectionView? - private let isLoggedIn: Bool - private let cellSize: () -> CGSize? - - private lazy var readerPostService: ReaderPostService = { - .init(coreDataStack: coreDataStack) - }() - - private lazy var dataSource: DataSource? = { [weak self] in - guard let collectionView = self?.collectionView else { - return nil - } - - return self?.createDataSource(with: collectionView) - }() - - private lazy var resultsController: NSFetchedResultsController = { - let fetchRequest = NSFetchRequest(entityName: ReaderPost.classNameWithoutNamespaces()) - fetchRequest.sortDescriptors = [NSSortDescriptor(key: "sortRank", ascending: false)] - fetchRequest.fetchLimit = Constants.displayPostLimit - fetchRequest.includesSubentities = false - let resultsController = NSFetchedResultsController(fetchRequest: fetchRequest, - managedObjectContext: ContextManager.shared.mainContext, - sectionNameKeyPath: nil, - cacheName: nil) - resultsController.delegate = self - return resultsController - }() - - // MARK: Methods - - init(parent: UIViewController?, - tag: ReaderTagTopic, - collectionView: UICollectionView?, - isLoggedIn: Bool, - viewDelegate: ReaderTagCardCellViewModelDelegate?, - coreDataStack: CoreDataStackSwift = ContextManager.shared, - cellSize: @escaping @autoclosure () -> CGSize?) { - self.parentViewController = parent - self.slug = tag.slug - self.tag = tag - self.collectionView = collectionView - self.isLoggedIn = isLoggedIn - self.viewDelegate = viewDelegate - self.coreDataStack = coreDataStack - self.cellSize = cellSize - - super.init() - - resultsController.fetchRequest.predicate = NSPredicate(format: "topic = %@ AND isSiteBlocked = NO", tag) - collectionView?.delegate = self - } - - func fetchTagPosts(syncRemotely: Bool) { - guard let topic = try? ReaderTagTopic.lookup(withSlug: slug, in: coreDataStack.mainContext) else { - return - } - - viewDelegate?.showLoading() - - let onRemoteFetchComplete = { [weak self] in - try? self?.resultsController.performFetch() - } - - guard syncRemotely else { - onRemoteFetchComplete() - return - } - - readerPostService.fetchPosts(for: topic, earlierThan: Date()) { _, _ in - onRemoteFetchComplete() - } failure: { _ in - // try to show local contents even if the request failed. - onRemoteFetchComplete() - } - } - - func onTagButtonTapped(source: TagButtonSource) { - switch source { - case .footer: - let controller = ReaderStreamViewController.controllerWithTagSlug(slug) - controller.statSource = .tagsFeed - parentViewController?.navigationController?.pushViewController(controller, animated: true) - case .header: - NotificationCenter.default.post(name: .ReaderFilterUpdated, - object: nil, - userInfo: [ReaderNotificationKeys.topic: tag]) - } - - WPAnalytics.track(source.event) - } - - struct Constants { - static let displayPostLimit = 10 - static let footerWidth: CGFloat = 200 - } - -} - -// MARK: - Private Methods - -private extension ReaderTagCardCellViewModel { - /// Translates a diffable snapshot from `NSFetchedResultsController` to a snapshot that fits the collection view. - /// - /// Snapshots returned from `NSFetchedResultsController` always have the type ``, so - /// it needs to be converted to match the correct type required by the collection view. - /// - /// - Parameter snapshotRef: The snapshot returned from the `NSFetchedResultsController` - /// - Returns: `Snapshot` - private func collectionViewSnapshot(from snapshotRef: NSDiffableDataSourceSnapshotReference) -> Snapshot { - let coreDataSnapshot = snapshotRef as NSDiffableDataSourceSnapshot - let isEmpty = coreDataSnapshot.numberOfItems == .zero - var snapshot = Snapshot() - - // there must be at least one section. - snapshot.appendSections([isEmpty ? .emptyState : .posts]) - snapshot.appendItems(isEmpty ? [.empty] : coreDataSnapshot.itemIdentifiers.map { .post(id: $0) }) - - return snapshot - } - - private func createDataSource(with collectionView: UICollectionView) -> DataSource { - let dataSource = DataSource(collectionView: collectionView) { [weak self] collectionView, indexPath, item in - switch item { - case .empty: - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ReaderTagCardEmptyCell.defaultReuseID, - for: indexPath) as? ReaderTagCardEmptyCell else { - return UICollectionViewCell() - } - - cell.configure(tagTitle: self?.slug ?? "") { [weak self] in - self?.fetchTagPosts(syncRemotely: true) - } - - return cell - - case .post(let objectID): - guard let post = try? ContextManager.shared.mainContext.existingObject(with: objectID) as? ReaderPost, - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ReaderTagCell.classNameWithoutNamespaces(), - for: indexPath) as? ReaderTagCell else { - return UICollectionViewCell() - } - - cell.configure(parent: self?.parentViewController, - post: post, - isLoggedIn: self?.isLoggedIn ?? AccountHelper.isLoggedIn) - return cell - } - } - dataSource.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath in - guard kind == UICollectionView.elementKindSectionFooter, - let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, - withReuseIdentifier: ReaderTagFooterView.classNameWithoutNamespaces(), - for: indexPath) as? ReaderTagFooterView else { - return nil - } - view.configure(with: self?.slug ?? "") { [weak self] in - self?.onTagButtonTapped(source: .footer) - } - return view - } - return dataSource - } -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index fad7b8c2546d..c5aefc7817a4 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2471,8 +2471,6 @@ 83A337A22A9FA525009ED60C /* ReaderSiteHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83A337A02A9FA525009ED60C /* ReaderSiteHeaderView.swift */; }; 83B1D037282C62620061D911 /* BloggingPromptsAttribution.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83B1D036282C62620061D911 /* BloggingPromptsAttribution.swift */; }; 83B1D038282C62620061D911 /* BloggingPromptsAttribution.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83B1D036282C62620061D911 /* BloggingPromptsAttribution.swift */; }; - 83BF48BB2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BF48BA2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift */; }; - 83BF48BC2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BF48BA2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift */; }; 83BF48BE2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BF48BD2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift */; }; 83BF48BF2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BF48BD2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift */; }; 83BFAE482A6EBF1F00C7B683 /* DashboardJetpackSocialCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BFAE472A6EBF1F00C7B683 /* DashboardJetpackSocialCardCell.swift */; }; @@ -8007,7 +8005,6 @@ 839B150A2795DEE0009F5E77 /* UIView+Margins.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Margins.swift"; sourceTree = ""; }; 83A337A02A9FA525009ED60C /* ReaderSiteHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderSiteHeaderView.swift; sourceTree = ""; }; 83B1D036282C62620061D911 /* BloggingPromptsAttribution.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloggingPromptsAttribution.swift; sourceTree = ""; }; - 83BF48BA2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTagCardCellViewModel.swift; sourceTree = ""; }; 83BF48BD2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTagCellViewModel.swift; sourceTree = ""; }; 83BFAE472A6EBF1F00C7B683 /* DashboardJetpackSocialCardCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardJetpackSocialCardCell.swift; sourceTree = ""; }; 83BFAE4F2A6EBF9900C7B683 /* DashboardJetpackSocialCardCellTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardJetpackSocialCardCellTests.swift; sourceTree = ""; }; @@ -13353,7 +13350,6 @@ 83204EDB2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift */, 3234BB322530EA980068DA40 /* ReaderRecommendedSiteCardCell.swift */, 3234BB332530EA980068DA40 /* ReaderRecommendedSiteCardCell.xib */, - 83BF48BA2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift */, 83317EDB2BC72DB7001AD2F4 /* ReaderTagCell.swift */, 83317EDE2BC72DED001AD2F4 /* ReaderTagCell.xib */, 83BF48BD2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift */, @@ -22205,7 +22201,6 @@ E6F2788121BC1A4A008B4DB5 /* PlanGroup.swift in Sources */, 08216FCE1CDBF96000304BA7 /* MenuItemPostsViewController.m in Sources */, 4322A20D203E1885004EA740 /* SignupUsernameTableViewController.swift in Sources */, - 83BF48BB2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift in Sources */, 098B8576275E76FE004D299F /* AppLocalizedString.swift in Sources */, 7E7BEF7022E1AED8009A880D /* Blog+Editor.swift in Sources */, 1756F1DF2822BB6F00CD0915 /* SparklineView.swift in Sources */, @@ -26035,7 +26030,6 @@ FABB25982602FC2C00C8785C /* JetpackRestoreHeaderView.swift in Sources */, FA6C32B32BEE65EF00BBDDB4 /* BlockingUpdateView.swift in Sources */, FABB25992602FC2C00C8785C /* StoryboardLoadable.swift in Sources */, - 83BF48BC2BD6F03000C0E1A1 /* ReaderTagCardCellViewModel.swift in Sources */, FABB259A2602FC2C00C8785C /* ReaderBlockSiteAction.swift in Sources */, 0CDDCA052C8F3F6E005AACA3 /* ReaderSidebarTagsSection.swift in Sources */, FABB259C2602FC2C00C8785C /* ReaderPostService+RelatedPosts.swift in Sources */, From 2d337bac672804e0deddb5295d36c351600cbdeb Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:20:07 -0400 Subject: [PATCH 12/55] Remove ReaderTagCell --- .../ViewRelated/Reader/ReaderTagCell.swift | 176 ----------------- .../ViewRelated/Reader/ReaderTagCell.xib | 179 ------------------ .../Reader/ReaderTagCellViewModel.swift | 46 ----- WordPress/WordPress.xcodeproj/project.pbxproj | 18 -- 4 files changed, 419 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderTagCell.swift delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderTagCell.xib delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderTagCellViewModel.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTagCell.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTagCell.swift deleted file mode 100644 index 4181140c6606..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTagCell.swift +++ /dev/null @@ -1,176 +0,0 @@ -import WordPressUI - -class ReaderTagCell: UICollectionViewCell { - - private typealias AccessibilityConstants = ReaderPostCardCell.Constants.Accessibility - - @IBOutlet private weak var contentStackView: UIStackView! - @IBOutlet private weak var headerStackView: UIStackView! - @IBOutlet private weak var siteLabel: UILabel! - @IBOutlet private weak var postDateLabel: UILabel! - @IBOutlet private weak var titleLabel: UILabel! - @IBOutlet private weak var summaryLabel: UILabel! - @IBOutlet private weak var featuredImageViewContainer: UIView! - @IBOutlet private weak var featuredImageView: CachedAnimatedImageView! - @IBOutlet private weak var likeButton: UIButton! - @IBOutlet private weak var menuButton: UIButton! - @IBOutlet weak var spacerView: UIView! - @IBOutlet weak var titleSpacerView: UIView! - @IBOutlet weak var countsLabelSpacerView: UIView! - @IBOutlet private var contentBoundsConstraints: [NSLayoutConstraint]! - - private lazy var imageLoader = ImageLoader(imageView: featuredImageView) - private var viewModel: ReaderTagCellViewModel? - - override func awakeFromNib() { - super.awakeFromNib() - setupStyles() - contentStackView.setCustomSpacing(0, after: featuredImageView) - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(onSiteTitleTapped)) - headerStackView.addGestureRecognizer(tapGesture) - - spacerView.isGhostableDisabled = true - titleSpacerView.isGhostableDisabled = true - countsLabelSpacerView.isGhostableDisabled = true - - updateContentConstraints() - } - - override func prepareForReuse() { - super.prepareForReuse() - imageLoader.prepareForReuse() - resetHiddenViews() - updateContentConstraints() - } - - func configure(parent: UIViewController?, post: ReaderPost, isLoggedIn: Bool) { - viewModel = ReaderTagCellViewModel(parent: parent, post: post, isLoggedIn: isLoggedIn) - - setupLabels(with: post, isLoggedIn: isLoggedIn) - configureLikeButton(with: post) - loadFeaturedImage(with: post) - } - - @objc private func onSiteTitleTapped() { - viewModel?.onSiteTitleTapped() - } - - @IBAction private func onLikeButtonTapped(_ sender: Any) { - viewModel?.onLikeButtonTapped() - } - - @IBAction private func onMenuButtonTapped(_ sender: UIButton) { - viewModel?.onMenuButtonTapped(with: sender) - } - - private struct Constants { - static let likeText = NSLocalizedString("reader.tags.button.like", - value: "Like", - comment: "Text for the 'Like' button on the reader tag cell.") - static let likedText = NSLocalizedString("reader.tags.button.liked", - value: "Liked", - comment: "Text for the 'Liked' button on the reader tag cell.") - static let likeButtonImage = UIImage(named: "icon-reader-star-outline")?.withRenderingMode(.alwaysTemplate) - static let likedButtonImage = UIImage(named: "icon-reader-star-fill")?.withRenderingMode(.alwaysTemplate) - } - -} - -// MARK: - Private methods - -private extension ReaderTagCell { - - func setupStyles() { - siteLabel.font = WPStyleGuide.fontForTextStyle(.footnote, fontWeight: .semibold) - postDateLabel.font = WPStyleGuide.fontForTextStyle(.footnote) - postDateLabel.textColor = .secondaryLabel - titleLabel.font = WPStyleGuide.fontForTextStyle(.headline, fontWeight: .semibold) - summaryLabel.font = WPStyleGuide.fontForTextStyle(.footnote) - likeButton.tintColor = .secondaryLabel - likeButton.titleLabel?.font = WPStyleGuide.fontForTextStyle(.footnote) - menuButton.tintColor = .secondaryLabel - featuredImageView.layer.cornerRadius = 5.0 - } - - func loadFeaturedImage(with post: ReaderPost) { - guard let url = post.featuredImageURLForDisplay() else { - featuredImageViewContainer.isHidden = true - featuredImageView.isHidden = true - return - } - let imageSize = CGSize(width: featuredImageView.frame.width, - height: featuredImageView.frame.height) - let host = MediaHost(with: post, failure: { error in - DDLogError("\(error)") - }) - imageLoader.loadImage(with: url, from: host, preferredSize: imageSize) - } - - func resetHiddenViews() { - siteLabel.isHidden = false - titleLabel.isHidden = false - summaryLabel.isHidden = false - featuredImageViewContainer.isHidden = false - featuredImageView.isHidden = false - likeButton.isHidden = false - } - - func configureLikeButton(with post: ReaderPost) { - let isLiked = post.isLiked - likeButton.setTitle(isLiked ? Constants.likedText : Constants.likeText, for: .normal) - likeButton.setImage(isLiked ? Constants.likedButtonImage : Constants.likeButtonImage, for: .normal) - likeButton.tintColor = isLiked ? UIAppColor.jetpackGreen : .secondaryLabel - likeButton.setTitleColor(likeButton.tintColor, for: .normal) - likeButton.accessibilityHint = post.isLiked ? AccessibilityConstants.likedButtonHint : AccessibilityConstants.likeButtonHint - } - - func setupLabels(with post: ReaderPost, isLoggedIn: Bool) { - let blogName = post.blogNameForDisplay() - let postDate = post.shortDateForDisplay() - let postTitle = post.titleForDisplay() - let postSummary = post.summaryForDisplay(isPad: traitCollection.userInterfaceIdiom == .pad) - - siteLabel.text = blogName - postDateLabel.text = postDate - titleLabel.text = postTitle - summaryLabel.text = postSummary - - siteLabel.isHidden = blogName == nil - postDateLabel.isHidden = postDate == nil - titleLabel.isHidden = postTitle == nil - summaryLabel.isHidden = postSummary == nil - - headerStackView.isAccessibilityElement = true - headerStackView.accessibilityLabel = [blogName, postDate].compactMap { $0 }.joined(separator: ", ") - headerStackView.accessibilityHint = AccessibilityConstants.siteStackViewHint - headerStackView.accessibilityTraits = .button - menuButton.accessibilityLabel = AccessibilityConstants.menuButtonLabel - menuButton.accessibilityHint = AccessibilityConstants.menuButtonHint - } - - func updateContentConstraints() { - let isExtraLargeCategory = traitCollection.preferredContentSizeCategory >= .extraLarge - contentBoundsConstraints.forEach { $0.isActive = !isExtraLargeCategory } - } - -} - -extension ReaderTagCell: GhostableView { - - func ghostAnimationWillStart() { - // The ghost loading animation only works on leaf subviews. - // `CachedAnimatedImageView` by default injects an activity indicator as a subview into the image view, - // therefore causing the `GhostLayer` to not be applied to the image view. - featuredImageView?.subviews.forEach { $0.removeFromSuperview() } - - siteLabel?.text = "Site name" - - var configuration = UIButton.Configuration.plain() - configuration.contentInsets = .init(top: 0, leading: 0, bottom: 0, trailing: 15.0) - configuration.imagePadding = .zero - configuration.imagePlacement = .leading - likeButton?.configuration = configuration - likeButton?.setTitle("", for: .normal) - } - -} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTagCell.xib b/WordPress/Classes/ViewRelated/Reader/ReaderTagCell.xib deleted file mode 100644 index 66227cbdbca8..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTagCell.xib +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTagCellViewModel.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTagCellViewModel.swift deleted file mode 100644 index 1214e98e939c..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTagCellViewModel.swift +++ /dev/null @@ -1,46 +0,0 @@ - -struct ReaderTagCellViewModel { - - private weak var parentViewController: UIViewController? - private let post: ReaderPost - private let isLoggedIn: Bool - private var followCommentsService: FollowCommentsService? - - init(parent: UIViewController?, post: ReaderPost, isLoggedIn: Bool) { - self.parentViewController = parent - self.post = post - self.isLoggedIn = isLoggedIn - } - - func onSiteTitleTapped() { - guard let parentViewController else { - return - } - ReaderHeaderAction().execute(post: post, origin: parentViewController, source: .tagsFeed) - } - - func onLikeButtonTapped() { - ReaderLikeAction().execute(with: post, source: ReaderStreamViewController.StatSource.tagsFeed.rawValue) - } - - mutating func onMenuButtonTapped(with anchor: UIView) { - guard let parentViewController = parentViewController as? ReaderStreamViewController, - let followCommentsService = FollowCommentsService(post: post) else { - return - } - self.followCommentsService = followCommentsService - - ReaderMenuAction(logged: isLoggedIn).execute( - post: post, - context: parentViewController.viewContext, - readerTopic: parentViewController.readerTopic, - anchor: anchor, - vc: parentViewController, - source: .tagCard, - followCommentsService: followCommentsService, - showAdditionalItems: true - ) - WPAnalytics.trackReader(.postCardMoreTapped) - } - -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index c5aefc7817a4..9194cdee1191 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2403,10 +2403,6 @@ 8320BDE5283D9359009DF2DE /* BlogService+BloggingPrompts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8320BDE4283D9359009DF2DE /* BlogService+BloggingPrompts.swift */; }; 8320BDE6283D9359009DF2DE /* BlogService+BloggingPrompts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8320BDE4283D9359009DF2DE /* BlogService+BloggingPrompts.swift */; }; 8323789928526E6E003F4443 /* AppConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA25F9FD2609AA830005E08F /* AppConfiguration.swift */; }; - 83317EDC2BC72DB7001AD2F4 /* ReaderTagCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83317EDB2BC72DB7001AD2F4 /* ReaderTagCell.swift */; }; - 83317EDD2BC72DB7001AD2F4 /* ReaderTagCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83317EDB2BC72DB7001AD2F4 /* ReaderTagCell.swift */; }; - 83317EDF2BC72DED001AD2F4 /* ReaderTagCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83317EDE2BC72DED001AD2F4 /* ReaderTagCell.xib */; }; - 83317EE02BC72DED001AD2F4 /* ReaderTagCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83317EDE2BC72DED001AD2F4 /* ReaderTagCell.xib */; }; 8332D7452ADF263500EB97EF /* UIConfigurationTextAttributesTransformer+Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8332D7442ADF263400EB97EF /* UIConfigurationTextAttributesTransformer+Font.swift */; }; 8332D7462ADF263500EB97EF /* UIConfigurationTextAttributesTransformer+Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8332D7442ADF263400EB97EF /* UIConfigurationTextAttributesTransformer+Font.swift */; }; 8332DD2429259AE300802F7D /* DataMigrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8332DD2329259AE300802F7D /* DataMigrator.swift */; }; @@ -2471,8 +2467,6 @@ 83A337A22A9FA525009ED60C /* ReaderSiteHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83A337A02A9FA525009ED60C /* ReaderSiteHeaderView.swift */; }; 83B1D037282C62620061D911 /* BloggingPromptsAttribution.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83B1D036282C62620061D911 /* BloggingPromptsAttribution.swift */; }; 83B1D038282C62620061D911 /* BloggingPromptsAttribution.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83B1D036282C62620061D911 /* BloggingPromptsAttribution.swift */; }; - 83BF48BE2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BF48BD2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift */; }; - 83BF48BF2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BF48BD2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift */; }; 83BFAE482A6EBF1F00C7B683 /* DashboardJetpackSocialCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BFAE472A6EBF1F00C7B683 /* DashboardJetpackSocialCardCell.swift */; }; 83BFAE492A6EBF1F00C7B683 /* DashboardJetpackSocialCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BFAE472A6EBF1F00C7B683 /* DashboardJetpackSocialCardCell.swift */; }; 83BFAE502A6EBF9900C7B683 /* DashboardJetpackSocialCardCellTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83BFAE4F2A6EBF9900C7B683 /* DashboardJetpackSocialCardCellTests.swift */; }; @@ -7962,8 +7956,6 @@ 8313B9F92995A03C000AF26E /* JetpackRemoteInstallCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackRemoteInstallCardView.swift; sourceTree = ""; }; 83204EDB2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderPostCardCellViewModel.swift; sourceTree = ""; }; 8320BDE4283D9359009DF2DE /* BlogService+BloggingPrompts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BlogService+BloggingPrompts.swift"; sourceTree = ""; }; - 83317EDB2BC72DB7001AD2F4 /* ReaderTagCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTagCell.swift; sourceTree = ""; }; - 83317EDE2BC72DED001AD2F4 /* ReaderTagCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReaderTagCell.xib; sourceTree = ""; }; 8332D7442ADF263400EB97EF /* UIConfigurationTextAttributesTransformer+Font.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIConfigurationTextAttributesTransformer+Font.swift"; sourceTree = ""; }; 8332DD2329259AE300802F7D /* DataMigrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataMigrator.swift; sourceTree = ""; }; 8332DD2729259BEB00802F7D /* DataMigratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataMigratorTests.swift; sourceTree = ""; }; @@ -8005,7 +7997,6 @@ 839B150A2795DEE0009F5E77 /* UIView+Margins.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Margins.swift"; sourceTree = ""; }; 83A337A02A9FA525009ED60C /* ReaderSiteHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderSiteHeaderView.swift; sourceTree = ""; }; 83B1D036282C62620061D911 /* BloggingPromptsAttribution.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloggingPromptsAttribution.swift; sourceTree = ""; }; - 83BF48BD2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTagCellViewModel.swift; sourceTree = ""; }; 83BFAE472A6EBF1F00C7B683 /* DashboardJetpackSocialCardCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardJetpackSocialCardCell.swift; sourceTree = ""; }; 83BFAE4F2A6EBF9900C7B683 /* DashboardJetpackSocialCardCellTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardJetpackSocialCardCellTests.swift; sourceTree = ""; }; 83C972DF281C45AB0049E1FE /* Post+BloggingPrompts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Post+BloggingPrompts.swift"; sourceTree = ""; }; @@ -13350,9 +13341,6 @@ 83204EDB2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift */, 3234BB322530EA980068DA40 /* ReaderRecommendedSiteCardCell.swift */, 3234BB332530EA980068DA40 /* ReaderRecommendedSiteCardCell.xib */, - 83317EDB2BC72DB7001AD2F4 /* ReaderTagCell.swift */, - 83317EDE2BC72DED001AD2F4 /* ReaderTagCell.xib */, - 83BF48BD2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift */, ); name = Cards; sourceTree = ""; @@ -20101,7 +20089,6 @@ 17222D9D261DDDF90047B163 /* black-icon-app-83.5x83.5@2x.png in Resources */, 17C1D6F526711ED0006C8970 /* Emoji.txt in Resources */, B5C66B761ACF072C00F68370 /* NoteBlockCommentTableViewCell.xib in Resources */, - 83317EDF2BC72DED001AD2F4 /* ReaderTagCell.xib in Resources */, 17222D94261DDDF90047B163 /* pink-icon-app-76x76@2x.png in Resources */, 3F4D035328A5BFCE00F0A4FD /* JetpackWordPressLogoAnimation_ltr.json in Resources */, 3223393E24FEC2A700BDD4BF /* ReaderDetailFeaturedImageView.xib in Resources */, @@ -20708,7 +20695,6 @@ F465977B28E6598900D5F49A /* black-on-white-icon-app-76@2x.png in Resources */, FABB209A2602FC2C00C8785C /* PostListFooterView.xib in Resources */, 98E5501A265C977E00B4BE9A /* ReaderDetailLikesView.xib in Resources */, - 83317EE02BC72DED001AD2F4 /* ReaderTagCell.xib in Resources */, F46597BF28E6687800D5F49A /* neumorphic-dark-icon-app-83.5@2x.png in Resources */, F465980C28E66A5B00D5F49A /* white-on-blue-icon-app-83.5@2x.png in Resources */, F41E4E9928F20802001880C6 /* white-on-pink-icon-app-60@2x.png in Resources */, @@ -22050,7 +22036,6 @@ 80A2154029CA68D5002FE8EB /* RemoteFeatureFlag.swift in Sources */, 74729CA62056FE6000D1394D /* SearchableItemConvertable.swift in Sources */, B59D994F1C0790CC0003D795 /* SettingsListEditorViewController.swift in Sources */, - 83317EDC2BC72DB7001AD2F4 /* ReaderTagCell.swift in Sources */, FAC1B81E29B0C2AC00E0C542 /* BlazeOverlayViewModel.swift in Sources */, C9B477AE29CC35A0008CBF49 /* WidgetDataReader.swift in Sources */, FEF28E822ACB3DCE006C6579 /* ReaderDetailNewHeaderView.swift in Sources */, @@ -22511,7 +22496,6 @@ 46C984682527863E00988BB9 /* LayoutPickerAnalyticsEvent.swift in Sources */, 7E442FCD20F6AB9C00DEACA5 /* ActivityRange.swift in Sources */, 9AF9551821A1D7970057827C /* DiffAbstractValue+Attributes.swift in Sources */, - 83BF48BE2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift in Sources */, FE50965C2A20D0F300DDD071 /* CommentTableHeaderView.swift in Sources */, 8BD66ED42787530C00CCD95A /* PostsCardViewModel.swift in Sources */, 7E58879A20FE8D9300DB6F80 /* AppEnvironment.swift in Sources */, @@ -25033,7 +25017,6 @@ FABB22DD2602FC2C00C8785C /* RevisionsTableViewCell.swift in Sources */, E6D6A1312683ABE6004C24A7 /* ReaderSubscribeCommentsAction.swift in Sources */, F49B9A06293A21BF000CEFCE /* MigrationAnalyticsTracker.swift in Sources */, - 83BF48BF2BD6FA3000C0E1A1 /* ReaderTagCellViewModel.swift in Sources */, E62CE58F26B1D14200C9D147 /* AccountService+Cookies.swift in Sources */, 0C391E622A3002950040EA91 /* BlazeCampaignStatusView.swift in Sources */, FABB22DF2602FC2C00C8785C /* PlanDetailViewModel.swift in Sources */, @@ -25350,7 +25333,6 @@ FABB23B02602FC2C00C8785C /* Data.swift in Sources */, FAA5C9102B7FC74C002E073B /* PostSyncStateViewModel.swift in Sources */, FA111E392A2F474600896FCE /* BlazeCampaignsViewController.swift in Sources */, - 83317EDD2BC72DB7001AD2F4 /* ReaderTagCell.swift in Sources */, FABB23B12602FC2C00C8785C /* AccountSettingsViewController.swift in Sources */, FABB23B22602FC2C00C8785C /* StatsChildRowsView.swift in Sources */, FABB23B32602FC2C00C8785C /* Menu.m in Sources */, From 1200e8f5067f85e65294da621ef2e0ad83a80d8d Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:22:39 -0400 Subject: [PATCH 13/55] Remove ReaderTopicChangeObserver --- .../Filter/ReaderTopicChangeObserver.swift | 47 ------------------- .../Reader/ReaderStreamViewController.swift | 21 --------- .../Reader/ReaderTableContent.swift | 3 ++ WordPress/WordPress.xcodeproj/project.pbxproj | 6 --- 4 files changed, 3 insertions(+), 74 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Filter/ReaderTopicChangeObserver.swift diff --git a/WordPress/Classes/ViewRelated/Reader/Filter/ReaderTopicChangeObserver.swift b/WordPress/Classes/ViewRelated/Reader/Filter/ReaderTopicChangeObserver.swift deleted file mode 100644 index a6e04a27201f..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Filter/ReaderTopicChangeObserver.swift +++ /dev/null @@ -1,47 +0,0 @@ -import CoreData - -// MARK: - Protocols - -protocol ReaderTopicObserverDelegate: NSObjectProtocol { - func readerTopicDidChange() -} - -protocol ReaderTopicObserving: NSObjectProtocol { - var delegate: ReaderTopicObserverDelegate? { get set } -} - -// MARK: - Concrete Class - -/// Observes model changes to `Topic` and notifies the delegate. -/// The type `Topic` is restricted to `ReaderAbstractTopic` and its subclasses. -/// -class ReaderTopicChangeObserver: NSObject, ReaderTopicObserving { - weak var delegate: ReaderTopicObserverDelegate? - - init(delegate: ReaderTopicObserverDelegate? = nil) { - self.delegate = delegate - super.init() - - NotificationCenter.default.addObserver(self, - selector: #selector(handleObjectsChange), - name: .NSManagedObjectContextObjectsDidChange, - object: nil) - } - - @objc private func handleObjectsChange(_ notification: Foundation.Notification) { - // Check for objects with type `Topic` within the Notification. - let notificationContainsTopic = [notification.userInfo?[NSUpdatedObjectsKey] as? Set, - notification.userInfo?[NSRefreshedObjectsKey] as? Set] - .compactMap { set in set?.firstIndex(where: { $0 is Topic }) } - .count > 0 - - // Skip if `Topic` is not included at all in the notification payload. - guard notificationContainsTopic else { - return - } - - Task { @MainActor [weak self] in - self?.delegate?.readerTopicDidChange() - } - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 177ee43dd2d8..583dd7f1d685 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -1496,13 +1496,6 @@ extension ReaderStreamViewController: WPTableViewHandlerDelegate { logReaderError(.invalidIndexPath(row: indexPath.row, totalRows: posts.count)) return .init() } - } else if let tags = content.content as? [ReaderTagTopic] { - if let tag = tags[safe: indexPath.row] { - return cell(for: tag) - } else { - logReaderError(.invalidIndexPath(row: indexPath.row, totalRows: tags.count)) - return .init() - } } assertionFailure("Unexpected content type.") return UITableViewCell() @@ -1556,20 +1549,6 @@ extension ReaderStreamViewController: WPTableViewHandlerDelegate { cell.separatorInset = UIEdgeInsets(.leading, 9999) } - func cell(for tag: ReaderTagTopic) -> UITableViewCell { - let cell = tableConfiguration.tagCell(tableView) - - // check whether we should sync the tag's posts. - let shouldSync = !tagStreamSyncTracker.contains(tag.slug) - if shouldSync { - tagStreamSyncTracker.insert(tag.slug) - } - - cell.configure(parent: self, tag: tag, isLoggedIn: isLoggedIn, shouldSyncRemotely: shouldSync) - cell.selectionStyle = .none - return cell - } - func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { // Cache the cell's layout height as the currently known height, for estimation. // See estimatedHeightForRowAtIndexPath diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTableContent.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTableContent.swift index 4324c6361c8c..c5525b89fbcd 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTableContent.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderTableContent.swift @@ -1,3 +1,6 @@ +import UIKit +import WordPressShared + /// Wraps WPTableViewHandler so that we can start abstracting coredata out of some view controllers final class ReaderTableContent { private var tableViewHandler: WPTableViewHandler? diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 9194cdee1191..86722888a1ae 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -5714,8 +5714,6 @@ FEF4DC5528439357003806BE /* ReminderScheduleCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEF4DC5428439357003806BE /* ReminderScheduleCoordinator.swift */; }; FEF4DC5628439357003806BE /* ReminderScheduleCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEF4DC5428439357003806BE /* ReminderScheduleCoordinator.swift */; }; FEF7F3402AFEA0C200F793FC /* blogging-prompts-bloganuary.json in Resources */ = {isa = PBXBuildFile; fileRef = FEF7F33F2AFEA0C200F793FC /* blogging-prompts-bloganuary.json */; }; - FEF9A74B2BA1CF370014045E /* ReaderTopicChangeObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEF9A74A2BA1CF370014045E /* ReaderTopicChangeObserver.swift */; }; - FEF9A74C2BA1CF370014045E /* ReaderTopicChangeObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEF9A74A2BA1CF370014045E /* ReaderTopicChangeObserver.swift */; }; FEFA263E26C58427009CCB7E /* ShareAppTextActivityItemSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEFA263D26C58427009CCB7E /* ShareAppTextActivityItemSourceTests.swift */; }; FEFA263F26C5AE9A009CCB7E /* ShareAppContentPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE06AC8226C3BD0900B69DE4 /* ShareAppContentPresenter.swift */; }; FEFA264026C5AE9E009CCB7E /* ShareAppTextActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE06AC8426C3C2F800B69DE4 /* ShareAppTextActivityItemSource.swift */; }; @@ -9780,7 +9778,6 @@ FEF28E812ACB3DCE006C6579 /* ReaderDetailNewHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderDetailNewHeaderView.swift; sourceTree = ""; }; FEF4DC5428439357003806BE /* ReminderScheduleCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReminderScheduleCoordinator.swift; sourceTree = ""; }; FEF7F33F2AFEA0C200F793FC /* blogging-prompts-bloganuary.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "blogging-prompts-bloganuary.json"; sourceTree = ""; }; - FEF9A74A2BA1CF370014045E /* ReaderTopicChangeObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTopicChangeObserver.swift; sourceTree = ""; }; FEFA263D26C58427009CCB7E /* ShareAppTextActivityItemSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareAppTextActivityItemSourceTests.swift; sourceTree = ""; }; FEFA6AC22A83F4BE004EE5E6 /* PostHelper+JetpackSocial.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PostHelper+JetpackSocial.swift"; sourceTree = ""; }; FEFA6AC52A86824A004EE5E6 /* PostHelperJetpackSocialTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostHelperJetpackSocialTests.swift; sourceTree = ""; }; @@ -18574,7 +18571,6 @@ F5E29037243FAB0300C19CA5 /* FilterTableData.swift */, 837779B02B55D44B00FDA1AC /* EmptyFilterView.swift */, 837779B32B55E93800FDA1AC /* EmptyFilterViewModel.swift */, - FEF9A74A2BA1CF370014045E /* ReaderTopicChangeObserver.swift */, ); path = Filter; sourceTree = ""; @@ -23176,7 +23172,6 @@ E1B912831BB01047003C25B9 /* PeopleRoleBadgeLabel.swift in Sources */, 40FC6B7F2072E3EC00B9A1CD /* ActivityDetailViewController.swift in Sources */, E16FB7E11F8B5D7D0004DD9F /* WebViewControllerConfiguration.swift in Sources */, - FEF9A74B2BA1CF370014045E /* ReaderTopicChangeObserver.swift in Sources */, 98B3FA8421C05BDC00148DD4 /* ViewMoreRow.swift in Sources */, 8BADF16524801BCE005AD038 /* ReaderWebView.swift in Sources */, C3C21EB928385EC8002296E2 /* RemoteSiteDesigns.swift in Sources */, @@ -24930,7 +24925,6 @@ FABB22A12602FC2C00C8785C /* MediaHost+Blog.swift in Sources */, FABB22A22602FC2C00C8785C /* PlanListRow.swift in Sources */, FABB22A32602FC2C00C8785C /* SiteCreationWizard.swift in Sources */, - FEF9A74C2BA1CF370014045E /* ReaderTopicChangeObserver.swift in Sources */, FA4B203029A619130089FE68 /* BlazeFlowCoordinator.swift in Sources */, C7AFF875283C0ADC000E01DF /* UIApplication+Helpers.swift in Sources */, 0CEDBCFC2CB9A4BD00080019 /* FaviconService.swift in Sources */, From 582842b77d557801ffe9738c9ac2dcbce89474ad Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:23:05 -0400 Subject: [PATCH 14/55] Remove EmptyFilterView --- .../Reader/Filter/EmptyFilterView.swift | 95 ---------------- .../Reader/Filter/EmptyFilterViewModel.swift | 107 ------------------ WordPress/WordPress.xcodeproj/project.pbxproj | 12 -- 3 files changed, 214 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Filter/EmptyFilterView.swift delete mode 100644 WordPress/Classes/ViewRelated/Reader/Filter/EmptyFilterViewModel.swift diff --git a/WordPress/Classes/ViewRelated/Reader/Filter/EmptyFilterView.swift b/WordPress/Classes/ViewRelated/Reader/Filter/EmptyFilterView.swift deleted file mode 100644 index 0e2fad210ba6..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Filter/EmptyFilterView.swift +++ /dev/null @@ -1,95 +0,0 @@ - -class EmptyFilterView: UIView { - - private let viewModel: EmptyFilterViewModel - - private lazy var stackView: UIStackView = { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.axis = .vertical - $0.spacing = 16.0 - let subviews = { - viewModel.filterType == .blog ? - [titleLabel, bodyLabel, searchButton] : - [titleLabel, bodyLabel, suggestedButton, searchButton] - }() - $0.addArrangedSubviews(subviews) - $0.setCustomSpacing(8.0, after: titleLabel) - $0.setCustomSpacing(32.0, after: bodyLabel) - return $0 - }(UIStackView()) - - private lazy var titleLabel: UILabel = { - $0.text = viewModel.title - $0.textAlignment = .center - $0.font = .preferredFont(forTextStyle: .title3).semibold() - return $0 - }(UILabel()) - - private lazy var bodyLabel: UILabel = { - $0.text = viewModel.body - $0.numberOfLines = 0 - $0.textAlignment = .center - $0.font = .preferredFont(forTextStyle: .callout) - $0.textColor = .secondaryLabel - return $0 - }(UILabel()) - - private var buttonConfig: UIButton.Configuration { - var config = UIButton.Configuration.plain() - config.contentInsets = NSDirectionalEdgeInsets(top: 12.0, leading: 0.0, bottom: 12.0, trailing: 0.0) - config.titleTextAttributesTransformer = .transformer(with: .preferredFont(forTextStyle: .body).semibold()) - return config - } - - private lazy var suggestedButton: UIButton = { - $0.configuration = buttonConfig - $0.setTitle(viewModel.suggestedButton, for: .normal) - $0.setTitleColor(.systemBackground, for: .normal) - $0.setTitleColor(.systemBackground.withAlphaComponent(0.7), for: .highlighted) - $0.backgroundColor = .label - $0.layer.cornerRadius = 5.0 - $0.addTarget(self, action: #selector(suggestedButtonTapped), for: .touchUpInside) - return $0 - }(UIButton()) - - private lazy var searchButton: UIButton = { - $0.configuration = buttonConfig - $0.setTitle(viewModel.searchButton, for: .normal) - $0.setTitleColor(.label, for: .normal) - $0.setTitleColor(.label.withAlphaComponent(0.7), for: .highlighted) - $0.backgroundColor = .systemBackground - $0.layer.cornerRadius = 5.0 - $0.layer.borderWidth = 1.0 - $0.layer.borderColor = UIColor.tertiaryLabel.cgColor - $0.addTarget(self, action: #selector(searchButtonTapped), for: .touchUpInside) - return $0 - }(UIButton()) - - init(viewModel: EmptyFilterViewModel) { - self.viewModel = viewModel - super.init(frame: .zero) - setupViews() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func setupViews() { - addSubview(stackView) - NSLayoutConstraint.activate([ - stackView.topAnchor.constraint(equalTo: safeTopAnchor, constant: 12.0), - stackView.leadingAnchor.constraint(equalTo: safeLeadingAnchor, constant: 16.0), - stackView.trailingAnchor.constraint(equalTo: safeTrailingAnchor, constant: -16.0), - ]) - } - - @objc private func suggestedButtonTapped() { - viewModel.suggestedButtonTap?() - } - - @objc private func searchButtonTapped() { - viewModel.searchButtonTap?() - } - -} diff --git a/WordPress/Classes/ViewRelated/Reader/Filter/EmptyFilterViewModel.swift b/WordPress/Classes/ViewRelated/Reader/Filter/EmptyFilterViewModel.swift deleted file mode 100644 index c91d39b74924..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Filter/EmptyFilterViewModel.swift +++ /dev/null @@ -1,107 +0,0 @@ - -struct EmptyFilterViewModel { - - let filterType: FilterType - let suggestedButtonTap: (() -> Void)? - let searchButtonTap: (() -> Void)? - - var title: String { filterType.title } - var body: String { filterType.body } - var suggestedButton: String { filterType.suggestedButton } - var searchButton: String { filterType.searchButton } - - enum FilterType { - case blog - case tag - - var title: String { - switch self { - case .blog: - return Strings.blogTitle - case .tag: - return Strings.tagsTitle - } - } - - var body: String { - switch self { - case .blog: - return Strings.blogBody - case .tag: - return Strings.tagsBody - } - } - - var suggestedButton: String { - switch self { - case .blog: - return "" - case .tag: - return Strings.tagsSuggestedButton - } - } - - var searchButton: String { - switch self { - case .blog: - return Strings.blogSearchButton - case .tag: - return Strings.tagsSearchButton - } - } - } - - struct Strings { - static let tagsTitle = NSLocalizedString( - "reader.filterSheet.empty.tags.title", - value: "No tags", - comment: "Title for an empty filter sheet on the Reader for tags" - ) - static let blogTitle = NSLocalizedString( - "reader.filterSheet.empty.blogs.title", - value: "No blog subscriptions", - comment: "Title for an empty filter sheet on the Reader for blogs" - ) - static let tagsBody = NSLocalizedString( - "reader.filterSheet.empty.tags.body", - value: "Subscribe to a tag and you’ll be able to see the best posts from it here.", - comment: "Body text for an empty filter sheet on the Reader for tags" - ) - static let blogBody = NSLocalizedString( - "reader.filterSheet.empty.blogs.body", - value: "Subscribe to blogs in Discover and you’ll see their latest posts here. Or search for a blog that you like already.", - comment: "Body text for an empty filter sheet on the Reader for blogs" - ) - static let tagsSuggestedButton = NSLocalizedString( - "reader.filterSheet.empty.tags.suggested", - value: "Suggested tags", - comment: "Suggested tags button text for an empty filter sheet on the Reader" - ) - static let tagsSearchButton = NSLocalizedString( - "reader.filterSheet.empty.tags.subscribe", - value: "Subscribe to a tag", - comment: "Subscribe to a tag button text for an empty filter sheet on the Reader" - ) - static let blogSearchButton = NSLocalizedString( - "reader.filterSheet.empty.blogs.search", - value: "Search for a blog", - comment: "Search blogs button text for an empty filter sheet on the Reader" - ) - } -} - -extension FilterProvider { - - var filterType: EmptyFilterViewModel.FilterType { - switch reuseIdentifier { - case ReuseIdentifiers.blogs: - return .blog - case ReuseIdentifiers.tags: - return .tag - default: - assertionFailure("Unknown filter type, add an empty filter view for it if necessary") - return .blog - } - } - -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 86722888a1ae..09072fab74a0 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2423,10 +2423,6 @@ 836498CE281735CC00A2C170 /* BloggingPromptsHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 836498CD281735CC00A2C170 /* BloggingPromptsHeaderView.swift */; }; 836498CF281735CC00A2C170 /* BloggingPromptsHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 836498CD281735CC00A2C170 /* BloggingPromptsHeaderView.swift */; }; 8370D10A11FA499A009D650F /* WPTableViewActivityCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8370D10911FA499A009D650F /* WPTableViewActivityCell.m */; }; - 837779B12B55D44B00FDA1AC /* EmptyFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 837779B02B55D44B00FDA1AC /* EmptyFilterView.swift */; }; - 837779B22B55D44B00FDA1AC /* EmptyFilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 837779B02B55D44B00FDA1AC /* EmptyFilterView.swift */; }; - 837779B42B55E93800FDA1AC /* EmptyFilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 837779B32B55E93800FDA1AC /* EmptyFilterViewModel.swift */; }; - 837779B52B55E93800FDA1AC /* EmptyFilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 837779B32B55E93800FDA1AC /* EmptyFilterViewModel.swift */; }; 83796699299C048E004A92B9 /* DashboardJetpackInstallCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83796698299C048E004A92B9 /* DashboardJetpackInstallCardCell.swift */; }; 8379669A299C048E004A92B9 /* DashboardJetpackInstallCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83796698299C048E004A92B9 /* DashboardJetpackInstallCardCell.swift */; }; 8379669C299C0C44004A92B9 /* JetpackRemoteInstallTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8379669B299C0C44004A92B9 /* JetpackRemoteInstallTableViewCell.swift */; }; @@ -7974,8 +7970,6 @@ 836498CD281735CC00A2C170 /* BloggingPromptsHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloggingPromptsHeaderView.swift; sourceTree = ""; }; 8370D10811FA499A009D650F /* WPTableViewActivityCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WPTableViewActivityCell.h; sourceTree = ""; }; 8370D10911FA499A009D650F /* WPTableViewActivityCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPTableViewActivityCell.m; sourceTree = ""; }; - 837779B02B55D44B00FDA1AC /* EmptyFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyFilterView.swift; sourceTree = ""; }; - 837779B32B55E93800FDA1AC /* EmptyFilterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyFilterViewModel.swift; sourceTree = ""; }; 83796698299C048E004A92B9 /* DashboardJetpackInstallCardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardJetpackInstallCardCell.swift; sourceTree = ""; }; 8379669B299C0C44004A92B9 /* JetpackRemoteInstallTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackRemoteInstallTableViewCell.swift; sourceTree = ""; }; 8379669E299D51EC004A92B9 /* JetpackPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackPlugin.swift; sourceTree = ""; }; @@ -18569,8 +18563,6 @@ F5E29035243E4F5F00C19CA5 /* FilterProvider.swift */, F5E6312A243BC83E0088229D /* FilterSheetViewController.swift */, F5E29037243FAB0300C19CA5 /* FilterTableData.swift */, - 837779B02B55D44B00FDA1AC /* EmptyFilterView.swift */, - 837779B32B55E93800FDA1AC /* EmptyFilterViewModel.swift */, ); path = Filter; sourceTree = ""; @@ -21454,7 +21446,6 @@ D87A329620ABD60700F4726F /* ReaderTableContent.swift in Sources */, 738B9A5A21B85CF20005062B /* SiteCreationHeaderData.swift in Sources */, 594399931B45091000539E21 /* WPAuthTokenIssueSolver.m in Sources */, - 837779B12B55D44B00FDA1AC /* EmptyFilterView.swift in Sources */, 0CB4057929C8DDEC008EED0A /* BlogDashboardPersonalizationViewModel.swift in Sources */, 8BDA5A6B247C2EAF00AB124C /* ReaderDetailViewController.swift in Sources */, 3F8B313025D1D652005A2903 /* HomeWidgetThisWeekData.swift in Sources */, @@ -21663,7 +21654,6 @@ B089140D27E1255D00CF468B /* SiteIntentViewController.swift in Sources */, 82FC61271FA8ADAD00A1757E /* WPStyleGuide+Activity.swift in Sources */, 98BFF57E23984345008A1DCB /* AllTimeWidgetStats.swift in Sources */, - 837779B42B55E93800FDA1AC /* EmptyFilterViewModel.swift in Sources */, 7E40713A2372AD54003627FA /* GutenbergFilesAppMediaSource.swift in Sources */, B532D4EC199D4357006E4DF6 /* NoteBlockTextTableViewCell.swift in Sources */, 8B15CDAB27EB89AD00A75749 /* BlogDashboardPostsParser.swift in Sources */, @@ -25882,7 +25872,6 @@ FABB25422602FC2C00C8785C /* AnimatedImageCache.swift in Sources */, FABB25432602FC2C00C8785C /* PostListFilterSettings.swift in Sources */, FABB25442602FC2C00C8785C /* FooterTextContent.swift in Sources */, - 837779B22B55D44B00FDA1AC /* EmptyFilterView.swift in Sources */, 4A072CD329093704006235BE /* AsyncBlockOperation.swift in Sources */, FABB25462602FC2C00C8785C /* PostFeaturedImageCell.m in Sources */, FABB25472602FC2C00C8785C /* WPException.m in Sources */, @@ -25926,7 +25915,6 @@ 0CD9CCA02AD73A560044A33C /* PostSearchViewController.swift in Sources */, FABB25682602FC2C00C8785C /* StatsInsightsStore.swift in Sources */, FABB25692602FC2C00C8785C /* MenuItemPagesViewController.m in Sources */, - 837779B52B55E93800FDA1AC /* EmptyFilterViewModel.swift in Sources */, 4A9314E52979FA4700360232 /* PostCategory+Creation.swift in Sources */, F4B0F4842ADED9B5003ABC61 /* DomainsService+AllDomains.swift in Sources */, FA6402D229C325C1007A235C /* MovedToJetpackEventsTracker.swift in Sources */, From 4c1296d85a407d51efdf7e9e17e07e71d3e64481 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:24:58 -0400 Subject: [PATCH 15/55] Remove FilterSheetViewController --- .../Filter/FilterSheetViewController.swift | 311 ------------------ .../Reader/Filter/FilterTableData.swift | 96 ------ WordPress/WordPress.xcodeproj/project.pbxproj | 12 - 3 files changed, 419 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Filter/FilterSheetViewController.swift delete mode 100644 WordPress/Classes/ViewRelated/Reader/Filter/FilterTableData.swift diff --git a/WordPress/Classes/ViewRelated/Reader/Filter/FilterSheetViewController.swift b/WordPress/Classes/ViewRelated/Reader/Filter/FilterSheetViewController.swift deleted file mode 100644 index 532b9e9e47ae..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Filter/FilterSheetViewController.swift +++ /dev/null @@ -1,311 +0,0 @@ -import WordPressUI -import WordPressFlux - -protocol FilterSheetViewControllerDelegate { - func didSelectTopic(_ topic: ReaderAbstractTopic) - func didTapEdit() -} - -class FilterSheetViewController: UIViewController { - - // MARK: Properties - - private let viewTitle: String - - private let filterProvider: FilterProvider - - // closure that's called when a filter item is selected. - private let changedFilter: (ReaderAbstractTopic) -> Void - - private let onEditButtonTap: (UIViewController) -> Void - - private var receipt: Receipt? - - private var dataSource: FilterTableViewDataSource? { - didSet { - tableView.dataSource = dataSource - tableView.reloadData() - } - } - - // MARK: Views - - lazy var tableView: UITableView = { - let tableView = UITableView() - tableView.tableFooterView = UIView() // To hide the separators for empty cells - tableView.separatorStyle = .none - tableView.delegate = self - return tableView - }() - - private lazy var emptyView = EmptyFilterView( - viewModel: EmptyFilterViewModel( - filterType: filterProvider.filterType, - suggestedButtonTap: { [weak self] in - self?.tappedSuggestedButton() - }, searchButtonTap: { [weak self] in - self?.tappedEmptyAddButton() - } - ) - ) - - private lazy var ghostableTableView: UITableView = { - let tableView = UITableView() - tableView.allowsSelection = false - tableView.isScrollEnabled = false - tableView.separatorStyle = .none - return tableView - }() - - private lazy var headerLabelView: UIView = { - let labelView = UIView() - let label = UILabel() - label.font = HeaderConstants.font - label.adjustsFontForContentSizeCategory = true - label.text = viewTitle - label.translatesAutoresizingMaskIntoConstraints = false - labelView.addSubview(label) - labelView.pinSubviewToAllEdges(label, insets: HeaderConstants.insets) - return labelView - }() - - private lazy var editButton: UIButton = { - let button = UIButton(type: .system) - button.setTitle(Strings.manageButtonTitle, for: .normal) - button.tintColor = .label - button.titleLabel?.adjustsFontForContentSizeCategory = true - - button.configuration = .plain() - button.configuration?.contentInsets = .init(top: HeaderConstants.insets.top, - leading: HeaderConstants.insets.left, - bottom: HeaderConstants.insets.bottom, - trailing: HeaderConstants.insets.right) - button.addTarget(self, action: #selector(didTapEditButton), for: .touchUpInside) - - return button - }() - - private lazy var headerStackView: UIStackView = { - let stack = UIStackView(arrangedSubviews: [ - headerLabelView, - UIView(), - editButton - ]) - - stack.axis = .horizontal - stack.translatesAutoresizingMaskIntoConstraints = false - return stack - }() - - private lazy var stackView: UIStackView = { - let stack = UIStackView(arrangedSubviews: [ - headerStackView, - tableView, - ghostableTableView, - emptyView - ]) - - stack.setCustomSpacing(HeaderConstants.spacing, after: headerStackView) - stack.axis = .vertical - stack.translatesAutoresizingMaskIntoConstraints = false - return stack - }() - - // MARK: Methods - - init(filter: FilterProvider, - viewTitle: String? = nil, - changedFilter: @escaping (ReaderAbstractTopic) -> Void, - onEditButtonTap: @escaping (UIViewController) -> Void) { - let defaultTitle = filter.section == .sites ? Strings.blogFilterTitle : Strings.tagFilterTitle - self.viewTitle = viewTitle ?? defaultTitle - self.filterProvider = filter - self.changedFilter = changedFilter - self.onEditButtonTap = onEditButtonTap - super.init(nibName: nil, bundle: nil) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - configureViews() - configureObservers() - refresh() - } -} - -// MARK: - Private Helpers - -private extension FilterSheetViewController { - - struct HeaderConstants { - static let spacing: CGFloat = 16 - static let insets: UIEdgeInsets = UIEdgeInsets(top: 0, left: 18, bottom: 0, right: 18) - static let font = WPStyleGuide.fontForTextStyle(.headline, fontWeight: .semibold) - } - - struct Strings { - static let blogFilterTitle = NSLocalizedString( - "reader.filterSheet.byBlog.title", - value: "Filter by blog", - comment: "Title for a filter sheet on the Reader to filter the stream by blog" - ) - static let tagFilterTitle = NSLocalizedString( - "reader.filterSheet.byTag.title", - value: "Filter by tag", - comment: "Title for a filter sheet on the Reader to filter the stream by tag" - ) - static let selectInterestsTitle = NSLocalizedString( - "reader.filterSheet.select.tags.title", - value: "Suggested tags", - comment: "Screen title. Reader select interests title label text." - ) - static let selectInterestsLoading = NSLocalizedString( - "reader.filterSheet.select.tags.following", - value: "Following new tags...", - comment: "Label displayed to the user while loading their selected interests" - ) - static let manageButtonTitle = NSLocalizedString( - "reader.filterSheet.button.manage", - value: "Manage", - comment: "Title for a button that allows user to manage their subscribed list from the filter sheet" - ) - } - - func configureViews() { - // configure table view - tableView.register(filterProvider.cellClass, forCellReuseIdentifier: filterProvider.reuseIdentifier) - - // configure content view - view.addSubview(stackView) - view.pinSubviewToAllEdges(stackView) - } - - func configureObservers() { - receipt = filterProvider.onChange { [weak self] in - guard let self else { - return - } - - self.dataSource = FilterTableViewDataSource(data: self.filterProvider.items, - reuseIdentifier: self.filterProvider.reuseIdentifier) - if !self.filterProvider.state.isReady { - /// Loading state - self.emptyView.isHidden = true - self.tableView.isHidden = true - self.headerLabelView.isHidden = false - self.updateGhostableTableViewOptions(cellClass: self.filterProvider.cellClass, - identifier: self.filterProvider.reuseIdentifier) - } else { - /// Finished loading - self.ghostableTableView.stopGhostAnimation() - self.ghostableTableView.isHidden = true - - let isEmpty = self.filterProvider.items.isEmpty - self.emptyView.isHidden = !isEmpty - self.tableView.isHidden = isEmpty - self.headerLabelView.isHidden = isEmpty - } - } - } - - func tappedSuggestedButton() { - guard filterProvider.filterType == .tag else { - assertionFailure("Unsupported suggested button action") - return - } - let configuration = ReaderSelectInterestsConfiguration( - title: Strings.selectInterestsTitle, - subtitle: nil, - buttonTitle: nil, - loading: Strings.selectInterestsLoading - ) - let controller = ReaderSelectInterestsViewController(configuration: configuration) - - controller.didSaveInterests = { [weak self] _ in - self?.dismiss(animated: true, completion: nil) - self?.refresh() - } - - let navController = UINavigationController(rootViewController: controller) - navController.modalPresentationStyle = .formSheet - - present(navController, animated: true, completion: nil) - } - - func tappedEmptyAddButton() { - switch filterProvider.filterType { - case .blog: - let searchController = ReaderSearchViewController.controller() - searchController.onViewWillDisappear = { [weak self] in - self?.refresh() - } - let navController = UINavigationController(rootViewController: searchController) - navController.modalPresentationStyle = .formSheet - present(navController, animated: true) - break - case .tag: - // Go to the Filter management view - didTapEditButton() - } - } - - func refresh() { - filterProvider.refresh() - } - - func updateGhostableTableViewOptions(cellClass: UITableViewCell.Type, identifier: String) { - ghostableTableView.register(cellClass, forCellReuseIdentifier: identifier) - let ghostOptions = GhostOptions(displaysSectionHeader: false, reuseIdentifier: identifier, rowsPerSection: [15]) - ghostableTableView.removeGhostContent() - ghostableTableView.isHidden = false - ghostableTableView.displayGhostContent(options: ghostOptions, style: GhostStyle()) - } - - @objc - func didTapEditButton() { - onEditButtonTap(self) - } -} - -// MARK: - UITableViewDelegate - -extension FilterSheetViewController: UITableViewDelegate { - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - if let topic = dataSource?.data[indexPath.row].topic { - changedFilter(topic) - } - } -} - -// MARK: - SceneDelegate - -extension FilterSheetViewController: ScenePresenterDelegate { - func didDismiss(presenter: ScenePresenter) { - refresh() - } -} - -// MARK: - DrawerPresentable - -extension FilterSheetViewController: DrawerPresentable { - func handleDismiss() { - WPAnalytics.track(.readerFilterSheetDismissed) - } - - var scrollableView: UIScrollView? { - return tableView - } - - var collapsedHeight: DrawerHeight { - if traitCollection.verticalSizeClass == .compact { - return .maxHeight - } else { - return .contentHeight(0) - } - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/Filter/FilterTableData.swift b/WordPress/Classes/ViewRelated/Reader/Filter/FilterTableData.swift deleted file mode 100644 index 45b38fea601c..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Filter/FilterTableData.swift +++ /dev/null @@ -1,96 +0,0 @@ -import WordPressUI - -struct TableDataItem { - let topic: ReaderAbstractTopic - let configure: (UITableViewCell) -> Void -} - -class FilterTableViewDataSource: NSObject, UITableViewDataSource { - - let data: [TableDataItem] - private let reuseIdentifier: String - - init(data: [TableDataItem], reuseIdentifier: String) { - self.data = data - self.reuseIdentifier = reuseIdentifier - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return data.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let item = data[indexPath.row] - let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) - - item.configure(cell) - - return cell - } -} - -class SiteTableViewCell: UITableViewCell, GhostableView { - - enum Constants { - static let preferredSiteIconSize = CGSize(width: 40.0, height: 40.0) - static let textLabelCharacterWidth = 40 // Number of characters in text label - static let detailLabelCharacterWidth = 80 // Number of characters in detail label - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .subtitle, reuseIdentifier: reuseIdentifier) - configureStyle() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func configureStyle() { - imageView?.image = .siteIconPlaceholder - imageView?.layer.masksToBounds = true - imageView?.contentMode = .scaleAspectFill - - textLabel?.font = UIFont.preferredFont(forTextStyle: .callout) - textLabel?.textColor = .label - - detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .footnote) - detailTextLabel?.textColor = .secondaryLabel - } - - override func layoutSubviews() { - super.layoutSubviews() - - guard let imageView else { - return - } - - // check if the image has a larger width than intended. - let extraWidth = imageView.frame.width - Constants.preferredSiteIconSize.width - - // when there's extra width, UITableViewCell automatically adjusts the label position. - // let's shift the labels back by that much. - if extraWidth > 0 { - // Note: for RTL, we want to make sure that we're shifting the views to the correct direction. - textLabel?.frame.origin.x += traitCollection.layoutDirection == .leftToRight ? (-1 * extraWidth) : extraWidth - detailTextLabel?.frame.origin.x += traitCollection.layoutDirection == .leftToRight ? (-1 * extraWidth) : extraWidth - - if traitCollection.layoutDirection == .rightToLeft { - imageView.frame.origin.x += extraWidth - } - } - - imageView.frame.size = Constants.preferredSiteIconSize - imageView.layer.cornerRadius = imageView.frame.height * 0.5 - } - - func ghostAnimationWillStart() { - contentView.subviews.forEach { view in - view.isGhostableDisabled = true - } - textLabel?.text = String(repeating: " ", count: Constants.textLabelCharacterWidth) - textLabel?.isGhostableDisabled = false - detailTextLabel?.text = String(repeating: " ", count: Constants.detailLabelCharacterWidth) - detailTextLabel?.isGhostableDisabled = false - } -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 09072fab74a0..49fe13df685d 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -4073,8 +4073,6 @@ F5E032E62408D537003AF350 /* ActionSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E032E32408D537003AF350 /* ActionSheetViewController.swift */; }; F5E032E82408D537003AF350 /* BottomSheetPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E032E52408D537003AF350 /* BottomSheetPresentationController.swift */; }; F5E29036243E4F5F00C19CA5 /* FilterProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E29035243E4F5F00C19CA5 /* FilterProvider.swift */; }; - F5E29038243FAB0300C19CA5 /* FilterTableData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E29037243FAB0300C19CA5 /* FilterTableData.swift */; }; - F5E6312B243BC83E0088229D /* FilterSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E6312A243BC83E0088229D /* FilterSheetViewController.swift */; }; F5EF481723ABCAD8004C3532 /* MainShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74337EDC20054D5500777997 /* MainShareViewController.swift */; }; F5EF481823ABCAE0004C3532 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 740C7C4E202F4CD6001C31B0 /* MainInterface.storyboard */; }; F913BB0E24B3C58B00C19032 /* EventLoggingDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F913BB0D24B3C58B00C19032 /* EventLoggingDelegate.swift */; }; @@ -4746,7 +4744,6 @@ FABB22A52602FC2C00C8785C /* SignupEpilogueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98656BD72037A1770079DE67 /* SignupEpilogueViewController.swift */; }; FABB22A82602FC2C00C8785C /* TableDataCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 738B9A4A21B85CF20005062B /* TableDataCoordinator.swift */; }; FABB22A92602FC2C00C8785C /* SettingsMultiTextViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B541276A1C0F7D610015CA80 /* SettingsMultiTextViewController.m */; }; - FABB22AA2602FC2C00C8785C /* FilterSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E6312A243BC83E0088229D /* FilterSheetViewController.swift */; }; FABB22AB2602FC2C00C8785C /* Plan.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F2787A21BC1A48008B4DB5 /* Plan.swift */; }; FABB22AC2602FC2C00C8785C /* DiscussionSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5AC00671BE3C4E100F8E7C3 /* DiscussionSettingsViewController.swift */; }; FABB22AD2602FC2C00C8785C /* GutenbergSuggestionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0637542253E7E7A00FD45D2 /* GutenbergSuggestionsViewController.swift */; }; @@ -5063,7 +5060,6 @@ FABB24252602FC2C00C8785C /* WPContentSyncHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D6C4B051B603E03005E3C43 /* WPContentSyncHelper.swift */; }; FABB24262602FC2C00C8785C /* SiteAssemblyStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73C8F05F21BEED9100DDDF7E /* SiteAssemblyStep.swift */; }; FABB24272602FC2C00C8785C /* SiteSettingsViewController+Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82C420751FE44BD900CFB15B /* SiteSettingsViewController+Swift.swift */; }; - FABB24282602FC2C00C8785C /* FilterTableData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E29037243FAB0300C19CA5 /* FilterTableData.swift */; }; FABB24292602FC2C00C8785C /* ReaderGapMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = E6A3384B1BB08E3F00371587 /* ReaderGapMarker.m */; }; FABB242A2602FC2C00C8785C /* Pattern.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CFC1561E0AC8FF001DF9E9 /* Pattern.swift */; }; FABB242B2602FC2C00C8785C /* ShareExtensionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 930F09161C7D110E00995926 /* ShareExtensionService.swift */; }; @@ -9533,8 +9529,6 @@ F5E032E32408D537003AF350 /* ActionSheetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetViewController.swift; sourceTree = ""; }; F5E032E52408D537003AF350 /* BottomSheetPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomSheetPresentationController.swift; sourceTree = ""; }; F5E29035243E4F5F00C19CA5 /* FilterProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterProvider.swift; sourceTree = ""; }; - F5E29037243FAB0300C19CA5 /* FilterTableData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterTableData.swift; sourceTree = ""; }; - F5E6312A243BC83E0088229D /* FilterSheetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterSheetViewController.swift; sourceTree = ""; }; F75F3A68DCE524B4BAFCE76E /* Pods-WordPressDraftActionExtension.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressDraftActionExtension.release-alpha.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPressDraftActionExtension/Pods-WordPressDraftActionExtension.release-alpha.xcconfig"; sourceTree = ""; }; F85B762A18D018C22DF2A40D /* Pods-JetpackShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JetpackShareExtension.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-JetpackShareExtension/Pods-JetpackShareExtension.debug.xcconfig"; sourceTree = ""; }; F913BB0D24B3C58B00C19032 /* EventLoggingDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventLoggingDelegate.swift; sourceTree = ""; }; @@ -18561,8 +18555,6 @@ isa = PBXGroup; children = ( F5E29035243E4F5F00C19CA5 /* FilterProvider.swift */, - F5E6312A243BC83E0088229D /* FilterSheetViewController.swift */, - F5E29037243FAB0300C19CA5 /* FilterTableData.swift */, ); path = Filter; sourceTree = ""; @@ -22001,7 +21993,6 @@ FA73D7E52798765B00DF24B3 /* HomeSiteHeaderViewController.swift in Sources */, B541276B1C0F7D610015CA80 /* SettingsMultiTextViewController.m in Sources */, 3F810A5A2616870C00ADDCC2 /* UnifiedPrologueIntroContentView.swift in Sources */, - F5E6312B243BC83E0088229D /* FilterSheetViewController.swift in Sources */, 8BC81D6527CFC0DA0057F790 /* BlogDashboardState.swift in Sources */, E6F2788021BC1A4A008B4DB5 /* Plan.swift in Sources */, B5AC00681BE3C4E100F8E7C3 /* DiscussionSettingsViewController.swift in Sources */, @@ -22526,7 +22517,6 @@ 82C420761FE44BD900CFB15B /* SiteSettingsViewController+Swift.swift in Sources */, 803BB983295957F600B3F6D6 /* MySitesCoordinator+RootViewPresenter.swift in Sources */, 8BBC778B27B5531700DBA087 /* BlogDashboardPersistence.swift in Sources */, - F5E29038243FAB0300C19CA5 /* FilterTableData.swift in Sources */, 0CE538D02B0E317000834BA2 /* StockPhotosWelcomeView.swift in Sources */, E6A3384C1BB08E3F00371587 /* ReaderGapMarker.m in Sources */, 011896A529D5B72500D34BA9 /* DomainsDashboardCoordinator.swift in Sources */, @@ -24925,7 +24915,6 @@ FABB22A82602FC2C00C8785C /* TableDataCoordinator.swift in Sources */, 0C02E6C62BE3B6E30055F0F6 /* PostTrashedOverlayView.swift in Sources */, FABB22A92602FC2C00C8785C /* SettingsMultiTextViewController.m in Sources */, - FABB22AA2602FC2C00C8785C /* FilterSheetViewController.swift in Sources */, FABB22AB2602FC2C00C8785C /* Plan.swift in Sources */, FABB22AC2602FC2C00C8785C /* DiscussionSettingsViewController.swift in Sources */, FABB22AD2602FC2C00C8785C /* GutenbergSuggestionsViewController.swift in Sources */, @@ -25471,7 +25460,6 @@ FABB24272602FC2C00C8785C /* SiteSettingsViewController+Swift.swift in Sources */, 3FFDEF8F29187F1200B625CE /* MigrationHeaderConfiguration.swift in Sources */, 0CEA55532BC55940008D0FE5 /* WPInstrumentation.swift in Sources */, - FABB24282602FC2C00C8785C /* FilterTableData.swift in Sources */, FABB24292602FC2C00C8785C /* ReaderGapMarker.m in Sources */, FABB242A2602FC2C00C8785C /* Pattern.swift in Sources */, FABB242B2602FC2C00C8785C /* ShareExtensionService.swift in Sources */, From 5b437857f4946900dc85d73918d6beb807ae8bd8 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:27:57 -0400 Subject: [PATCH 16/55] Remove FilterProvider --- .../Reader/Filter/FilterProvider.swift | 399 ------------------ ...TabBarController+ReaderTabNavigation.swift | 1 + WordPress/WordPress.xcodeproj/project.pbxproj | 14 - 3 files changed, 1 insertion(+), 413 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Filter/FilterProvider.swift diff --git a/WordPress/Classes/ViewRelated/Reader/Filter/FilterProvider.swift b/WordPress/Classes/ViewRelated/Reader/Filter/FilterProvider.swift deleted file mode 100644 index 9050fb814f10..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Filter/FilterProvider.swift +++ /dev/null @@ -1,399 +0,0 @@ -import WordPressFlux - -class FilterProvider: NSObject, Identifiable, Observable, FilterTabBarItem { - - let id: UUID = UUID() - - enum FilterProviderError: Error { - case notAuthorized - } - - enum State { - case loading - case ready([TableDataItem]) - case error(Error) - - var isReady: Bool { - switch self { - case .ready: - return true - case .error, .loading: - return false - } - } - } - - var title: String { - return titleFunc(state) - } - - var state: State = .loading { - didSet { - emitChange() - } - } - - var items: [TableDataItem] { - switch state { - case .loading, .error: - return [] - case .ready(let items): - return FilterProvider.filterItems(items, siteType: siteType) - } - } - - /// Closure block that's responsible for populating the items for this `FilterProvider`. - /// - /// The `localOnly` parameter provides information for the closure on whether the fetch should happen - /// locally or remotely, but whether this parameter is honored or not depends on the actual implementation. - /// - /// - Parameters: - /// - localOnly: Specifies whether the fetch process should happen locally or remotely. - /// - completion: The closure to be called once the fetching process completes. - typealias Provider = (_ localOnly: Bool, _ completion: @escaping (Result<[TableDataItem], Error>) -> Void) -> Void - - let accessibilityIdentifier: String - let cellClass: UITableViewCell.Type - let reuseIdentifier: String - let emptyTitle: String - let section: ReaderManageScenePresenter.TabbedSection - let siteType: SiteOrganizationType? - - /// Notifies when there are changes made to the `ReaderAbstractTopic` model depended by this provider. - let observer: ReaderTopicObserving? - - private let titleFunc: (State?) -> String - private let provider: Provider - - let changeDispatcher = Dispatcher() - - init(title: @escaping (State?) -> String, - accessibilityIdentifier: String, - cellClass: UITableViewCell.Type, - reuseIdentifier: String, - emptyTitle: String, - section: ReaderManageScenePresenter.TabbedSection, - provider: @escaping Provider, - siteType: SiteOrganizationType? = nil, - observer: ReaderTopicObserving? = nil) { - - titleFunc = title - self.accessibilityIdentifier = accessibilityIdentifier - self.cellClass = cellClass - self.reuseIdentifier = reuseIdentifier - self.emptyTitle = emptyTitle - self.section = section - self.provider = provider - self.siteType = siteType - self.observer = observer - - super.init() - self.observer?.delegate = self - } - - func refresh(localOnly: Bool = false) { - state = .loading - provider(localOnly) { [weak self] result in - switch result { - case .success(let items): - self?.state = .ready(items) - case .failure(let error): - self?.state = .error(error) - } - } - } - - struct ReuseIdentifiers { - static let blogs = "blogs" - static let tags = "tags" - } -} - -extension FilterProvider: ReaderTopicObserverDelegate { - func readerTopicDidChange() { - // TODO: Revisit and think of better approach. - // IMPORTANT — This is a workaround. At this stage, we need to ensure that the data is *only* refreshed - // from the local store, because pulling from remote will trigger the observer again and causing a loop! - refresh(localOnly: true) - } -} - -extension FilterProvider { - static func == (lhs: FilterProvider, rhs: FilterProvider) -> Bool { - return lhs.title == rhs.title - } -} - -extension FilterProvider { - - static func filterItems(_ items: [TableDataItem], siteType: SiteOrganizationType?) -> [TableDataItem] { - // If a site type is specified, filter items by it. - // Otherwise, just return all items. - guard let siteType = siteType else { - return items - } - - var filteredItems = [TableDataItem]() - - for item in items { - if let topic = item.topic as? ReaderSiteTopic, - topic.organizationType == siteType { - filteredItems.append(item) - } - } - - return filteredItems - } - -} - -extension ReaderSiteTopic { - - static func filterProvider(for siteType: SiteOrganizationType?) -> FilterProvider { - let titleFunction: (FilterProvider.State?) -> String = { state in - switch state { - case .loading, .error, .none: - return Strings.unnumberedFilterTitle - case .ready(let items): - let filteredItems = FilterProvider.filterItems(items, siteType: siteType) - return String(format: filteredItems.count == 1 ? Strings.singularFilterTitle : Strings.pluralFilterTitle, filteredItems.count) - } - } - - let emptyTitle = NSLocalizedString( - "reader.no.blog.title", - value: "Add a blog", - comment: "No Tags View Button Label" - ) - - return FilterProvider(title: titleFunction, - accessibilityIdentifier: "SitesFilterTab", - cellClass: SiteTableViewCell.self, - reuseIdentifier: FilterProvider.ReuseIdentifiers.blogs, - emptyTitle: emptyTitle, - section: .sites, - provider: tableProvider, - siteType: siteType, - observer: ReaderTopicChangeObserver()) - } - - private static func tableProvider(localOnly: Bool = false, - completion: @escaping (Result<[TableDataItem], Error>) -> Void) { - let completionBlock: (Result<[ReaderSiteTopic], Error>) -> Void = { result in - let itemResult = result.map { sites in - sites.map { topic in - return TableDataItem(topic: topic, configure: { cell in - cell.imageView?.downloadSiteIcon(at: topic.siteBlavatar) - cell.textLabel?.text = topic.title - cell.detailTextLabel?.text = topic.siteURL - addUnseenPostCount(topic, with: cell) - }) - } - } - completion(itemResult) - } - - // User needs to be logged in to follow sites. - guard ReaderHelpers.isLoggedIn() else { - completionBlock(.failure(FilterProvider.FilterProviderError.notAuthorized)) - return - } - - fetchStoredFollowedSites(completion: completionBlock) - - if !localOnly { - fetchFollowedSites(completion: completionBlock) - } - } - - /// Fetch sites from remote service - /// - private static func fetchFollowedSites(completion: @escaping (Result<[ReaderSiteTopic], Error>) -> Void) { - let siteService = ReaderTopicService(coreDataStack: ContextManager.shared) - - siteService.fetchAllFollowedSites(success: { - let sites = (try? ReaderAbstractTopic.lookupAllSites(in: ContextManager.shared.mainContext)) ?? [] - completion(.success(sites)) - }, failure: { error in - DDLogError("Could not sync sites: \(String(describing: error))") - let remoteServiceError = NSError(domain: WordPressComRestApiErrorDomain, code: -1, userInfo: nil) - completion(.failure(error ?? remoteServiceError)) - }) - } - - /// Fetch sites from Core Data - /// - private static func fetchStoredFollowedSites(completion: @escaping (Result<[ReaderSiteTopic], Error>) -> Void) { - let sites = (try? ReaderAbstractTopic.lookupAllSites(in: ContextManager.shared.mainContext)) ?? [] - completion(.success(sites)) - } - - /// Adds a custom accessory view displaying the unseen post count. - /// - private static func addUnseenPostCount(_ topic: ReaderSiteTopic, with cell: UITableViewCell) { - - // Always reset first. - cell.accessoryView = nil - - guard topic.unseenCount > 0 else { - return - } - - // Create background view - let unseenCountView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: UnseenCountConstants.viewSize)) - unseenCountView.layer.cornerRadius = UnseenCountConstants.cornerRadius - unseenCountView.backgroundColor = .tertiarySystemFill - - // Create count label - let countLabel = UILabel() - countLabel.font = WPStyleGuide.subtitleFont() - countLabel.textColor = .label - countLabel.backgroundColor = .clear - countLabel.text = topic.unseenCount.abbreviatedString() - - let accessibilityFormat = topic.unseenCount == 1 ? UnseenCountConstants.singularUnseen : UnseenCountConstants.pluralUnseen - countLabel.accessibilityLabel = String(format: accessibilityFormat, topic.unseenCount) - - countLabel.sizeToFit() - - // Resize views - unseenCountView.frame.size.width = max(countLabel.frame.width + UnseenCountConstants.labelPadding, UnseenCountConstants.viewSize) - countLabel.center = unseenCountView.center - - // Display in cell's accessory view - unseenCountView.addSubview(countLabel) - cell.accessoryView = unseenCountView - } - - private struct UnseenCountConstants { - static let cornerRadius: CGFloat = 15 - static let viewSize: CGFloat = 30 - static let labelPadding: CGFloat = 20 - static let singularUnseen = NSLocalizedString("%1$d unseen post", comment: "Format string for single unseen post count. The %1$d is a placeholder for the count.") - static let pluralUnseen = NSLocalizedString("%1$d unseen posts", comment: "Format string for plural unseen posts count. The %1$d is a placeholder for the count.") - } - - private struct Strings { - static let unnumberedFilterTitle = NSLocalizedString( - "reader.navigation.filter.blog.unspecified", - value: "Blogs", - comment: """ - Button title to filter the Reader stream by blog. - This is displayed when we don't know the number of blogs yet. - """ - ) - - static let singularFilterTitle = NSLocalizedString( - "reader.navigation.filter.blog.singular", - value: "%1$d Blog", - comment: """ - Singular button title to filter the Reader stream by blog. - %1$d is a placeholder for the number of blogs. - """ - ) - - static let pluralFilterTitle = NSLocalizedString( - "reader.navigation.filter.blog.plural", - value: "%1$d Blogs", - comment: """ - Plural button title to filter the Reader stream by blog. - %1$d is a placeholder for the number of blogs. - """ - ) - } - -} - -extension ReaderTagTopic { - - static func filterProvider() -> FilterProvider { - let titleFunction: (FilterProvider.State?) -> String = { state in - switch state { - case .loading, .error, .none: - return Strings.unnumberedFilterTitle - case .ready(let items): - return String(format: items.count == 1 ? Strings.singularFilterTitle : Strings.pluralFilterTitle, items.count) - } - } - - let emptyTitle = NSLocalizedString( - "reader.no.tags.title", - value: "Add a tag", - comment: "No Tags View Button Label" - ) - - return FilterProvider(title: titleFunction, - accessibilityIdentifier: "TagsFilterTab", - cellClass: UITableViewCell.self, - reuseIdentifier: FilterProvider.ReuseIdentifiers.tags, - emptyTitle: emptyTitle, - section: .tags, - provider: tableProvider, - observer: ReaderTopicChangeObserver()) - } - - private static func tableProvider(localOnly: Bool = false, - completion: @escaping (Result<[TableDataItem], Error>) -> Void) { - fetchFollowedTags(completion: { result in - let itemResult = result.map { tags in - tags.map { topic in - return TableDataItem(topic: topic, configure: { (cell) in - cell.textLabel?.text = topic.slugForDisplay - cell.textLabel?.font = UIFont.preferredFont(forTextStyle: .callout) - }) - } - } - completion(itemResult) - }) - } - - static var tagsFetchRequest: NSFetchRequest { - let fetchRequest = NSFetchRequest(entityName: "ReaderTagTopic") - // Only show following tags, even if the user is logged out - fetchRequest.predicate = NSPredicate(format: "following == YES AND showInMenu == YES AND type == 'tag'") - - fetchRequest.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare))] - return fetchRequest - } - - private static func fetchFollowedTags(completion: @escaping (Result<[ReaderTagTopic], Error>) -> Void) { - do { - guard let topics = try ContextManager.sharedInstance().mainContext.fetch(tagsFetchRequest) as? [ReaderTagTopic] else { - return - } - completion(.success(topics)) - } catch { - DDLogError("There was a problem fetching followed tags. \(error.localizedDescription)") - completion(.failure(error)) - } - } - - private struct Strings { - static let unnumberedFilterTitle = NSLocalizedString( - "reader.navigation.filter.tag.unnumbered", - value: "Tags", - comment: """ - Button title to filter the Reader stream by tag. - This is displayed when we don't know the number of tags yet. - """ - ) - - static let singularFilterTitle = NSLocalizedString( - "reader.navigation.filter.tag.singular", - value: "%1$d Tag", - comment: """ - Singular button title to filter the Reader stream by tag. - %1$d is a placeholder for the number of tags. - """ - ) - - static let pluralFilterTitle = NSLocalizedString( - "reader.navigation.filter.tag.plural", - value: "%1$d Tags", - comment: """ - Plural button title to filter the Reader stream by tag. - %1$d is a placeholder for the number of tags. - """ - ) - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift index 0de7988c1b40..b636da73e8d1 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift @@ -26,6 +26,7 @@ extension WPTabBarController { case .search: showReaderDetails(ReaderSearchViewController.controller()) case .subscriptions: + // TODO: (reader) implement using the new screen ReaderManageScenePresenter().present(on: self, selectedSection: .sites, animated: true, completion: nil) case let .post(postID, siteID, isFeed): showReaderDetails(ReaderDetailViewController.controllerWithPostID(NSNumber(value: postID), siteID: NSNumber(value: siteID), isFeed: isFeed)) diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 49fe13df685d..48cf7ccbd628 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -4072,7 +4072,6 @@ F5E032DB24088F44003AF350 /* UIView+SpringAnimations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E032DA24088F44003AF350 /* UIView+SpringAnimations.swift */; }; F5E032E62408D537003AF350 /* ActionSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E032E32408D537003AF350 /* ActionSheetViewController.swift */; }; F5E032E82408D537003AF350 /* BottomSheetPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E032E52408D537003AF350 /* BottomSheetPresentationController.swift */; }; - F5E29036243E4F5F00C19CA5 /* FilterProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E29035243E4F5F00C19CA5 /* FilterProvider.swift */; }; F5EF481723ABCAD8004C3532 /* MainShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74337EDC20054D5500777997 /* MainShareViewController.swift */; }; F5EF481823ABCAE0004C3532 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 740C7C4E202F4CD6001C31B0 /* MainInterface.storyboard */; }; F913BB0E24B3C58B00C19032 /* EventLoggingDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F913BB0D24B3C58B00C19032 /* EventLoggingDelegate.swift */; }; @@ -4723,7 +4722,6 @@ FABB228D2602FC2C00C8785C /* VideoUploadProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F126FDFD20A33BDB0010EB6E /* VideoUploadProcessor.swift */; }; FABB228E2602FC2C00C8785C /* PeopleCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E166FA1A1BB0656B00374B5B /* PeopleCellViewModel.swift */; }; FABB22902602FC2C00C8785C /* RegisterDomainDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 436D56192117312700CEAA33 /* RegisterDomainDetailsViewController.swift */; }; - FABB22912602FC2C00C8785C /* FilterProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E29035243E4F5F00C19CA5 /* FilterProvider.swift */; }; FABB22922602FC2C00C8785C /* DomainCreditEligibilityChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 027AC51C227896540033E56E /* DomainCreditEligibilityChecker.swift */; }; FABB22932602FC2C00C8785C /* SiteSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83FEFC7411FF6C5A0078B462 /* SiteSettingsViewController.m */; }; FABB22942602FC2C00C8785C /* WPStyleGuide+Comments.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56994441B7A7EF200FF26FA /* WPStyleGuide+Comments.swift */; }; @@ -9528,7 +9526,6 @@ F5E032DA24088F44003AF350 /* UIView+SpringAnimations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+SpringAnimations.swift"; sourceTree = ""; }; F5E032E32408D537003AF350 /* ActionSheetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetViewController.swift; sourceTree = ""; }; F5E032E52408D537003AF350 /* BottomSheetPresentationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomSheetPresentationController.swift; sourceTree = ""; }; - F5E29035243E4F5F00C19CA5 /* FilterProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterProvider.swift; sourceTree = ""; }; F75F3A68DCE524B4BAFCE76E /* Pods-WordPressDraftActionExtension.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressDraftActionExtension.release-alpha.xcconfig"; path = "../Pods/Target Support Files/Pods-WordPressDraftActionExtension/Pods-WordPressDraftActionExtension.release-alpha.xcconfig"; sourceTree = ""; }; F85B762A18D018C22DF2A40D /* Pods-JetpackShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JetpackShareExtension.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-JetpackShareExtension/Pods-JetpackShareExtension.debug.xcconfig"; sourceTree = ""; }; F913BB0D24B3C58B00C19032 /* EventLoggingDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventLoggingDelegate.swift; sourceTree = ""; }; @@ -17004,7 +17001,6 @@ 9870EF7827866DCE00F3BB54 /* Comments */, 5D08B8FD19647C0800D5B381 /* Controllers */, 8BADF16324801B4B005AD038 /* Detail */, - F597768C243E1E140062BAD1 /* Filter */, E6D2E16A1B8B41AC0000ED14 /* Headers */, F5A738C1244DF92300EDE065 /* Manage */, 32E1BFD824A66801007A08F0 /* Select Interests */, @@ -18551,14 +18547,6 @@ path = Scheduling; sourceTree = ""; }; - F597768C243E1E140062BAD1 /* Filter */ = { - isa = PBXGroup; - children = ( - F5E29035243E4F5F00C19CA5 /* FilterProvider.swift */, - ); - path = Filter; - sourceTree = ""; - }; F5A34D0525DF2F7700C9654B /* Fonts */ = { isa = PBXGroup; children = ( @@ -21953,7 +21941,6 @@ F4EDAA4C29A516EA00622D3D /* ReaderPostService.swift in Sources */, 01C4472C2BE4F8560006F787 /* StatsGhostLineChartCell.swift in Sources */, 019105862BE8BD6000CDFB16 /* StatsGhostSingleValueCell.swift in Sources */, - F5E29036243E4F5F00C19CA5 /* FilterProvider.swift in Sources */, F4FE743429C3767300AC2729 /* AddressTableViewCell+ViewModel.swift in Sources */, 027AC51D227896540033E56E /* DomainCreditEligibilityChecker.swift in Sources */, 83FEFC7611FF6C5A0078B462 /* SiteSettingsViewController.m in Sources */, @@ -24881,7 +24868,6 @@ FABB22902602FC2C00C8785C /* RegisterDomainDetailsViewController.swift in Sources */, 1770BD0E267A368100D5F8C0 /* BloggingRemindersPushPromptViewController.swift in Sources */, C7BB601A2863AF9700748FD9 /* QRLoginProtocols.swift in Sources */, - FABB22912602FC2C00C8785C /* FilterProvider.swift in Sources */, 0C7E09212A4286A00052324C /* PostMetaButton.m in Sources */, FABB22922602FC2C00C8785C /* DomainCreditEligibilityChecker.swift in Sources */, FABB22932602FC2C00C8785C /* SiteSettingsViewController.m in Sources */, From a480923c7b1a02f57ea8235605903955bf071c9b Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:28:43 -0400 Subject: [PATCH 17/55] Remove TabbedViewController --- .../Reader/Manage/TabbedViewController.swift | 97 ------------------- ...TabBarController+ReaderTabNavigation.swift | 2 +- WordPress/WordPress.xcodeproj/project.pbxproj | 6 -- 3 files changed, 1 insertion(+), 104 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Manage/TabbedViewController.swift diff --git a/WordPress/Classes/ViewRelated/Reader/Manage/TabbedViewController.swift b/WordPress/Classes/ViewRelated/Reader/Manage/TabbedViewController.swift deleted file mode 100644 index 84eb5c627fd1..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Manage/TabbedViewController.swift +++ /dev/null @@ -1,97 +0,0 @@ -import UIKit - -/// Contains multiple Child View Controllers with a Filter Tab Bar to switch between them. -class TabbedViewController: UIViewController { - - struct TabbedItem: FilterTabBarItem { - let title: String - let viewController: UIViewController - let accessibilityIdentifier: String - } - - /// The selected view controller - var selection: Int { - set { - tabBar.setSelectedIndex(newValue) - } - get { - return tabBar.selectedIndex - } - } - - private let items: [TabbedItem] - private let onDismiss: (() -> Void)? - - private lazy var tabBar: FilterTabBar = { - let bar = FilterTabBar() - WPStyleGuide.configureFilterTabBar(bar) - bar.tabSizingStyle = .equalWidths - bar.translatesAutoresizingMaskIntoConstraints = false - bar.addTarget(self, action: #selector(changedItem(sender:)), for: .valueChanged) - return bar - }() - - private lazy var stackView: UIStackView = { - let stackView = UIStackView() - stackView.translatesAutoresizingMaskIntoConstraints = false - stackView.axis = .vertical - return stackView - }() - - private weak var child: UIViewController? { - didSet { - oldValue?.remove() - - if let child = child, child.parent != self { - addChild(child) - stackView.addArrangedSubview(child.view) - child.didMove(toParent: self) - } - } - } - - init(items: [TabbedItem], onDismiss: (() -> Void)? = nil) { - self.items = items - self.onDismiss = onDismiss - super.init(nibName: nil, bundle: nil) - tabBar.items = items - - navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(donePressed)) - - stackView.addArrangedSubview(tabBar) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - @objc func donePressed() { - onDismiss?() - dismiss(animated: true, completion: nil) - } - - override func viewDidLoad() { - super.viewDidLoad() - - view.backgroundColor = .systemBackground - - view.addSubview(stackView) - NSLayoutConstraint.activate([ - stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), - stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor), - stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor), - stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor) - ]) - setInitialChild() - } - - private func setInitialChild() { - let initialItem: TabbedItem = items[selection] - child = initialItem.viewController - } - - @objc func changedItem(sender: FilterTabBar) { - let item = items[sender.selectedIndex] - child = item.viewController - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift index b636da73e8d1..3d085d5b1615 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift @@ -27,7 +27,7 @@ extension WPTabBarController { showReaderDetails(ReaderSearchViewController.controller()) case .subscriptions: // TODO: (reader) implement using the new screen - ReaderManageScenePresenter().present(on: self, selectedSection: .sites, animated: true, completion: nil) + break case let .post(postID, siteID, isFeed): showReaderDetails(ReaderDetailViewController.controllerWithPostID(NSNumber(value: postID), siteID: NSNumber(value: siteID), isFeed: isFeed)) case let .postURL(url): diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 48cf7ccbd628..ae47b0ec5264 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -4057,7 +4057,6 @@ F5A738BF244DF7E400EDE065 /* ReaderTagsTableViewController+Cells.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5A738BE244DF7E400EDE065 /* ReaderTagsTableViewController+Cells.swift */; }; F5A738C3244E7A6F00EDE065 /* ReaderTagsTableViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5A738C2244E7A6F00EDE065 /* ReaderTagsTableViewModel.swift */; }; F5B8A60F23CE56A1001B7359 /* PreviewDeviceSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5B8A60E23CE56A1001B7359 /* PreviewDeviceSelectionViewController.swift */; }; - F5B9151F244653C100179876 /* TabbedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5B9151E244653C100179876 /* TabbedViewController.swift */; }; F5B9152124465FB400179876 /* ReaderTagsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5B9152024465FB400179876 /* ReaderTagsTableViewController.swift */; }; F5B9D7F0245BA938002BB2C7 /* FancyAlertViewController+CreateButtonAnnouncement.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5B9D7EF245BA938002BB2C7 /* FancyAlertViewController+CreateButtonAnnouncement.swift */; }; F5C00EAE242179780047846F /* WeekdaysHeaderViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5C00EAD242179780047846F /* WeekdaysHeaderViewTests.swift */; }; @@ -4534,7 +4533,6 @@ FABB219D2602FC2C00C8785C /* Page+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59E1D46D1CEF77B500126697 /* Page+CoreDataProperties.swift */; }; FABB219F2602FC2C00C8785C /* RegisterDomainSectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43D74AD520FB5AD5004AD934 /* RegisterDomainSectionHeaderView.swift */; }; FABB21A02602FC2C00C8785C /* WPStyleGuide+Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 986DD19B218D002500D28061 /* WPStyleGuide+Stats.swift */; }; - FABB21A12602FC2C00C8785C /* TabbedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5B9151E244653C100179876 /* TabbedViewController.swift */; }; FABB21A22602FC2C00C8785C /* Blog+Quota.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF00889A204DF3ED007CCE66 /* Blog+Quota.swift */; }; FABB21A32602FC2C00C8785C /* CommentsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C533CF340E6D3ADA000C3DE8 /* CommentsViewController.m */; }; FABB21A42602FC2C00C8785C /* SiteSettingsViewController+SiteManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAFF153C1C98962E007D1C90 /* SiteSettingsViewController+SiteManagement.swift */; }; @@ -9513,7 +9511,6 @@ F5A738BE244DF7E400EDE065 /* ReaderTagsTableViewController+Cells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ReaderTagsTableViewController+Cells.swift"; sourceTree = ""; }; F5A738C2244E7A6F00EDE065 /* ReaderTagsTableViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTagsTableViewModel.swift; sourceTree = ""; }; F5B8A60E23CE56A1001B7359 /* PreviewDeviceSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewDeviceSelectionViewController.swift; sourceTree = ""; }; - F5B9151E244653C100179876 /* TabbedViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabbedViewController.swift; sourceTree = ""; }; F5B9152024465FB400179876 /* ReaderTagsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTagsTableViewController.swift; sourceTree = ""; }; F5B9D7EF245BA938002BB2C7 /* FancyAlertViewController+CreateButtonAnnouncement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FancyAlertViewController+CreateButtonAnnouncement.swift"; sourceTree = ""; }; F5C00EAD242179780047846F /* WeekdaysHeaderViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeekdaysHeaderViewTests.swift; sourceTree = ""; }; @@ -18563,7 +18560,6 @@ F5B9152024465FB400179876 /* ReaderTagsTableViewController.swift */, F5A738BE244DF7E400EDE065 /* ReaderTagsTableViewController+Cells.swift */, F5A738BC244DF75400EDE065 /* OffsetTableViewHandler.swift */, - F5B9151E244653C100179876 /* TabbedViewController.swift */, F5A738C2244E7A6F00EDE065 /* ReaderTagsTableViewModel.swift */, F52CACC9244FA7AA00661380 /* ReaderManageScenePresenter.swift */, FA7F92B725E61C7E00502D2A /* ReaderTagsFooter.swift */, @@ -21616,7 +21612,6 @@ C373D6E728045281008F8C26 /* SiteIntentData.swift in Sources */, 43D74AD620FB5AD5004AD934 /* RegisterDomainSectionHeaderView.swift in Sources */, 986DD19C218D002500D28061 /* WPStyleGuide+Stats.swift in Sources */, - F5B9151F244653C100179876 /* TabbedViewController.swift in Sources */, FF00889B204DF3ED007CCE66 /* Blog+Quota.swift in Sources */, C533CF350E6D3ADA000C3DE8 /* CommentsViewController.m in Sources */, 0C1531FE2AE17140003CDE13 /* PostSearchViewModel+Highlighter.swift in Sources */, @@ -24555,7 +24550,6 @@ FABB219D2602FC2C00C8785C /* Page+CoreDataProperties.swift in Sources */, FABB219F2602FC2C00C8785C /* RegisterDomainSectionHeaderView.swift in Sources */, FABB21A02602FC2C00C8785C /* WPStyleGuide+Stats.swift in Sources */, - FABB21A12602FC2C00C8785C /* TabbedViewController.swift in Sources */, FABB21A22602FC2C00C8785C /* Blog+Quota.swift in Sources */, FABB21A32602FC2C00C8785C /* CommentsViewController.m in Sources */, FABB21A42602FC2C00C8785C /* SiteSettingsViewController+SiteManagement.swift in Sources */, From 06e4a0018377cba82a18689fd3791996aa61b0e0 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:31:08 -0400 Subject: [PATCH 18/55] Remove ReaderManageScenePresenter --- .../Utility/Analytics/WPAnalyticsEvent.swift | 10 -- .../Manage/ReaderManageScenePresenter.swift | 110 ------------------ .../Reader/ReaderDiscoverViewController.swift | 12 -- WordPress/WordPress.xcodeproj/project.pbxproj | 6 - 4 files changed, 138 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift diff --git a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift index 57c099fcf559..8dedc2b19b6c 100644 --- a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift +++ b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift @@ -324,10 +324,6 @@ import Foundation case readerDiscoverChannelSelected case readerDiscoverEditInterestsTapped - // Reader: Manage - case readerManageViewDisplayed - case readerManageViewDismissed - // App Settings case settingsDidChange @@ -1188,12 +1184,6 @@ import Foundation case .readerDiscoverEditInterestsTapped: return "reader_discover_edit_interests_tapped" - // Reader: Manage View - case .readerManageViewDisplayed: - return "reader_manage_view_displayed" - case .readerManageViewDismissed: - return "reader_manage_view_dismissed" - // App Settings case .settingsDidChange: return "settings_did_change" diff --git a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift b/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift deleted file mode 100644 index 7d0d5632cd9f..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift +++ /dev/null @@ -1,110 +0,0 @@ -extension NSNotification.Name { - static let readerManageControllerWasDismissed = NSNotification.Name("ReaderManageControllerWasDismissed") -} - -class ReaderManageScenePresenter { - - enum TabbedSection { - case tags - case sites - - private func makeViewController() -> UIViewController { - switch self { - case .tags: - return ReaderTagsTableViewController(style: .plain) - case .sites: - return ReaderFollowedSitesViewController.controller(showsAccessoryFollowButtons: true, showsSectionTitle: false) - } - } - - var tabbedItem: TabbedViewController.TabbedItem { - switch self { - case .tags: - return TabbedViewController.TabbedItem(title: NSLocalizedString("reader.manage.tab.tags", - value: "Tags", - comment: "Manage tags tab title"), - viewController: makeViewController(), - accessibilityIdentifier: "FollowedTags") - case .sites: - return TabbedViewController.TabbedItem(title: NSLocalizedString("reader.manage.tab.blogs", - value: "Blogs", - comment: "Manage blogs tab title"), - viewController: makeViewController(), - accessibilityIdentifier: "FollowedSites") - } - } - } - - weak var presentedViewController: UIViewController? - - private let sections: [TabbedSection] - private var selectedSection: TabbedSection? - private weak var delegate: ScenePresenterDelegate? - - init(sections tabbedSections: [TabbedSection] = [TabbedSection.tags, TabbedSection.sites], - selected: TabbedSection? = nil, - sceneDelegate: ScenePresenterDelegate? = nil) { - sections = tabbedSections - selectedSection = selected - delegate = sceneDelegate - } - - /// Presents the Reader Manage flow. - /// - /// - Parameters: - /// - viewController: The presenting view controller. - /// - selectedSection: The section that will be selected by default. - /// - animated: Whether the presentation should be animated. - /// - completion: Closure that's called after the user dismisses the Manage flow. - func present(on viewController: UIViewController, - selectedSection: TabbedSection?, - animated: Bool, - completion: (() -> Void)?) { - guard presentedViewController == nil else { - completion?() - return - } - - self.selectedSection = selectedSection - let navigationController = UINavigationController(rootViewController: makeViewController()) - presentedViewController = navigationController - viewController.present(navigationController, animated: true, completion: nil) - - WPAnalytics.track(.readerManageViewDisplayed) - } -} - -// MARK: - ScenePresenter - -extension ReaderManageScenePresenter: ScenePresenter { - func present(on viewController: UIViewController, animated: Bool, completion: (() -> Void)?) { - present(on: viewController, selectedSection: nil, animated: animated, completion: completion) - } -} - -// MARK: - Private helpers - -private extension ReaderManageScenePresenter { - func makeViewController() -> TabbedViewController { - let tabbedItems = sections.map({ item in - return item.tabbedItem - }) - - let tabbedViewController = TabbedViewController(items: tabbedItems, onDismiss: { [weak self] in - guard let self else { - return - } - - self.delegate?.didDismiss(presenter: self) - NotificationCenter.default.post(name: .readerManageControllerWasDismissed, object: self) - WPAnalytics.track(.readerManageViewDismissed) - }) - tabbedViewController.title = NSLocalizedString("Manage", comment: "Title for the Reader Manage screen.") - if let section = selectedSection, let firstSelection = sections.firstIndex(of: section) { - tabbedViewController.selection = firstSelection - } - - return tabbedViewController - } - -} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift index a5f33cd4495b..46607dc88ab7 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift @@ -318,13 +318,6 @@ private class ReaderDiscoverStreamViewController: ReaderStreamViewController { } private func addObservers() { - - // Listens for when the reader manage view controller is dismissed - NotificationCenter.default.addObserver(self, - selector: #selector(manageControllerWasDismissed(_:)), - name: .readerManageControllerWasDismissed, - object: nil) - // Listens for when a site is blocked NotificationCenter.default.addObserver(self, selector: #selector(siteBlocked(_:)), @@ -332,11 +325,6 @@ private class ReaderDiscoverStreamViewController: ReaderStreamViewController { object: nil) } - @objc private func manageControllerWasDismissed(_ notification: Foundation.Notification) { - shouldForceRefresh = true - self.displaySelectInterestsIfNeeded() - } - /// Update the post card when a site is blocked from post details. /// @objc private func siteBlocked(_ notification: Foundation.Notification) { diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index ae47b0ec5264..23f8d5281d6d 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -4037,7 +4037,6 @@ F511F8A42356A4F400895E73 /* PublishSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F511F8A32356A4F400895E73 /* PublishSettingsViewController.swift */; }; F515E9662654312200848251 /* Noticons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F5A34D0C25DF2F7700C9654B /* Noticons.ttf */; }; F515E9672654312200848251 /* Noticons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F5A34D0C25DF2F7700C9654B /* Noticons.ttf */; }; - F52CACCA244FA7AA00661380 /* ReaderManageScenePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F52CACC9244FA7AA00661380 /* ReaderManageScenePresenter.swift */; }; F532AE1C253E55D40013B42E /* CreateButtonActionSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = F532AE1B253E55D40013B42E /* CreateButtonActionSheet.swift */; }; F53FF3AA23EA725C001AD596 /* SiteDetailsSiteIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F53FF3A923EA725C001AD596 /* SiteDetailsSiteIconView.swift */; }; F543AF5723A84E4D0022F595 /* PublishSettingsControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F543AF5623A84E4D0022F595 /* PublishSettingsControllerTests.swift */; }; @@ -5097,7 +5096,6 @@ FABB24552602FC2C00C8785C /* WPStyleGuide+Suggestions.m in Sources */ = {isa = PBXBuildFile; fileRef = 31EC15071A5B6675009FC8B3 /* WPStyleGuide+Suggestions.m */; }; FABB24562602FC2C00C8785C /* SiteStatsInsightsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9865257C2194D77E0078B916 /* SiteStatsInsightsViewModel.swift */; }; FABB24572602FC2C00C8785C /* CheckmarkTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F74696A209EFD0C0074D52B /* CheckmarkTableViewCell.swift */; }; - FABB24582602FC2C00C8785C /* ReaderManageScenePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F52CACC9244FA7AA00661380 /* ReaderManageScenePresenter.swift */; }; FABB24592602FC2C00C8785C /* MediaService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF5371621FDFF64F00619A3F /* MediaService.swift */; }; FABB245C2602FC2C00C8785C /* PluginStore+Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40ADB15420686870009A9161 /* PluginStore+Persistence.swift */; }; FABB245D2602FC2C00C8785C /* ResultsPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D83CA3A620842CD90060E310 /* ResultsPage.swift */; }; @@ -9491,7 +9489,6 @@ F4FF50EB2B4ECE320076DB0C /* MySiteOverlaysCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MySiteOverlaysCoordinator.swift; sourceTree = ""; }; F50B0E7A246212B8006601DD /* NoticeAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoticeAnimator.swift; sourceTree = ""; }; F511F8A32356A4F400895E73 /* PublishSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublishSettingsViewController.swift; sourceTree = ""; }; - F52CACC9244FA7AA00661380 /* ReaderManageScenePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderManageScenePresenter.swift; sourceTree = ""; }; F532AE1B253E55D40013B42E /* CreateButtonActionSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateButtonActionSheet.swift; sourceTree = ""; }; F53FF3A923EA725C001AD596 /* SiteDetailsSiteIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteDetailsSiteIconView.swift; sourceTree = ""; }; F543AF5623A84E4D0022F595 /* PublishSettingsControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublishSettingsControllerTests.swift; sourceTree = ""; }; @@ -18561,7 +18558,6 @@ F5A738BE244DF7E400EDE065 /* ReaderTagsTableViewController+Cells.swift */, F5A738BC244DF75400EDE065 /* OffsetTableViewHandler.swift */, F5A738C2244E7A6F00EDE065 /* ReaderTagsTableViewModel.swift */, - F52CACC9244FA7AA00661380 /* ReaderManageScenePresenter.swift */, FA7F92B725E61C7E00502D2A /* ReaderTagsFooter.swift */, FA7F92C925E61C9300502D2A /* ReaderTagsFooter.xib */, ); @@ -22568,7 +22564,6 @@ 31EC15081A5B6675009FC8B3 /* WPStyleGuide+Suggestions.m in Sources */, 9865257D2194D77F0078B916 /* SiteStatsInsightsViewModel.swift in Sources */, 9F74696B209EFD0C0074D52B /* CheckmarkTableViewCell.swift in Sources */, - F52CACCA244FA7AA00661380 /* ReaderManageScenePresenter.swift in Sources */, 0840513E2A4DDE3400A596E6 /* CompliancePopoverCoordinator.swift in Sources */, 0C878AD42CBEE0EB006CF997 /* ReaderBlockingHelper.swift in Sources */, FF5371631FDFF64F00619A3F /* MediaService.swift in Sources */, @@ -25509,7 +25504,6 @@ FACF66CE2ADD645C008C3E13 /* PostListHeaderView.swift in Sources */, 4A9672B22C813EEA00337176 /* WebAuthenticationPresentationAnchorProvider.swift in Sources */, FABB24572602FC2C00C8785C /* CheckmarkTableViewCell.swift in Sources */, - FABB24582602FC2C00C8785C /* ReaderManageScenePresenter.swift in Sources */, FABB24592602FC2C00C8785C /* MediaService.swift in Sources */, 839B150C2795DEE0009F5E77 /* UIView+Margins.swift in Sources */, FABB245C2602FC2C00C8785C /* PluginStore+Persistence.swift in Sources */, From d19b53fc159e086b11a83bf9df5bcf940e49db00 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:39:30 -0400 Subject: [PATCH 19/55] Fix build --- .../Utility/App Configuration/AppColor.swift | 3 +++ .../ReaderStreamViewController+Helper.swift | 10 ---------- .../CreateButtonCoordinator.swift | 18 ++---------------- 3 files changed, 5 insertions(+), 26 deletions(-) diff --git a/WordPress/Classes/Utility/App Configuration/AppColor.swift b/WordPress/Classes/Utility/App Configuration/AppColor.swift index 4d110b912672..d55f47c19ad4 100644 --- a/WordPress/Classes/Utility/App Configuration/AppColor.swift +++ b/WordPress/Classes/Utility/App Configuration/AppColor.swift @@ -137,6 +137,9 @@ struct UIAppColor { static let appBarTint = UIColor.systemOrange static let appBarText = UIColor.systemOrange + static let placeholderElement = UIColor(light: .systemGray5, dark: .systemGray4) + static let placeholderElementFaded: UIColor = UIColor(light: .systemGray6, dark: .systemGray5) + static let prologueBackground = UIColor(light: blue(.shade0), dark: .systemBackground) static let switchStyle: SwitchToggleStyle = SwitchToggleStyle(tint: Color(UIAppColor.brand)) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift index bdab328d515c..00640fd74daf 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift @@ -151,16 +151,6 @@ extension ReaderStreamViewController { } } -// MARK: - Tags Feed - -extension ReaderStreamViewController { - - var isTagsFeed: Bool { - contentType == .tags && readerTopic == nil - } - -} - // MARK: - Tracks extension ReaderStreamViewController { func trackSavedListAccessed() { diff --git a/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift b/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift index 5e5dc3437a4b..d2b131b5c74d 100644 --- a/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift +++ b/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift @@ -202,14 +202,7 @@ private extension CreateButtonCoordinator { let promptsHeaderView = BloggingPromptsHeaderView.view(for: prompt) promptsHeaderView.answerPromptHandler = { [weak self] in - let answerPromptEvent: WPAnalyticsEvent = { - if self?.source == Strings.readerSource { - return .readerCreateSheetAnswerPromptTapped - } - return .promptsBottomSheetAnswerPrompt - }() - - WPAnalytics.track(answerPromptEvent) + WPAnalytics.track(promptsBottomSheetAnswerPrompt) self?.viewController?.dismiss(animated: true) { let editor = EditPostViewController(blog: blog, prompt: prompt) editor.modalPresentationStyle = .fullScreen @@ -219,14 +212,7 @@ private extension CreateButtonCoordinator { } promptsHeaderView.infoButtonHandler = { [weak self] in - let helpEvent: WPAnalyticsEvent = { - if self?.source == Strings.readerSource { - return .readerCreateSheetPromptHelpTapped - } - return .promptsBottomSheetHelp - }() - - WPAnalytics.track(helpEvent) + WPAnalytics.track(promptsBottomSheetHelp) guard let presentedViewController = self?.viewController?.presentedViewController else { return } From b2e137ebd36e6beadfbc626f6f0726a41a41bdcd Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:43:04 -0400 Subject: [PATCH 20/55] Fix build --- .../Manage/OffsetTableViewHandler.swift | 2 ++ .../ReaderTagsTableViewController+Cells.swift | 2 ++ .../Manage/ReaderTagsTableViewModel.swift | 12 +++++++++++ .../ViewRelated/Reader/ReaderHelpers.swift | 4 ---- .../Reader/ReaderStreamViewController.swift | 21 +------------------ .../Reader/Tab Navigation/ReaderTabItem.swift | 21 ++----------------- .../CreateButtonCoordinator.swift | 4 ++-- 7 files changed, 21 insertions(+), 45 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/Manage/OffsetTableViewHandler.swift b/WordPress/Classes/ViewRelated/Reader/Manage/OffsetTableViewHandler.swift index 511f8dd3a985..d643a5464079 100644 --- a/WordPress/Classes/ViewRelated/Reader/Manage/OffsetTableViewHandler.swift +++ b/WordPress/Classes/ViewRelated/Reader/Manage/OffsetTableViewHandler.swift @@ -1,3 +1,5 @@ +import UIKit + // A table view handler offset by 1 (for Add a Topic in Reader Tags) class OffsetTableViewHandler: WPTableViewHandler { diff --git a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderTagsTableViewController+Cells.swift b/WordPress/Classes/ViewRelated/Reader/Manage/ReaderTagsTableViewController+Cells.swift index bfe715057802..49f221e9387f 100644 --- a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderTagsTableViewController+Cells.swift +++ b/WordPress/Classes/ViewRelated/Reader/Manage/ReaderTagsTableViewController+Cells.swift @@ -1,3 +1,5 @@ +import UIKit + extension ReaderTagsTableViewModel { func configure(cell: UITableViewCell, for topic: ReaderTagTopic?) { guard let topic = topic else { diff --git a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderTagsTableViewModel.swift b/WordPress/Classes/ViewRelated/Reader/Manage/ReaderTagsTableViewModel.swift index deae1d254ad8..d89f3c859b18 100644 --- a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderTagsTableViewModel.swift +++ b/WordPress/Classes/ViewRelated/Reader/Manage/ReaderTagsTableViewModel.swift @@ -1,3 +1,4 @@ +import UIKit import WordPressUI class ReaderTagsTableViewModel: NSObject { @@ -230,3 +231,14 @@ extension ReaderTagsTableViewModel { tableView?.flashRowAtIndexPath(tableViewHandler.adjustedToTable(indexPath: indexPath), scrollPosition: .middle, completion: {}) } } + +extension ReaderTagTopic { + static var tagsFetchRequest: NSFetchRequest { + let fetchRequest = NSFetchRequest(entityName: "ReaderTagTopic") + // Only show following tags, even if the user is logged out + fetchRequest.predicate = NSPredicate(format: "following == YES AND showInMenu == YES AND type == 'tag'") + + fetchRequest.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true, selector: #selector(NSString.localizedCaseInsensitiveCompare))] + return fetchRequest + } +} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift b/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift index 9bd2f36ce73e..f2029da118dd 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift @@ -677,10 +677,6 @@ extension ReaderHelpers { let savedPosition = min(mutableItems.count, defaultSavedItemPosition) mutableItems.insert(ReaderTabItem(ReaderContent(topic: nil, contentType: .saved)), at: savedPosition) - if RemoteFeatureFlag.readerTagsFeed.enabled() { - mutableItems.append(ReaderTabItem(ReaderContent(topic: nil, contentType: .tags))) - } - // in case of log in with a self hosted site, prepend a 'dummy' Following tab after Discover. if !isLoggedIn() { // to safeguard, ensure that there are items in the array before inserting. Otherwise, insert at index 0. diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 583dd7f1d685..ed347062b2c4 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -719,11 +719,6 @@ import AutomatticTracks /// Scrolls to the top of the list of posts. @objc func scrollViewToTop() { - guard !FeatureFlag.readerReset.enabled else { - return - } - - navigationMenuDelegate?.didScrollToTop() guard tableView.numberOfRows(inSection: .zero) > 0 else { tableView.setContentOffset(.zero, animated: true) return @@ -857,12 +852,6 @@ import AutomatticTracks /// Handles the user initiated pull to refresh action. /// @objc func handleRefresh(_ sender: UIRefreshControl) { - if contentType == .tags { - // NOTE: This is a workaround. - // Allow all tags to re-fetch posts. - tagStreamSyncTracker.removeAll() - } - if !canSync() { cleanupAfterSync() @@ -1414,10 +1403,6 @@ extension ReaderStreamViewController: WPTableViewHandlerDelegate { } } - func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { - navigationMenuDelegate?.scrollViewWillEndDragging(scrollView, withVelocity: velocity, targetContentOffset: targetContentOffset) - } - // MARK: - Fetched Results Related func managedObjectContext() -> NSManagedObjectContext { @@ -1907,7 +1892,7 @@ extension ReaderStreamViewController: NoResultsViewControllerDelegate { } if ReaderHelpers.topicIsFollowing(topic) { - navigationMenuDelegate?.didTapDiscoverBlogs() + // TODO: (reader) reimplement return } @@ -2055,10 +2040,6 @@ private extension ReaderStreamViewController { extension ReaderStreamViewController: UITableViewDelegate, JPScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { processJetpackBannerVisibility(scrollView) - - let velocity = tableView.panGestureRecognizer.velocity(in: tableView) - navigationMenuDelegate?.scrollViewDidScroll(scrollView, velocity: velocity) - $titleView.value?.updateAlpha(in: scrollView) } } diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift index e0c0fdac0fda..935432ce94dc 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift @@ -1,11 +1,8 @@ +import Foundation + struct ReaderTabItem: FilterTabBarItem, Hashable, Identifiable { var id: ReaderTabItem { self } - let shouldHideStreamFilters: Bool - let shouldHideSettingsButton: Bool - let shouldHideTagFilter: Bool - let shouldHideBlogFilter: Bool - let content: ReaderContent var accessibilityIdentifier: String { @@ -15,13 +12,6 @@ struct ReaderTabItem: FilterTabBarItem, Hashable, Identifiable { /// initialize with topic init(_ content: ReaderContent) { self.content = content - let filterableTopicTypes = [ReaderTopicType.following, .organization] - shouldHideStreamFilters = !filterableTopicTypes.contains(content.topicType) - && content.type != .selfHostedFollowing - && content.type != .tags - shouldHideSettingsButton = content.type == .selfHostedFollowing - shouldHideTagFilter = content.topicType == .organization || (content.type != .tags && RemoteFeatureFlag.readerTagsFeed.enabled()) - shouldHideBlogFilter = content.type == .tags } } @@ -44,8 +34,6 @@ extension ReaderTabItem { return Titles.followingTitle case .saved: return Titles.savedTitle - case .tags: - return Titles.tagsTitle default: return Titles.emptyTitle } @@ -67,11 +55,6 @@ extension ReaderTabItem { value: "Saved", comment: "Reader navigation menu item for the Saved filter" ) - static let tagsTitle = NSLocalizedString( - "reader.navigation.menu.tags", - value: "Your Tags", - comment: "Reader navigation menu item for the Tags filter" - ) static let emptyTitle = "" } } diff --git a/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift b/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift index d2b131b5c74d..ce93882ce30c 100644 --- a/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift +++ b/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonCoordinator.swift @@ -202,7 +202,7 @@ private extension CreateButtonCoordinator { let promptsHeaderView = BloggingPromptsHeaderView.view(for: prompt) promptsHeaderView.answerPromptHandler = { [weak self] in - WPAnalytics.track(promptsBottomSheetAnswerPrompt) + WPAnalytics.track(.promptsBottomSheetAnswerPrompt) self?.viewController?.dismiss(animated: true) { let editor = EditPostViewController(blog: blog, prompt: prompt) editor.modalPresentationStyle = .fullScreen @@ -212,7 +212,7 @@ private extension CreateButtonCoordinator { } promptsHeaderView.infoButtonHandler = { [weak self] in - WPAnalytics.track(promptsBottomSheetHelp) + WPAnalytics.track(.promptsBottomSheetHelp) guard let presentedViewController = self?.viewController?.presentedViewController else { return } From eb73861cad34f8075f02e72ff3459c8fe22038fe Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:46:01 -0400 Subject: [PATCH 21/55] Remove ReaderSpacerView --- .../ViewRelated/Reader/ReaderSpacerView.swift | 20 ------------------- WordPress/WordPress.xcodeproj/project.pbxproj | 6 ------ 2 files changed, 26 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderSpacerView.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderSpacerView.swift b/WordPress/Classes/ViewRelated/Reader/ReaderSpacerView.swift deleted file mode 100644 index 1ea0093c74f9..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderSpacerView.swift +++ /dev/null @@ -1,20 +0,0 @@ -import Foundation - -// A UIView used to defined a spacer to be used in a UIStackView when custom spacing -// is desired and the stack view's uniform spacing won't do the trick. -// Defining the spacing via intrinsicContentSize plays nice with the UIStackView's -// behavior of applying a 0 height constraint to hidden views. -class ReaderSpacerView: UIView { - - // Defined with var instead of let in order to set via User Defined Runtime Attributes in IB if needed. - @objc var space: Int = 8 { - didSet { - invalidateIntrinsicContentSize() - } - } - - override var intrinsicContentSize: CGSize { - return CGSize(width: space, height: space) - } - -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 23f8d5281d6d..7b04e24508ae 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -3660,7 +3660,6 @@ E66E2A661FE4311300788F22 /* SiteTagsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E66E2A641FE4311200788F22 /* SiteTagsViewController.swift */; }; E66E2A691FE432BC00788F22 /* TitleBadgeDisclosureCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E66E2A671FE432B900788F22 /* TitleBadgeDisclosureCell.swift */; }; E66E2A6A1FE432BC00788F22 /* TitleBadgeDisclosureCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = E66E2A681FE432BB00788F22 /* TitleBadgeDisclosureCell.xib */; }; - E66EB6F91C1B7A76003DABC5 /* ReaderSpacerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E66EB6F81C1B7A76003DABC5 /* ReaderSpacerView.swift */; }; E678FC151C76241000F55F55 /* WPStyleGuide+ApplicationStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = E678FC141C76241000F55F55 /* WPStyleGuide+ApplicationStyles.swift */; }; E6805D301DCD399600168E4F /* WPRichTextEmbed.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6805D2D1DCD399600168E4F /* WPRichTextEmbed.swift */; }; E6805D311DCD399600168E4F /* WPRichTextImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6805D2E1DCD399600168E4F /* WPRichTextImage.swift */; }; @@ -4925,7 +4924,6 @@ FABB23882602FC2C00C8785C /* WPStyleGuide+ApplicationStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = E678FC141C76241000F55F55 /* WPStyleGuide+ApplicationStyles.swift */; }; FABB23892602FC2C00C8785C /* FormattableUserContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EFF208520EAD918009C4699 /* FormattableUserContent.swift */; }; FABB238A2602FC2C00C8785C /* RegisterDomainDetailsViewController+HeaderFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 436D56162117312700CEAA33 /* RegisterDomainDetailsViewController+HeaderFooter.swift */; }; - FABB238B2602FC2C00C8785C /* ReaderSpacerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E66EB6F81C1B7A76003DABC5 /* ReaderSpacerView.swift */; }; FABB238D2602FC2C00C8785C /* WPStyleGuide+SiteCreation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B560914B208A671E00399AE4 /* WPStyleGuide+SiteCreation.swift */; }; FABB238E2602FC2C00C8785C /* NotificationSettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5EFB1C11B31B98E007608A3 /* NotificationSettingsService.swift */; }; FABB23922602FC2C00C8785C /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58C4EC9207C5E1900E32E4D /* UIImage+Extensions.swift */; }; @@ -9167,7 +9165,6 @@ E66E2A641FE4311200788F22 /* SiteTagsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SiteTagsViewController.swift; sourceTree = ""; }; E66E2A671FE432B900788F22 /* TitleBadgeDisclosureCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitleBadgeDisclosureCell.swift; sourceTree = ""; }; E66E2A681FE432BB00788F22 /* TitleBadgeDisclosureCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TitleBadgeDisclosureCell.xib; sourceTree = ""; }; - E66EB6F81C1B7A76003DABC5 /* ReaderSpacerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReaderSpacerView.swift; sourceTree = ""; }; E677A0001D3ECBD500536CF2 /* WordPress 51.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 51.xcdatamodel"; sourceTree = ""; }; E678FC141C76241000F55F55 /* WPStyleGuide+ApplicationStyles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "WPStyleGuide+ApplicationStyles.swift"; sourceTree = ""; }; E6805D2D1DCD399600168E4F /* WPRichTextEmbed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WPRichTextEmbed.swift; path = WPRichText/WPRichTextEmbed.swift; sourceTree = ""; }; @@ -13231,7 +13228,6 @@ children = ( 321955BE24BE234C00E3F316 /* ReaderInterestsCoordinator.swift */, 088B89881DA6F93B000E8DEF /* ReaderPostCardContentLabel.swift */, - E66EB6F81C1B7A76003DABC5 /* ReaderSpacerView.swift */, ); name = Views; sourceTree = ""; @@ -22290,7 +22286,6 @@ F1D8C6EB26BABE3E002E3323 /* WeeklyRoundupDebugScreen.swift in Sources */, 436D56262117312700CEAA33 /* RegisterDomainDetailsViewController+HeaderFooter.swift in Sources */, 931215F2267FE162008C3B69 /* ReferrerDetailsSpamActionRow.swift in Sources */, - E66EB6F91C1B7A76003DABC5 /* ReaderSpacerView.swift in Sources */, FAFF7A222B695801006A7CB2 /* WebServerLogsView.swift in Sources */, AE2F3125270B6DA000B2A9C2 /* Scanner+QuotedText.swift in Sources */, B560914C208A671F00399AE4 /* WPStyleGuide+SiteCreation.swift in Sources */, @@ -25229,7 +25224,6 @@ 4ADE3F962C6365E00046EC8A /* ApplicationTokenListView.swift in Sources */, FABB23892602FC2C00C8785C /* FormattableUserContent.swift in Sources */, FABB238A2602FC2C00C8785C /* RegisterDomainDetailsViewController+HeaderFooter.swift in Sources */, - FABB238B2602FC2C00C8785C /* ReaderSpacerView.swift in Sources */, 3FFDEF852918215700B625CE /* MigrationStepView.swift in Sources */, FABB238D2602FC2C00C8785C /* WPStyleGuide+SiteCreation.swift in Sources */, F41E32FF287B47A500F89082 /* SuggestionsListViewModel.swift in Sources */, From 8b1d0abf78e5a319500e0400b6a0854c7d691e1c Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:49:18 -0400 Subject: [PATCH 22/55] Remove ReaderTopicsCardCell --- .../Reader/ReaderTopicsCardCell.swift | 2 +- .../Reader/ReaderTopicsCardCell.xib | 66 +++++++-------- .../Reader/ReaderTopicsNewCardCell.xib | 82 ------------------- WordPress/WordPress.xcodeproj/project.pbxproj | 20 ++--- 4 files changed, 38 insertions(+), 132 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderTopicsNewCardCell.xib diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTopicsCardCell.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTopicsCardCell.swift index 183f34ca0053..48e87abff312 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTopicsCardCell.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderTopicsCardCell.swift @@ -21,7 +21,7 @@ class ReaderTopicsCardCell: UITableViewCell, NibLoadable { weak var delegate: ReaderTopicsTableCardCellDelegate? - static var defaultNibName: String { "ReaderTopicsNewCardCell" } + static var defaultNibName: String { "ReaderTopicsCardCell" } func configure(_ data: [ReaderAbstractTopic]) { self.data = data diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTopicsCardCell.xib b/WordPress/Classes/ViewRelated/Reader/ReaderTopicsCardCell.xib index c1ed2a5aa3f0..4c0ceb6ce8a6 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTopicsCardCell.xib +++ b/WordPress/Classes/ViewRelated/Reader/ReaderTopicsCardCell.xib @@ -1,6 +1,6 @@ - + @@ -10,74 +10,68 @@ - - + + - - + + - - + + - - + + - - + - - - - + + + + - - - - + + + + - - - + + + - + diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTopicsNewCardCell.xib b/WordPress/Classes/ViewRelated/Reader/ReaderTopicsNewCardCell.xib deleted file mode 100644 index 4c0ceb6ce8a6..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTopicsNewCardCell.xib +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 7b04e24508ae..9e44b1c85e92 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -3197,7 +3197,6 @@ C700FAB3258020DB0090938E /* JetpackScanThreatCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = C700FAB1258020DB0090938E /* JetpackScanThreatCell.xib */; }; C7124E4E2638528F00929318 /* JetpackPrologueViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C7124E4C2638528F00929318 /* JetpackPrologueViewController.xib */; }; C7124E4F2638528F00929318 /* JetpackPrologueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7124E4D2638528F00929318 /* JetpackPrologueViewController.swift */; }; - C7192ECF25E8432D00C3020D /* ReaderTopicsCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = C7192ECE25E8432D00C3020D /* ReaderTopicsCardCell.xib */; }; C71BC73F25A652410023D789 /* JetpackScanStatusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C71BC73E25A652410023D789 /* JetpackScanStatusViewModel.swift */; }; C7234A3A2832BA240045C63F /* QRLoginCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7234A392832BA240045C63F /* QRLoginCoordinator.swift */; }; C7234A3B2832BA240045C63F /* QRLoginCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7234A392832BA240045C63F /* QRLoginCoordinator.swift */; }; @@ -4312,7 +4311,6 @@ FABB20602602FC2C00C8785C /* MediaSizeSliderCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = E14977191C0DCB6F0057CD60 /* MediaSizeSliderCell.xib */; }; FABB20622602FC2C00C8785C /* ReaderBlockedSiteCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = E65219F81B8D10C2000B1217 /* ReaderBlockedSiteCell.xib */; }; FABB20652602FC2C00C8785C /* SiteSegmentsCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D8C31CC52188490000A33B35 /* SiteSegmentsCell.xib */; }; - FABB20692602FC2C00C8785C /* ReaderTopicsCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = C7192ECE25E8432D00C3020D /* ReaderTopicsCardCell.xib */; }; FABB206B2602FC2C00C8785C /* richEmbedTemplate.html in Resources */ = {isa = PBXBuildFile; fileRef = E61507E12220A0FE00213D33 /* richEmbedTemplate.html */; }; FABB206D2602FC2C00C8785C /* NoteBlockUserTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5C66B791ACF074600F68370 /* NoteBlockUserTableViewCell.xib */; }; FABB20702602FC2C00C8785C /* ReaderListStreamHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = E6D2E1621B8AAA340000ED14 /* ReaderListStreamHeader.xib */; }; @@ -5571,8 +5569,8 @@ FE003F5F282D61BA006F8D1D /* BloggingPrompt+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE003F5C282D61B9006F8D1D /* BloggingPrompt+CoreDataProperties.swift */; }; FE003F60282D61BA006F8D1D /* BloggingPrompt+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE003F5C282D61B9006F8D1D /* BloggingPrompt+CoreDataProperties.swift */; }; FE003F62282E73E6006F8D1D /* blogging-prompts-fetch-success.json in Resources */ = {isa = PBXBuildFile; fileRef = FE003F61282E73E6006F8D1D /* blogging-prompts-fetch-success.json */; }; - FE015BB12ADA002400F50D7F /* ReaderTopicsNewCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FE015BB02ADA002400F50D7F /* ReaderTopicsNewCardCell.xib */; }; - FE015BB22ADA002400F50D7F /* ReaderTopicsNewCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FE015BB02ADA002400F50D7F /* ReaderTopicsNewCardCell.xib */; }; + FE015BB12ADA002400F50D7F /* ReaderTopicsCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FE015BB02ADA002400F50D7F /* ReaderTopicsCardCell.xib */; }; + FE015BB22ADA002400F50D7F /* ReaderTopicsCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FE015BB02ADA002400F50D7F /* ReaderTopicsCardCell.xib */; }; FE02F95F269DC14A00752A44 /* Comment+Interface.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE02F95E269DC14A00752A44 /* Comment+Interface.swift */; }; FE06AC8326C3BD0900B69DE4 /* ShareAppContentPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE06AC8226C3BD0900B69DE4 /* ShareAppContentPresenter.swift */; }; FE06AC8526C3C2F800B69DE4 /* ShareAppTextActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE06AC8426C3C2F800B69DE4 /* ShareAppTextActivityItemSource.swift */; }; @@ -8675,7 +8673,6 @@ C700FAB1258020DB0090938E /* JetpackScanThreatCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = JetpackScanThreatCell.xib; sourceTree = ""; }; C7124E4C2638528F00929318 /* JetpackPrologueViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JetpackPrologueViewController.xib; sourceTree = ""; }; C7124E4D2638528F00929318 /* JetpackPrologueViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JetpackPrologueViewController.swift; sourceTree = ""; }; - C7192ECE25E8432D00C3020D /* ReaderTopicsCardCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReaderTopicsCardCell.xib; sourceTree = ""; }; C71BC73E25A652410023D789 /* JetpackScanStatusViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackScanStatusViewModel.swift; sourceTree = ""; }; C7234A392832BA240045C63F /* QRLoginCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRLoginCoordinator.swift; sourceTree = ""; }; C7234A402832C2BA0045C63F /* QRLoginScanningViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRLoginScanningViewController.swift; sourceTree = ""; }; @@ -9672,7 +9669,7 @@ FE003F5B282D61B9006F8D1D /* BloggingPrompt+CoreDataClass.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BloggingPrompt+CoreDataClass.swift"; sourceTree = ""; }; FE003F5C282D61B9006F8D1D /* BloggingPrompt+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BloggingPrompt+CoreDataProperties.swift"; sourceTree = ""; }; FE003F61282E73E6006F8D1D /* blogging-prompts-fetch-success.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "blogging-prompts-fetch-success.json"; sourceTree = ""; }; - FE015BB02ADA002400F50D7F /* ReaderTopicsNewCardCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReaderTopicsNewCardCell.xib; sourceTree = ""; }; + FE015BB02ADA002400F50D7F /* ReaderTopicsCardCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReaderTopicsCardCell.xib; sourceTree = ""; }; FE02F95E269DC14A00752A44 /* Comment+Interface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Comment+Interface.swift"; sourceTree = ""; }; FE06AC8226C3BD0900B69DE4 /* ShareAppContentPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareAppContentPresenter.swift; sourceTree = ""; }; FE06AC8426C3C2F800B69DE4 /* ShareAppTextActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareAppTextActivityItemSource.swift; sourceTree = ""; }; @@ -13247,7 +13244,6 @@ 8BCB83D024C21063001581BD /* ReaderStreamViewController+Ghost.swift */, 8BB185D024B63D1600A4CCE8 /* ReaderDiscoverViewController.swift */, 3234BB162530DFCA0068DA40 /* ReaderTableCardCell.swift */, - 8BCF957924C6044000712056 /* ReaderTopicsCardCell.swift */, 3234B8E6252FA0930068DA40 /* ReaderSitesCardCell.swift */, E69551F51B8B6AE200CB8E4F /* ReaderStreamViewController+Helper.swift */, 7371E6D121FA730700596C0A /* ReaderStreamViewController+Sharing.swift */, @@ -13256,8 +13252,8 @@ 5D42A401175E76A1005CFF05 /* WPImageViewController.h */, 5D42A402175E76A2005CFF05 /* WPImageViewController.m */, 0C749D792B0543D0004CB468 /* WPImageViewController+Swift.swift */, - C7192ECE25E8432D00C3020D /* ReaderTopicsCardCell.xib */, - FE015BB02ADA002400F50D7F /* ReaderTopicsNewCardCell.xib */, + 8BCF957924C6044000712056 /* ReaderTopicsCardCell.swift */, + FE015BB02ADA002400F50D7F /* ReaderTopicsCardCell.xib */, F4D36AD4298498E600E6B84C /* ReaderPostBlockingController.swift */, ); name = Controllers; @@ -19985,7 +19981,7 @@ FEA088032696E81F00193358 /* ListTableHeaderView.xib in Resources */, B59F34A1207678480069992D /* SignupEpilogue.storyboard in Resources */, 98FCFC242231DF43006ECDD4 /* PostStatsTitleCell.xib in Resources */, - FE015BB12ADA002400F50D7F /* ReaderTopicsNewCardCell.xib in Resources */, + FE015BB12ADA002400F50D7F /* ReaderTopicsCardCell.xib in Resources */, 8BA77BCD248340CE00E1EBBF /* ReaderDetailToolbar.xib in Resources */, 4070D75C20E5F55A007CEBDA /* RewindStatusTableViewCell.xib in Resources */, 1761F18D26209AEE000815EF /* hot-pink-icon-app-76x76.png in Resources */, @@ -20071,7 +20067,6 @@ 1761F18326209AEE000815EF /* jetpack-green-icon-app-83.5x83.5@2x.png in Resources */, 0186358D2A810ABA00915532 /* support_chat_widget.js in Resources */, 9801E685274EEC19002FDDB6 /* ReaderDetailCommentsHeader.xib in Resources */, - C7192ECF25E8432D00C3020D /* ReaderTopicsCardCell.xib in Resources */, 17222D8E261DDDF90047B163 /* black-classic-icon-app-76x76.png in Resources */, E61507E22220A0FE00213D33 /* richEmbedTemplate.html in Resources */, B5C66B7A1ACF074600F68370 /* NoteBlockUserTableViewCell.xib in Resources */, @@ -20604,7 +20599,6 @@ FABB20602602FC2C00C8785C /* MediaSizeSliderCell.xib in Resources */, FABB20622602FC2C00C8785C /* ReaderBlockedSiteCell.xib in Resources */, FABB20652602FC2C00C8785C /* SiteSegmentsCell.xib in Resources */, - FABB20692602FC2C00C8785C /* ReaderTopicsCardCell.xib in Resources */, F465980928E66A5B00D5F49A /* white-on-blue-icon-app-76.png in Resources */, FABB206B2602FC2C00C8785C /* richEmbedTemplate.html in Resources */, FABB206D2602FC2C00C8785C /* NoteBlockUserTableViewCell.xib in Resources */, @@ -20619,7 +20613,7 @@ FABB20772602FC2C00C8785C /* world-map.svg in Resources */, FABB20782602FC2C00C8785C /* NoteBlockTextTableViewCell.xib in Resources */, C3234F4D27EB96A5004ADB29 /* IntentCell.xib in Resources */, - FE015BB22ADA002400F50D7F /* ReaderTopicsNewCardCell.xib in Resources */, + FE015BB22ADA002400F50D7F /* ReaderTopicsCardCell.xib in Resources */, 9822A8562624D01800FD8A03 /* UserProfileSiteCell.xib in Resources */, FABB207D2602FC2C00C8785C /* RELEASE-NOTES.txt in Resources */, F46597BD28E6687800D5F49A /* neumorphic-dark-icon-app-76.png in Resources */, From 9dabf8c6445214a3a79a3883b486a13c19342b3a Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 13:50:10 -0400 Subject: [PATCH 23/55] Fix build --- .../Reader/ReaderStreamViewController.swift | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index ed347062b2c4..bcbfd1569f19 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -1246,10 +1246,6 @@ import AutomatticTracks NSPredicate(format: "isSavedForLater == YES") : NSPredicate(format: "topic = NULL AND SELF in %@", [String]()) - if contentType == .tags { - return NSPredicate(format: "following = true") - } - guard let topic = readerTopic else { return predicateForNilTopic } @@ -1267,10 +1263,7 @@ import AutomatticTracks } func sortDescriptorsForFetchRequest(ascending: Bool = false) -> [NSSortDescriptor] { - let sortDescriptor = contentType == .tags ? - NSSortDescriptor(key: "title", ascending: true) : - NSSortDescriptor(key: "sortRank", ascending: ascending) - return [sortDescriptor] + [NSSortDescriptor(key: "sortRank", ascending: ascending)] } // MARK: - Helpers for ReaderStreamHeader @@ -1411,7 +1404,7 @@ extension ReaderStreamViewController: WPTableViewHandlerDelegate { } func fetchRequest() -> NSFetchRequest? { - let entityName = contentType == .tags ? ReaderTagTopic.classNameWithoutNamespaces() : ReaderPost.classNameWithoutNamespaces() + let entityName = ReaderPost.classNameWithoutNamespaces() let fetchRequest = NSFetchRequest(entityName: entityName) fetchRequest.predicate = predicateForFetchRequest() fetchRequest.sortDescriptors = sortDescriptorsForFetchRequest() @@ -1713,8 +1706,6 @@ extension ReaderStreamViewController { displayNoResultsForSavedPosts() } else if contentType == .topic && siteID == ReaderHelpers.discoverSiteID { displayNoResultsViewForDiscover() - } else if contentType == .tags { - showSelectInterestsView() } return } From 606733549e61da5ae72d249260c43b219133fb15 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 14:20:30 -0400 Subject: [PATCH 24/55] Simplify ReaderMenuStore --- .../ViewRelated/Reader/ReaderMenuStore.swift | 49 +++++++ .../Reader/ReaderSidebarViewModel.swift | 8 +- .../Tab Navigation/ReaderTabItemsStore.swift | 120 ------------------ WordPress/WordPress.xcodeproj/project.pbxproj | 12 +- 4 files changed, 59 insertions(+), 130 deletions(-) create mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderMenuStore.swift delete mode 100644 WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItemsStore.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderMenuStore.swift b/WordPress/Classes/ViewRelated/Reader/ReaderMenuStore.swift new file mode 100644 index 000000000000..4af3a7f0e7f6 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Reader/ReaderMenuStore.swift @@ -0,0 +1,49 @@ +import UIKit + +protocol ReaderMenuStoreProtocol { + func refreshMenu() +} + +final class ReaderMenuStore: ReaderMenuStoreProtocol { + let context: NSManagedObjectContext + let service: ReaderTopicService + + private var isLoading = false + + init(context: NSManagedObjectContext = ContextManager.sharedInstance().mainContext, + service: ReaderTopicService? = nil) { + self.context = context + self.service = service ?? ReaderTopicService(coreDataStack: ContextManager.shared) + } + + /// Updates the items from the underlying service + func refreshMenu() { + guard !isLoading else { + return + } + isLoading = true + + // Sync the reader menu + service.fetchReaderMenu(success: { [weak self] in + self?.fetchTabBarItemsAndFollowedSites() + }, failure: { [weak self] error in + self?.fetchTabBarItemsAndFollowedSites() + DDLogError("Error syncing menu: \(String(describing: error))") + }) + } + + private func fetchTabBarItemsAndFollowedSites() { + DispatchQueue.main.async { + self.fetchFollowedSites() + } + } + + private func fetchFollowedSites() { + service.fetchAllFollowedSites(success: { [weak self] in + self?.isLoading = false + }, failure: { [weak self] error in + DDLogError("Could not sync sites: \(String(describing: error))") + self?.isLoading = false + }) + } +} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift index 31b734fe458a..e63578026142 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift @@ -7,7 +7,7 @@ final class ReaderSidebarViewModel: ObservableObject { didSet { persistenSelection() } } - private let tabItemsStore: ReaderTabItemsStoreProtocol + private let tabItemsStore: ReaderMenuStoreProtocol private let contextManager: CoreDataStackSwift private var previousReloadTimestamp: Date? @@ -15,9 +15,9 @@ final class ReaderSidebarViewModel: ObservableObject { var navigate: (ReaderSidebarNavigation) -> Void = { _ in } - init(tabItemsStore: ReaderTabItemsStoreProtocol = ReaderTabItemsStore(), + init(menuStore: ReaderMenuStoreProtocol = ReaderMenuStore(), contextManager: CoreDataStackSwift = ContextManager.shared) { - self.tabItemsStore = tabItemsStore + self.tabItemsStore = menuStore self.contextManager = contextManager let selection = UserDefaults.standard.readerSidebarSelection self.selection = .main(selection ?? .recent) @@ -37,7 +37,7 @@ final class ReaderSidebarViewModel: ObservableObject { private func reloadMenuIfNeeded() { if Date.now.timeIntervalSince(previousReloadTimestamp ?? .distantPast) > 60 { previousReloadTimestamp = .now - tabItemsStore.getItems() + tabItemsStore.refreshMenu() } } diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItemsStore.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItemsStore.swift deleted file mode 100644 index 3115b046ff07..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItemsStore.swift +++ /dev/null @@ -1,120 +0,0 @@ -import WordPressFlux - -protocol ReaderTabItemsStoreProtocol: Observable { - var items: [ReaderTabItem] { get } - func getItems() -} - -class ReaderTabItemsStore: ReaderTabItemsStoreProtocol { - - let changeDispatcher = Dispatcher() - - let context: NSManagedObjectContext - let service: ReaderTopicService - - init(context: NSManagedObjectContext = ContextManager.sharedInstance().mainContext, - service: ReaderTopicService? = nil) { - self.context = context - self.service = service ?? ReaderTopicService(coreDataStack: ContextManager.shared) - } - - enum State { - case loading - case ready([ReaderTabItem]) - case error(Error) - - var isLoading: Bool { - switch self { - case .loading: - return true - case .error, .ready: - return false - } - } - } - - var state: State = .ready([]) { - didSet { - guard !state.isLoading else { - return - } - emitChange() - } - } - - var items: [ReaderTabItem] { - switch state { - case .loading, .error: - return [] - case .ready(let items): - return items - } - } -} - -// MARK: - Data fetching -extension ReaderTabItemsStore { - - /// Fetch request to extract reader menu topics from Core Data - private var topicsFetchRequest: NSFetchRequest { - let fetchRequest = NSFetchRequest(entityName: ReaderTopicsConstants.entityName) - fetchRequest.predicate = NSPredicate(format: ReaderTopicsConstants.predicateFormat, NSNumber(value: ReaderHelpers.isLoggedIn())) - fetchRequest.sortDescriptors = [NSSortDescriptor(key: ReaderTopicsConstants.sortByKey, ascending: true)] - return fetchRequest - } - - /// Fetches items from the Core Data cache, if they exist, and updates the state accordingly - private func fetchTabBarItems() { - do { - let topics = try context.fetch(topicsFetchRequest) - let items = ReaderHelpers.rearrange(items: topics.map { ReaderTabItem(ReaderContent(topic: $0)) }) - self.state = .ready(items) - } catch { - DDLogError("\(ReaderTopicsConstants.fetchRequestError)\(error.localizedDescription)") - self.state = .error(error) - } - } - - /// Updates the items from the underlying service - func getItems() { - guard !state.isLoading else { - return - } - state = .loading - - // Return the tab bar items right away to avoid waiting for the request to finish - fetchTabBarItems() - - // Sync the reader menu - service.fetchReaderMenu(success: { [weak self] in - self?.fetchTabBarItemsAndFollowedSites() - }, failure: { [weak self] (error) in - self?.fetchTabBarItemsAndFollowedSites() - let actualError = error ?? ReaderTopicsConstants.remoteServiceError - DDLogError("Error syncing menu: \(String(describing: actualError))") - }) - } - - private func fetchTabBarItemsAndFollowedSites() { - DispatchQueue.main.async { - self.fetchFollowedSites() - } - fetchTabBarItems() - } - - private func fetchFollowedSites() { - service.fetchAllFollowedSites(success: { - }, failure: { (error) in - let actualError = error ?? ReaderTopicsConstants.remoteServiceError - DDLogError("Could not sync sites: \(String(describing: actualError))") - }) - } - - private enum ReaderTopicsConstants { - static let predicateFormat = "type == 'default' OR type == 'organization' OR (type == 'list' AND following == %@ AND showInMenu == YES)" - static let entityName = "ReaderAbstractTopic" - static let sortByKey = "type" - static let fetchRequestError = "There was a problem fetching topics for the menu. " - static let remoteServiceError = NSError(domain: WordPressComRestApiErrorDomain, code: -1, userInfo: nil) - } -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 9e44b1c85e92..a926650ba9df 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -1180,7 +1180,7 @@ 3FBF21B7267AA17A0098335F /* BloggingRemindersAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FBF21B6267AA17A0098335F /* BloggingRemindersAnimator.swift */; }; 3FBF21B8267AA17A0098335F /* BloggingRemindersAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FBF21B6267AA17A0098335F /* BloggingRemindersAnimator.swift */; }; 3FC7F89E2612341900FD8728 /* UnifiedPrologueStatsContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FC7F89D2612341900FD8728 /* UnifiedPrologueStatsContentView.swift */; }; - 3FC8D19B244F43B500495820 /* ReaderTabItemsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FC8D19A244F43B500495820 /* ReaderTabItemsStore.swift */; }; + 3FC8D19B244F43B500495820 /* ReaderMenuStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FC8D19A244F43B500495820 /* ReaderMenuStore.swift */; }; 3FCCAA1523F4A1A3004064C0 /* UIBarButtonItem+MeBarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FCCAA1423F4A1A3004064C0 /* UIBarButtonItem+MeBarButton.swift */; }; 3FD0316F24201E08005C0993 /* GravatarButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FD0316E24201E08005C0993 /* GravatarButtonView.swift */; }; 3FD272E024CF8F270021F0C8 /* UIColor+Notice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FD272DF24CF8F270021F0C8 /* UIColor+Notice.swift */; }; @@ -4887,7 +4887,7 @@ FABB235C2602FC2C00C8785C /* WPAnalyticsTrackerWPCom.m in Sources */ = {isa = PBXBuildFile; fileRef = 85DA8C4318F3F29A0074C8A4 /* WPAnalyticsTrackerWPCom.m */; }; FABB235D2602FC2C00C8785C /* AztecAttachmentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B50C0C5C1EF42A4A00372C65 /* AztecAttachmentViewController.swift */; }; FABB23602602FC2C00C8785C /* PostServiceRemoteFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57D66B99234BB206005A2D74 /* PostServiceRemoteFactory.swift */; }; - FABB23612602FC2C00C8785C /* ReaderTabItemsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FC8D19A244F43B500495820 /* ReaderTabItemsStore.swift */; }; + FABB23612602FC2C00C8785C /* ReaderMenuStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FC8D19A244F43B500495820 /* ReaderMenuStore.swift */; }; FABB23622602FC2C00C8785C /* NoResultsViewController+Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98EB126920D2DC2500D2D5B5 /* NoResultsViewController+Model.swift */; }; FABB23642602FC2C00C8785C /* UIAlertController+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5969E2120A49E86005E9DF1 /* UIAlertController+Helpers.swift */; }; FABB23652602FC2C00C8785C /* RevisionDiff+CoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A4E61F721A2C3BC0017A925 /* RevisionDiff+CoreData.swift */; }; @@ -6995,7 +6995,7 @@ 3FB6D13E2AD2AC5A00768C07 /* Announcement+Fixture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Announcement+Fixture.swift"; sourceTree = ""; }; 3FBF21B6267AA17A0098335F /* BloggingRemindersAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloggingRemindersAnimator.swift; sourceTree = ""; }; 3FC7F89D2612341900FD8728 /* UnifiedPrologueStatsContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnifiedPrologueStatsContentView.swift; sourceTree = ""; }; - 3FC8D19A244F43B500495820 /* ReaderTabItemsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTabItemsStore.swift; sourceTree = ""; }; + 3FC8D19A244F43B500495820 /* ReaderMenuStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderMenuStore.swift; sourceTree = ""; }; 3FCCAA1423F4A1A3004064C0 /* UIBarButtonItem+MeBarButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIBarButtonItem+MeBarButton.swift"; sourceTree = ""; }; 3FCF66E825CAF8C50047F337 /* ListStatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStatsView.swift; sourceTree = ""; }; 3FCF66FA25CAF8E00047F337 /* ListRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRow.swift; sourceTree = ""; }; @@ -10688,6 +10688,7 @@ 0CDDCA032C8F3F6E005AACA3 /* ReaderSidebarTagsSection.swift */, 0CDDCA0F2C8F9528005AACA3 /* ReaderSidebarListsSection.swift */, 0CDDCA122C907C7E005AACA3 /* ReaderSidebarOrganizationSection.swift */, + 3FC8D19A244F43B500495820 /* ReaderMenuStore.swift */, ); name = Sidebar; sourceTree = ""; @@ -11657,7 +11658,6 @@ isa = PBXGroup; children = ( 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */, - 3FC8D19A244F43B500495820 /* ReaderTabItemsStore.swift */, 3FF1A852242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift */, ); path = "Tab Navigation"; @@ -22224,7 +22224,7 @@ B50C0C5E1EF42A4A00372C65 /* AztecAttachmentViewController.swift in Sources */, 0CFE9AC62AF44A9F00B8F659 /* AbstractPostHelper+Actions.swift in Sources */, 57D66B9A234BB206005A2D74 /* PostServiceRemoteFactory.swift in Sources */, - 3FC8D19B244F43B500495820 /* ReaderTabItemsStore.swift in Sources */, + 3FC8D19B244F43B500495820 /* ReaderMenuStore.swift in Sources */, 98EB126A20D2DC2500D2D5B5 /* NoResultsViewController+Model.swift in Sources */, B5969E2220A49E86005E9DF1 /* UIAlertController+Helpers.swift in Sources */, 0CE783412B08FB2E00B114EB /* ExternalMediaPickerCollectionCell.swift in Sources */, @@ -25153,7 +25153,7 @@ FABB235D2602FC2C00C8785C /* AztecAttachmentViewController.swift in Sources */, FABB23602602FC2C00C8785C /* PostServiceRemoteFactory.swift in Sources */, 2448ABAF2C5D515700DC0091 /* URL+AVKit.swift in Sources */, - FABB23612602FC2C00C8785C /* ReaderTabItemsStore.swift in Sources */, + FABB23612602FC2C00C8785C /* ReaderMenuStore.swift in Sources */, FABB23622602FC2C00C8785C /* NoResultsViewController+Model.swift in Sources */, 4A26E98F2C90EE8400C1D5DE /* SplitViewRootPresenter+Notifications.swift in Sources */, 3F435220289B2B2B00CE19ED /* JetpackBrandingCoordinator.swift in Sources */, From 61e84a99f2979fd5c83006473d59b278323666b0 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 14:22:37 -0400 Subject: [PATCH 25/55] Remove ReaderTabItem --- .../ViewRelated/Reader/ReaderHelpers.swift | 61 ------------- .../Reader/ReaderSidebarViewModel.swift | 27 ++++++ .../Reader/Tab Navigation/ReaderTabItem.swift | 88 ------------------- WordPress/WordPress.xcodeproj/project.pbxproj | 6 -- 4 files changed, 27 insertions(+), 155 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift b/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift index f2029da118dd..afe98b3cf05b 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift @@ -627,67 +627,6 @@ struct ReaderPostMenuButtonTitles { } } -/// Reader tab items -extension ReaderHelpers { - - static let defaultSavedItemPosition = 2 - - /// Sorts the default tabs according to the order [Discover, Subscriptions, Saved, Liked, Your Tags] - class func rearrange(items: [ReaderTabItem]) -> [ReaderTabItem] { - - guard !items.isEmpty else { - return items - } - - var mutableItems = items - mutableItems.sort { - guard let leftTopic = $0.content.topic, let rightTopic = $1.content.topic else { - return true - } - - if topicIsDiscover(leftTopic) { - return true - } - if topicIsDiscover(rightTopic) { - return false - } - - if topicIsFollowing(leftTopic) { - return true - } - if topicIsFollowing(rightTopic) { - return false - } - - if topicIsLiked(leftTopic) { - return true - } - if topicIsLiked(rightTopic) { - return false - } - - // any other items: sort them alphabetically, grouped by topic type - if leftTopic.type == rightTopic.type { - return leftTopic.title < rightTopic.title - } - - return true - } - - let savedPosition = min(mutableItems.count, defaultSavedItemPosition) - mutableItems.insert(ReaderTabItem(ReaderContent(topic: nil, contentType: .saved)), at: savedPosition) - - // in case of log in with a self hosted site, prepend a 'dummy' Following tab after Discover. - if !isLoggedIn() { - // to safeguard, ensure that there are items in the array before inserting. Otherwise, insert at index 0. - let targetIndex = mutableItems.count > 0 ? 1 : 0 - mutableItems.insert(ReaderTabItem(ReaderContent(topic: nil, contentType: .selfHostedFollowing)), at: targetIndex) - } - - return mutableItems - } -} - /// Typed topic type enum ReaderTopicType { case discover diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift index e63578026142..c24532c13bc9 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift @@ -118,3 +118,30 @@ enum ReaderStaticScreen: String, CaseIterable, Identifiable, Hashable { } } } + +enum ReaderContentType { + case selfHostedFollowing + case contentError + case saved + case topic +} + +struct ReaderContent: Hashable { + + private(set) var topic: ReaderAbstractTopic? + let type: ReaderContentType + let topicType: ReaderTopicType + + init(topic: ReaderAbstractTopic?, contentType: ReaderContentType = .topic) { + self.topicType = ReaderHelpers.topicType(topic) + + if let topic = topic { + self.topic = topic + // if topic is not nil, contentType must be .topic. + self.type = .topic + return + } + // if topic is nil, passing contentType: .topic is invalid -> content will be treated as invalid + self.type = (topic == nil && contentType == .topic) ? .contentError : contentType + } +} diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift deleted file mode 100644 index 935432ce94dc..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabItem.swift +++ /dev/null @@ -1,88 +0,0 @@ -import Foundation - -struct ReaderTabItem: FilterTabBarItem, Hashable, Identifiable { - var id: ReaderTabItem { self } - - let content: ReaderContent - - var accessibilityIdentifier: String { - return "Reader Navigation Menu Item, \(title)" - } - - /// initialize with topic - init(_ content: ReaderContent) { - self.content = content - } - -} - -// MARK: - Localized titles -extension ReaderTabItem { - - var title: String { - switch content.type { - case .topic: - switch content.topicType { - case .following: - return Titles.followingTitle - case .likes: - return Titles.likesTitle - default: - return content.topic?.title ?? Titles.emptyTitle - } - case .selfHostedFollowing: - return Titles.followingTitle - case .saved: - return Titles.savedTitle - default: - return Titles.emptyTitle - } - } - - private enum Titles { - static let followingTitle = NSLocalizedString( - "reader.navigation.menu.subscriptions", - value: "Subscriptions", - comment: "Reader navigation menu item for the Subscriptions filter" - ) - static let likesTitle = NSLocalizedString( - "reader.navigation.menu.liked", - value: "Liked", - comment: "Reader navigation menu item for the Liked filter" - ) - static let savedTitle = NSLocalizedString( - "reader.navigation.menu.saved", - value: "Saved", - comment: "Reader navigation menu item for the Saved filter" - ) - static let emptyTitle = "" - } -} - -// MARK: - Reader Content -enum ReaderContentType { - case selfHostedFollowing - case contentError - case saved - case topic -} - -struct ReaderContent: Hashable { - - private(set) var topic: ReaderAbstractTopic? - let type: ReaderContentType - let topicType: ReaderTopicType - - init(topic: ReaderAbstractTopic?, contentType: ReaderContentType = .topic) { - self.topicType = ReaderHelpers.topicType(topic) - - if let topic = topic { - self.topic = topic - // if topic is not nil, contentType must be .topic. - self.type = .topic - return - } - // if topic is nil, passing contentType: .topic is invalid -> content will be treated as invalid - self.type = (topic == nil && contentType == .topic) ? .contentError : contentType - } -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index a926650ba9df..eb79d430e9fb 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -1077,7 +1077,6 @@ 37022D931981C19000F322B7 /* VerticallyStackedButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 37022D901981BF9200F322B7 /* VerticallyStackedButton.m */; }; 374CB16215B93C0800DD0EBC /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */; }; 37EAAF4D1A11799A006D6306 /* CircularImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37EAAF4C1A11799A006D6306 /* CircularImageView.swift */; }; - 3F09CCAE24292EFD00D00A8C /* ReaderTabItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */; }; 3F170E242655917400F6F670 /* UIView+SwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F170E232655917400F6F670 /* UIView+SwiftUI.swift */; }; 3F170E252655917400F6F670 /* UIView+SwiftUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F170E232655917400F6F670 /* UIView+SwiftUI.swift */; }; 3F1B66A323A2F54B0075F09E /* ReaderReblogActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F1B66A223A2F54B0075F09E /* ReaderReblogActionTests.swift */; }; @@ -5443,7 +5442,6 @@ FABB26002602FC2C00C8785C /* GravatarProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6FACB1D1EC675E300284AC7 /* GravatarProfile.swift */; }; FABB26012602FC2C00C8785C /* ReaderShareAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CB620AA7703008E8AE8 /* ReaderShareAction.swift */; }; FABB26022602FC2C00C8785C /* PostingActivityMonth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9826AE8921B5CC7300C851FA /* PostingActivityMonth.swift */; }; - FABB26042602FC2C00C8785C /* ReaderTabItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */; }; FABB26072602FC2C00C8785C /* JetpackBackupService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAB8FD6D25AEB23600D5D54A /* JetpackBackupService.swift */; }; FABB26082602FC2C00C8785C /* NotificationsViewController+JetpackPrompt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8236EB4F2024ED8C007C7CF9 /* NotificationsViewController+JetpackPrompt.swift */; }; FABB26092602FC2C00C8785C /* PostListFooterView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D732F961AE84E3C00CD89E7 /* PostListFooterView.m */; }; @@ -6899,7 +6897,6 @@ 37022D901981BF9200F322B7 /* VerticallyStackedButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VerticallyStackedButton.m; sourceTree = ""; }; 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 37EAAF4C1A11799A006D6306 /* CircularImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircularImageView.swift; sourceTree = ""; }; - 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTabItem.swift; sourceTree = ""; }; 3F170E232655917400F6F670 /* UIView+SwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+SwiftUI.swift"; sourceTree = ""; }; 3F1B66A223A2F54B0075F09E /* ReaderReblogActionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderReblogActionTests.swift; sourceTree = ""; }; 3F2656A025AF4DFA0073A832 /* AppLocalizedString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLocalizedString.swift; sourceTree = ""; }; @@ -11657,7 +11654,6 @@ 3F09CCA62428FE8600D00A8C /* Tab Navigation */ = { isa = PBXGroup; children = ( - 3F09CCAD24292EFD00D00A8C /* ReaderTabItem.swift */, 3FF1A852242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift */, ); path = "Tab Navigation"; @@ -23145,7 +23141,6 @@ 01C591452BDBD63D0071515C /* StatsGhostTopCell.swift in Sources */, 9826AE8A21B5CC7300C851FA /* PostingActivityMonth.swift in Sources */, 08F531FE2B7E94F20061BD0E /* CachedAsyncImage.swift in Sources */, - 3F09CCAE24292EFD00D00A8C /* ReaderTabItem.swift in Sources */, FAB8FD6E25AEB23600D5D54A /* JetpackBackupService.swift in Sources */, 17171374265FAA8A00F3A022 /* BloggingRemindersNavigationController.swift in Sources */, 8236EB502024ED8C007C7CF9 /* NotificationsViewController+JetpackPrompt.swift in Sources */, @@ -26097,7 +26092,6 @@ 08240C2F2AB8A2DD00E7AEA8 /* AllDomainsListCardView.swift in Sources */, FABB26022602FC2C00C8785C /* PostingActivityMonth.swift in Sources */, 0107E15D28FFE99300DE87DB /* WidgetConfiguration.swift in Sources */, - FABB26042602FC2C00C8785C /* ReaderTabItem.swift in Sources */, FABB26072602FC2C00C8785C /* JetpackBackupService.swift in Sources */, FABB26082602FC2C00C8785C /* NotificationsViewController+JetpackPrompt.swift in Sources */, FABB26092602FC2C00C8785C /* PostListFooterView.m in Sources */, From 81b5cd6e9006b60e311bb04c5add23bcd9656b4a Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 14:23:17 -0400 Subject: [PATCH 26/55] Remove selfHostedFollowing contentType --- .../ViewRelated/Reader/ReaderSidebarViewModel.swift | 1 - .../Reader/ReaderStreamViewController.swift | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift index c24532c13bc9..ef64c3aeaf02 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift @@ -120,7 +120,6 @@ enum ReaderStaticScreen: String, CaseIterable, Identifiable, Hashable { } enum ReaderContentType { - case selfHostedFollowing case contentError case saved case topic diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index bcbfd1569f19..8b0fc07a7744 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -1960,9 +1960,6 @@ private extension ReaderStreamViewController { var shouldDisplayNoTopicController: Bool { switch contentType { - case .selfHostedFollowing: - displaySelfHostedFollowingController() - return true case .contentError: displayContentErrorController() return true @@ -1972,15 +1969,6 @@ private extension ReaderStreamViewController { } } - func displaySelfHostedFollowingController() { - let controller = NoResultsViewController.noFollowedSitesController(showActionButton: isLoggedIn) - controller.delegate = self - - addNoTopicController(controller) - - view.isUserInteractionEnabled = true - } - func displayContentErrorController() { let controller = noTopicViewController(title: NoTopicConstants.contentErrorTitle, subtitle: NoTopicConstants.contentErrorSubtitle, From 0977a360c1c3bb9e8d8bf94db53757dfb2ae805a Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 14:25:59 -0400 Subject: [PATCH 27/55] Remove ReaderContentViewController --- .../Reader/ReaderDiscoverViewController.swift | 8 +----- .../Reader/ReaderStreamViewController.swift | 28 ------------------- ...TabBarController+ReaderTabNavigation.swift | 5 +--- 3 files changed, 2 insertions(+), 39 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift index 46607dc88ab7..f1e6a72d16e1 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift @@ -4,7 +4,7 @@ import Combine import WordPressKit import WordPressShared -class ReaderDiscoverViewController: UIViewController, ReaderDiscoverHeaderViewDelegate, ReaderContentViewController { +class ReaderDiscoverViewController: UIViewController, ReaderDiscoverHeaderViewDelegate { private let headerView = ReaderDiscoverHeaderView() private var selectedChannel: ReaderDiscoverChannel = .recommended private let topic: ReaderAbstractTopic @@ -114,12 +114,6 @@ class ReaderDiscoverViewController: UIViewController, ReaderDiscoverHeaderViewDe ReaderCardService.removeAllCards() } - // MARK: - ReaderContentViewController (Deprecated) - - func setContent(_ content: ReaderContent) { - streamVC?.setContent(content) - } - // MARK: - ReaderDiscoverHeaderViewDelegate func readerDiscoverHeaderView(_ view: ReaderDiscoverHeaderView, didChangeSelection selection: ReaderDiscoverChannel) { diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 8b0fc07a7744..74c27682b589 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -178,9 +178,6 @@ import AutomatticTracks } } - /// Whether the stream is being filtered by a site or tag. - var isContentFiltered: Bool = false - var contentType: ReaderContentType = .topic { didSet { if oldValue != .saved, contentType == .saved { @@ -1930,31 +1927,6 @@ extension ReaderStreamViewController: UIViewControllerTransitioningDelegate { } } -// MARK: - ReaderContentViewController -extension ReaderStreamViewController: ReaderContentViewController { - func setContent(_ content: ReaderContent) { - isContentFiltered = content.topicType == .tag || content.topicType == .site - readerTopic = content.topicType == .discover ? nil : content.topic - contentType = content.type - self.content.resetResultsController() - - guard !shouldDisplayNoTopicController else { - return - } - - siteID = content.topicType == .discover ? ReaderHelpers.discoverSiteID : nil - trackFilterTime() - } - - func trackFilterTime() { - if isContentFiltered { - ReaderTracker.shared.start(.filteredList) - } else { - ReaderTracker.shared.stop(.filteredList) - } - } -} - // MARK: - View content types without a topic private extension ReaderStreamViewController { diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift index 3d085d5b1615..c9ae67eb977b 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift @@ -1,7 +1,4 @@ -/// Generic type for the UIViewController in the Reader Content View -protocol ReaderContentViewController: UIViewController { - func setContent(_ content: ReaderContent) -} +import UIKit // MARK: - Reader Navigation extension WPTabBarController { From be67c30a54edf9a0a380611980faaa8027fc4b9b Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 14:26:24 -0400 Subject: [PATCH 28/55] Remove ReaderContent --- .../Reader/ReaderSidebarViewModel.swift | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift index ef64c3aeaf02..94e517040335 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift @@ -124,23 +124,3 @@ enum ReaderContentType { case saved case topic } - -struct ReaderContent: Hashable { - - private(set) var topic: ReaderAbstractTopic? - let type: ReaderContentType - let topicType: ReaderTopicType - - init(topic: ReaderAbstractTopic?, contentType: ReaderContentType = .topic) { - self.topicType = ReaderHelpers.topicType(topic) - - if let topic = topic { - self.topic = topic - // if topic is not nil, contentType must be .topic. - self.type = .topic - return - } - // if topic is nil, passing contentType: .topic is invalid -> content will be treated as invalid - self.type = (topic == nil && contentType == .topic) ? .contentError : contentType - } -} From 6b766d832bf29f32d042103e39877c4eb3fbecbb Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 14:27:12 -0400 Subject: [PATCH 29/55] Fix build --- .../ReaderStreamViewController+Helper.swift | 7 +-- ...TabBarController+ReaderTabNavigation.swift | 43 ------------------- .../System/WPTabBarController+Swift.swift | 7 +++ .../ViewRelated/System/WPTabBarController.h | 2 + WordPress/WordPress.xcodeproj/project.pbxproj | 14 ------ 5 files changed, 11 insertions(+), 62 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift index 00640fd74daf..41fb8c1c25bd 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift @@ -31,22 +31,19 @@ extension ReaderStreamViewController { } func headerForStream(_ topic: ReaderAbstractTopic) -> ReaderHeader? { - if ReaderHelpers.isTopicTag(topic) && !isContentFiltered { + if ReaderHelpers.isTopicTag(topic) { guard let nibViews = Bundle.main.loadNibNamed("ReaderTagStreamHeader", owner: nil, options: nil) as? [ReaderTagStreamHeader] else { return nil } return nibViews.first } - if ReaderHelpers.isTopicList(topic) { return Bundle.main.loadNibNamed("ReaderListStreamHeader", owner: nil, options: nil)?.first as? ReaderListStreamHeader } - - if ReaderHelpers.isTopicSite(topic) && !isContentFiltered { + if ReaderHelpers.isTopicSite(topic) { return ReaderSiteHeaderView() } - return nil } diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift deleted file mode 100644 index c9ae67eb977b..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift +++ /dev/null @@ -1,43 +0,0 @@ -import UIKit - -// MARK: - Reader Navigation -extension WPTabBarController { - func showReader(path: ReaderNavigationPath?) { - showReaderTab() - if let path { - navigate(to: path) - } - } - - private func navigate(to path: ReaderNavigationPath) { - switch path { - case .recent: - // TODO: (reader) implement - break - case .discover: - // TODO: (reader) implement - break - case .likes: - // TODO: (reader) implement - break - case .search: - showReaderDetails(ReaderSearchViewController.controller()) - case .subscriptions: - // TODO: (reader) implement using the new screen - break - case let .post(postID, siteID, isFeed): - showReaderDetails(ReaderDetailViewController.controllerWithPostID(NSNumber(value: postID), siteID: NSNumber(value: siteID), isFeed: isFeed)) - case let .postURL(url): - showReaderDetails(ReaderDetailViewController.controllerWithPostURL(url)) - case let .tag(slug): - showReaderDetails(ReaderStreamViewController.controllerWithTagSlug(slug)) - case let .topic(topic): - showReaderDetails(ReaderStreamViewController.controllerWithTopic(topic)) - } - } - - private func showReaderDetails(_ viewController: UIViewController) { - readerNavigationController?.popToRootViewController(animated: false) - readerNavigationController?.pushViewController(viewController, animated: true) - } -} diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift b/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift index f5e951a2939a..1566e56a3ad7 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift @@ -18,6 +18,13 @@ fileprivate extension WPTab { } extension WPTabBarController { + func showReader(path: ReaderNavigationPath?) { + showReaderTab() + if let path { + self.readerPresenter.navigate(to: path) + } + } + @objc public class var wpSigninDidFinishNotification: String { WordPressAuthenticator.WPSigninDidFinishNotification } diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController.h b/WordPress/Classes/ViewRelated/System/WPTabBarController.h index ee20f6a3ba16..92f353ef70dc 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController.h +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController.h @@ -15,6 +15,7 @@ extern NSNotificationName const WPTabBarHeightChangedNotification; @class MeViewController; @class MySitesCoordinator; @class NotificationsViewController; +@class ReaderPresenter; @protocol ScenePresenter; @interface WPTabBarController : UITabBarController @@ -24,6 +25,7 @@ extern NSNotificationName const WPTabBarHeightChangedNotification; @property (nonatomic, strong, readonly, nonnull) MeViewController *meViewController; @property (nonatomic, strong, readonly, nonnull) UINavigationController *meNavigationController; @property (nonatomic, strong, readonly, nonnull) MySitesCoordinator *mySitesCoordinator; +@property (nonatomic, strong, readonly, nullable) ReaderPresenter *readerPresenter; @property (nonatomic, assign) BOOL shouldUseStaticScreens; - (instancetype)initWithStaticScreens:(BOOL)shouldUseStaticScreens; diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index eb79d430e9fb..b6b9d42734ac 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -1194,7 +1194,6 @@ 3FEC241525D73E8B007AFE63 /* ConfettiView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FEC241425D73E8B007AFE63 /* ConfettiView.swift */; }; 3FF15A56291B4EEA00E1B4E5 /* MigrationCenterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FF15A55291B4EEA00E1B4E5 /* MigrationCenterView.swift */; }; 3FF15A5C291ED21100E1B4E5 /* MigrationNotificationsCenterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FF15A5B291ED21100E1B4E5 /* MigrationNotificationsCenterView.swift */; }; - 3FF1A853242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FF1A852242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift */; }; 3FF717FF291F07AB00323614 /* MigrationCenterViewConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FF717FE291F07AB00323614 /* MigrationCenterViewConfiguration.swift */; }; 3FFA5ED22876152E00830E28 /* JetpackButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FFA5ED12876152E00830E28 /* JetpackButton.swift */; }; 3FFB3F222AFC72EC00A742B0 /* DeepLinkSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FFB3F212AFC72EC00A742B0 /* DeepLinkSourceTests.swift */; }; @@ -4592,7 +4591,6 @@ FABB21E92602FC2C00C8785C /* MenuItemSourceHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 08D978521CD2AF7D0054F19A /* MenuItemSourceHeaderView.m */; }; FABB21EA2602FC2C00C8785C /* RestoreWarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA1A543D25A6E2F60033967D /* RestoreWarningView.swift */; }; FABB21EB2602FC2C00C8785C /* GutenbergWebNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E4F2E702458AF8500EB73E7 /* GutenbergWebNavigationViewController.swift */; }; - FABB21ED2602FC2C00C8785C /* WPTabBarController+ReaderTabNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FF1A852242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift */; }; FABB21EF2602FC2C00C8785C /* KeyboardDismissHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56695AF1D411EEB007E342F /* KeyboardDismissHelper.swift */; }; FABB21F02602FC2C00C8785C /* FancyAlertViewController+CreateButtonAnnouncement.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5B9D7EF245BA938002BB2C7 /* FancyAlertViewController+CreateButtonAnnouncement.swift */; }; FABB21F12602FC2C00C8785C /* GutenbergSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF54D4631D6F3FA900A0DC4D /* GutenbergSettings.swift */; }; @@ -7007,7 +7005,6 @@ 3FEC241425D73E8B007AFE63 /* ConfettiView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfettiView.swift; sourceTree = ""; }; 3FF15A55291B4EEA00E1B4E5 /* MigrationCenterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationCenterView.swift; sourceTree = ""; }; 3FF15A5B291ED21100E1B4E5 /* MigrationNotificationsCenterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationNotificationsCenterView.swift; sourceTree = ""; }; - 3FF1A852242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WPTabBarController+ReaderTabNavigation.swift"; sourceTree = ""; }; 3FF717FE291F07AB00323614 /* MigrationCenterViewConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationCenterViewConfiguration.swift; sourceTree = ""; }; 3FFA5ED12876152E00830E28 /* JetpackButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackButton.swift; sourceTree = ""; }; 3FFB3F212AFC72EC00A742B0 /* DeepLinkSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkSourceTests.swift; sourceTree = ""; }; @@ -11651,14 +11648,6 @@ path = "Notifications Permission"; sourceTree = ""; }; - 3F09CCA62428FE8600D00A8C /* Tab Navigation */ = { - isa = PBXGroup; - children = ( - 3FF1A852242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift */, - ); - path = "Tab Navigation"; - sourceTree = ""; - }; 3F170D2A2654615900F6F670 /* Blogging Reminders */ = { isa = PBXGroup; children = ( @@ -16988,7 +16977,6 @@ 32E1BFD824A66801007A08F0 /* Select Interests */, 5D98A1491B6C09730085E904 /* Style */, 0CAC10922C876E37003AB1BC /* Sidebar */, - 3F09CCA62428FE8600D00A8C /* Tab Navigation */, 0CDB1BAB2C8B4FF500C83860 /* Subscriptions */, 0CDDCA062C8F4116005AACA3 /* Tags */, 5D08B8FC19647C0300D5B381 /* Views */, @@ -21694,7 +21682,6 @@ FA1A543E25A6E2F60033967D /* RestoreWarningView.swift in Sources */, 1E4F2E712458AF8500EB73E7 /* GutenbergWebNavigationViewController.swift in Sources */, 98E0829F2637545C00537BF1 /* PostService+Likes.swift in Sources */, - 3FF1A853242D5FCB00373F5D /* WPTabBarController+ReaderTabNavigation.swift in Sources */, 4A526BDF296BE9A50007B5BA /* CoreDataService.m in Sources */, 98AA9F2127EA890800B3A98C /* FeatureIntroductionViewController.swift in Sources */, B56695B01D411EEB007E342F /* KeyboardDismissHelper.swift in Sources */, @@ -24636,7 +24623,6 @@ C7D30C652638B07A00A1695B /* JetpackPrologueStyleGuide.swift in Sources */, FABB21EB2602FC2C00C8785C /* GutenbergWebNavigationViewController.swift in Sources */, F4F9D5EC29096CF500502576 /* MigrationHeaderView.swift in Sources */, - FABB21ED2602FC2C00C8785C /* WPTabBarController+ReaderTabNavigation.swift in Sources */, FABB21EF2602FC2C00C8785C /* KeyboardDismissHelper.swift in Sources */, FABB21F02602FC2C00C8785C /* FancyAlertViewController+CreateButtonAnnouncement.swift in Sources */, FABB21F12602FC2C00C8785C /* GutenbergSettings.swift in Sources */, From 5258d9f594f36d212ebf3acee803229ee4c23b9c Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 14:34:28 -0400 Subject: [PATCH 30/55] Remove ReaderTracker --- .../Utility/Analytics/WPAppAnalytics.m | 4 - .../Reader/Analytics/ReaderTracker.swift | 65 ----------------- .../Detail/ReaderDetailViewController.swift | 23 ------ .../Reader/ReaderStreamViewController.swift | 12 --- .../System/WPTabBarController+Swift.swift | 2 +- WordPress/WordPress.xcodeproj/project.pbxproj | 18 ----- .../WordPressTest/ReaderTrackerTests.swift | 73 ------------------- 7 files changed, 1 insertion(+), 196 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/Analytics/ReaderTracker.swift delete mode 100644 WordPress/WordPressTest/ReaderTrackerTests.swift diff --git a/WordPress/Classes/Utility/Analytics/WPAppAnalytics.m b/WordPress/Classes/Utility/Analytics/WPAppAnalytics.m index 12a81d380348..c0fc17fe4b6d 100644 --- a/WordPress/Classes/Utility/Analytics/WPAppAnalytics.m +++ b/WordPress/Classes/Utility/Analytics/WPAppAnalytics.m @@ -204,12 +204,8 @@ - (void)trackApplicationClosed self.applicationOpenedTime = nil; } - [[ReaderTracker shared] stopAll]; - [analyticsProperties addEntriesFromDictionary: [[ReaderTracker shared] data]]; - [WPAnalytics track:WPAnalyticsStatApplicationClosed withProperties:analyticsProperties]; [WPAnalytics endSession]; - [[ReaderTracker shared] reset]; } /** diff --git a/WordPress/Classes/ViewRelated/Reader/Analytics/ReaderTracker.swift b/WordPress/Classes/ViewRelated/Reader/Analytics/ReaderTracker.swift deleted file mode 100644 index 4ee12ed0a941..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/Analytics/ReaderTracker.swift +++ /dev/null @@ -1,65 +0,0 @@ -import Foundation - -class ReaderTracker: NSObject { - @objc static let shared = ReaderTracker() - - enum Section: String, CaseIterable { - /// Time spent in the main Reader view (the one with the tabs) - case main = "time_in_main_reader" - - /// Time spent in the Following tab with an active filter - case filteredList = "time_in_reader_filtered_list" - - /// Time spent reading article - case readerPost = "time_in_reader_post" - } - - private var now: () -> Date - private var startTime: [Section: Date] = [:] - private var totalTimeInSeconds: [Section: TimeInterval] = [:] - - init(now: @escaping () -> Date = { return Date() }) { - self.now = now - } - - /// Returns a dictionary with a key and the time spent in that section - @objc func data() -> [String: Double] { - return Section.allCases.reduce([String: Double]()) { dict, section in - var dict = dict - dict[section.rawValue] = totalTimeInSeconds[section] ?? 0 - return dict - } - } - - /// Start counting time spent for a given section - func start(_ section: Section) { - guard startTime[section] == nil else { - return - } - - startTime[section] = now() - } - - /// Stop counting time spent for a given section - func stop(_ section: Section) { - guard let startTime = startTime[section] else { - return - } - - let timeSince = now().timeIntervalSince(startTime) - - totalTimeInSeconds[section] = (totalTimeInSeconds[section] ?? 0) + round(timeSince) - self.startTime.removeValue(forKey: section) - } - - /// Stop counting time for all sections - @objc func stopAll() { - Section.allCases.forEach { stop($0) } - } - - /// Stop counting time for all sections and reset them to zero - @objc func reset() { - startTime = [:] - totalTimeInSeconds = [:] - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift index d22094efeba7..7cb5817cebb1 100644 --- a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift @@ -218,16 +218,6 @@ class ReaderDetailViewController: UIViewController, ReaderDetailView { toolbar.viewWillDisappear() } - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - ReaderTracker.shared.start(.readerPost) - } - - override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - ReaderTracker.shared.stop(.readerPost) - } - override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) @@ -356,14 +346,6 @@ class ReaderDetailViewController: UIViewController, ReaderDetailView { displayLoadingViewWithWebAction(title: LoadingText.errorLoadingTitle) } - @objc func willEnterForeground() { - guard isViewOnScreen() else { - return - } - - ReaderTracker.shared.start(.readerPost) - } - /// Scroll the content to a given #hash /// func scroll(to hash: String) { @@ -693,11 +675,6 @@ class ReaderDetailViewController: UIViewController, ReaderDetailView { } private func configureNotifications() { - NotificationCenter.default.addObserver(self, - selector: #selector(willEnterForeground), - name: UIApplication.willEnterForegroundNotification, - object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(siteBlocked(_:)), name: .ReaderSiteBlocked, diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 74c27682b589..bdb9db628ad5 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -349,8 +349,6 @@ import AutomatticTracks didSetupView = true - NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) - guard !shouldDisplayNoTopicController else { return } @@ -386,8 +384,6 @@ import AutomatticTracks super.viewWillDisappear(animated) dismissNoNetworkAlert() - - ReaderTracker.shared.stop(.filteredList) } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { @@ -413,14 +409,6 @@ import AutomatticTracks } } - @objc func willEnterForeground() { - guard isViewOnScreen() else { - return - } - - ReaderTracker.shared.start(.filteredList) - } - // MARK: - Topic acquisition /// Fetches a site topic for the value of the `siteID` property. diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift b/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift index 1566e56a3ad7..01cebc18fad6 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController+Swift.swift @@ -21,7 +21,7 @@ extension WPTabBarController { func showReader(path: ReaderNavigationPath?) { showReaderTab() if let path { - self.readerPresenter.navigate(to: path) + self.readerPresenter?.navigate(to: path) } } diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index b6b9d42734ac..c36ecf10fea6 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2541,8 +2541,6 @@ 8B74A9A9268E3C68003511CE /* RewindStatus+multiSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B74A9A7268E3C68003511CE /* RewindStatus+multiSite.swift */; }; 8B7C97E325A8BFA2004A3373 /* JetpackActivityLogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B7C97E225A8BFA2004A3373 /* JetpackActivityLogViewController.swift */; }; 8B7F25A724E6EDB4007D82CC /* TopicsCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B7F25A624E6EDB4007D82CC /* TopicsCollectionView.swift */; }; - 8B7F51C924EED804008CF5B5 /* ReaderTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B7F51C824EED804008CF5B5 /* ReaderTracker.swift */; }; - 8B7F51CB24EED8A8008CF5B5 /* ReaderTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B7F51CA24EED8A8008CF5B5 /* ReaderTrackerTests.swift */; }; 8B85AEDA259230FC00ADBEC9 /* ABTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B85AED9259230FC00ADBEC9 /* ABTest.swift */; }; 8B8C814D2318073300A0E620 /* BasePostTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B8C814C2318073300A0E620 /* BasePostTests.swift */; }; 8B8E50B627A4692000C89979 /* DashboardPostListErrorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B8E50B527A4692000C89979 /* DashboardPostListErrorCell.swift */; }; @@ -4799,7 +4797,6 @@ FABB22F92602FC2C00C8785C /* AccountToAccount22to23.swift in Sources */ = {isa = PBXBuildFile; fileRef = 937D9A1019F838C2007B9D5F /* AccountToAccount22to23.swift */; }; FABB22FB2602FC2C00C8785C /* ReaderFollowAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CB220AA6861008E8AE8 /* ReaderFollowAction.swift */; }; FABB22FC2602FC2C00C8785C /* SheetActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5D3992F2541F25B0058D0AB /* SheetActions.swift */; }; - FABB22FD2602FC2C00C8785C /* ReaderTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B7F51C824EED804008CF5B5 /* ReaderTracker.swift */; }; FABB22FE2602FC2C00C8785C /* PlanFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6F2787E21BC1A49008B4DB5 /* PlanFeature.swift */; }; FABB23002602FC2C00C8785C /* StockPhotosDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A3A5AE206A442800992576 /* StockPhotosDataSource.swift */; }; FABB23022602FC2C00C8785C /* OfflineReaderWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B24C4E2249A4C3E0005E8A5 /* OfflineReaderWebView.swift */; }; @@ -8036,8 +8033,6 @@ 8B74A9A7268E3C68003511CE /* RewindStatus+multiSite.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RewindStatus+multiSite.swift"; sourceTree = ""; }; 8B7C97E225A8BFA2004A3373 /* JetpackActivityLogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackActivityLogViewController.swift; sourceTree = ""; }; 8B7F25A624E6EDB4007D82CC /* TopicsCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopicsCollectionView.swift; sourceTree = ""; }; - 8B7F51C824EED804008CF5B5 /* ReaderTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTracker.swift; sourceTree = ""; }; - 8B7F51CA24EED8A8008CF5B5 /* ReaderTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderTrackerTests.swift; sourceTree = ""; }; 8B85AED9259230FC00ADBEC9 /* ABTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ABTest.swift; sourceTree = ""; }; 8B8C814C2318073300A0E620 /* BasePostTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasePostTests.swift; sourceTree = ""; }; 8B8E50B527A4692000C89979 /* DashboardPostListErrorCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardPostListErrorCell.swift; sourceTree = ""; }; @@ -14757,14 +14752,6 @@ path = Activity; sourceTree = ""; }; - 8B7F51C724EED488008CF5B5 /* Analytics */ = { - isa = PBXGroup; - children = ( - 8B7F51C824EED804008CF5B5 /* ReaderTracker.swift */, - ); - path = Analytics; - sourceTree = ""; - }; 8B85AED8259230C500ADBEC9 /* AB Testing */ = { isa = PBXGroup; children = ( @@ -16967,7 +16954,6 @@ children = ( 0CB1D6AE2C99A7380020766E /* Navigation */, FE6BF4DC2BA5C86A0040A190 /* Theme */, - 8B7F51C724EED488008CF5B5 /* Analytics */, 5D5A6E901B613C1800DAF819 /* Cards */, 9870EF7827866DCE00F3BB54 /* Comments */, 5D08B8FD19647C0800D5B381 /* Controllers */, @@ -17737,7 +17723,6 @@ 8BDA5A73247C5EAA00AB124C /* ReaderDetailCoordinatorTests.swift */, 748437ED1F1D4A7300E8DDAF /* RichContentFormatterTests.swift */, E6B9B8AE1B94FA1C0001B92F /* ReaderStreamViewControllerTests.swift */, - 8B7F51CA24EED8A8008CF5B5 /* ReaderTrackerTests.swift */, 3F1B66A123A2F52A0075F09E /* ReaderPostActions */, 08C42C30281807880034720B /* ReaderSubscribeCommentsActionTests.swift */, ); @@ -22068,7 +22053,6 @@ 018635842A8109DE00915532 /* SupportChatBotViewController.swift in Sources */, 0CED1FED2B61AAF600E6DD52 /* AtomicSiteService.swift in Sources */, FE29EFCD29A91160007CE034 /* WPAdminConvertibleRouter.swift in Sources */, - 8B7F51C924EED804008CF5B5 /* ReaderTracker.swift in Sources */, E6F2788421BC1A4A008B4DB5 /* PlanFeature.swift in Sources */, 931215E4267F5003008C3B69 /* ReferrerDetailsTableViewController.swift in Sources */, D8A3A5AF206A442800992576 /* StockPhotosDataSource.swift in Sources */, @@ -23952,7 +23936,6 @@ D848CC1920FF3A2400A9038F /* FormattableNotIconTests.swift in Sources */, 32110547250BFC3E0048446F /* ImageDimensionParserTests.swift in Sources */, E1AB5A3A1E0C464700574B4E /* DelayTests.swift in Sources */, - 8B7F51CB24EED8A8008CF5B5 /* ReaderTrackerTests.swift in Sources */, D848CC0320FF04FA00A9038F /* FormattableUserContentTests.swift in Sources */, F41D98E82B39E14F004EC050 /* DashboardDynamicCardAnalyticsEventTests.swift in Sources */, 5948AD111AB73D19006E8882 /* WPAppAnalyticsTests.m in Sources */, @@ -24981,7 +24964,6 @@ FABB22F92602FC2C00C8785C /* AccountToAccount22to23.swift in Sources */, FABB22FB2602FC2C00C8785C /* ReaderFollowAction.swift in Sources */, FABB22FC2602FC2C00C8785C /* SheetActions.swift in Sources */, - FABB22FD2602FC2C00C8785C /* ReaderTracker.swift in Sources */, 4A26E99A2C93AEE200C1D5DE /* SplitViewRootPresenter+Welcome.swift in Sources */, FEC1B0CF2BE41E1C00CB4A3D /* AdaptiveCollectionViewFlowLayout.swift in Sources */, FABB22FE2602FC2C00C8785C /* PlanFeature.swift in Sources */, diff --git a/WordPress/WordPressTest/ReaderTrackerTests.swift b/WordPress/WordPressTest/ReaderTrackerTests.swift deleted file mode 100644 index e278aa90a90a..000000000000 --- a/WordPress/WordPressTest/ReaderTrackerTests.swift +++ /dev/null @@ -1,73 +0,0 @@ -import UIKit -import XCTest -import Nimble - -@testable import WordPress - -class ReaderTrackerTests: XCTestCase { - - /// Return 20s as the time spent in Reader - /// - func testTrackTimeSpentInMainReader() { - let nowMock = DateMock(startTime: Date(), endTime: Date() + 20) - let tracker = ReaderTracker(now: nowMock.now) - tracker.start(.main) - - tracker.stop(.main) - - expect(tracker.data()).to(equal([ - "time_in_main_reader": 20, - "time_in_reader_filtered_list": 0, - "time_in_reader_post": 0 - ])) - } - - /// Return 16s as the time spent in filtered list - /// - func testTrackTimeSpentInFilteredList() { - let nowMock = DateMock(startTime: Date(), endTime: Date() + 15.5) - let tracker = ReaderTracker(now: nowMock.now) - tracker.start(.filteredList) - - tracker.stop(.filteredList) - - expect(tracker.data()).to(equal([ - "time_in_main_reader": 0, - "time_in_reader_filtered_list": 16, - "time_in_reader_post": 0 - ])) - } - - /// Return 60s as the time spent in post - /// - func testTrackTimeSpentInPost() { - let nowMock = DateMock(startTime: Date(), endTime: Date() + 60) - let tracker = ReaderTracker(now: nowMock.now) - tracker.start(.readerPost) - - tracker.stop(.readerPost) - - expect(tracker.data()).to(equal([ - "time_in_main_reader": 0, - "time_in_reader_filtered_list": 0, - "time_in_reader_post": 60 - ])) - } - -} - -private class DateMock { - private let startTime: Date - private let endTime: Date - var called = 0 - - init(startTime: Date, endTime: Date) { - self.startTime = startTime - self.endTime = endTime - } - - func now() -> Date { - called += 1 - return called == 1 ? startTime : endTime - } -} From 0bc7cf85d669edfd91b4fbf9e4baa3e75f62af46 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 14:53:08 -0400 Subject: [PATCH 31/55] Integrate new menu in ReaderDetailsVC --- ...PresentationController+PopoverAnchor.swift | 9 ----- .../Post/PostSharingController.swift | 16 ++------ .../Detail/ReaderDetailCoordinator.swift | 37 +----------------- .../Detail/ReaderDetailViewController.swift | 33 ++++++++++------ .../Views/ReaderDetailNewHeaderView.swift | 1 - .../ViewRelated/Reader/ReaderMenuAction.swift | 23 +---------- .../ViewRelated/Reader/ReaderPostCell.swift | 2 +- .../ViewRelated/Reader/ReaderPostMenu.swift | 6 +-- .../Reader/ReaderShareAction.swift | 8 ++-- .../Reader/ReaderShowMenuAction.swift | 14 +------ .../Contents.json | 24 ------------ .../icon-menu-vertical-ellipsis.pdf | Bin 3899 -> 0 bytes WordPress/WordPress.xcodeproj/project.pbxproj | 6 --- .../ReaderDetailCoordinatorTests.swift | 4 +- 14 files changed, 40 insertions(+), 143 deletions(-) delete mode 100644 WordPress/Classes/Extensions/UIPopoverPresentationController+PopoverAnchor.swift delete mode 100644 WordPress/Resources/AppImages.xcassets/icon-menu-vertical-ellipsis.imageset/Contents.json delete mode 100644 WordPress/Resources/AppImages.xcassets/icon-menu-vertical-ellipsis.imageset/icon-menu-vertical-ellipsis.pdf diff --git a/WordPress/Classes/Extensions/UIPopoverPresentationController+PopoverAnchor.swift b/WordPress/Classes/Extensions/UIPopoverPresentationController+PopoverAnchor.swift deleted file mode 100644 index 6fcef97a4ed7..000000000000 --- a/WordPress/Classes/Extensions/UIPopoverPresentationController+PopoverAnchor.swift +++ /dev/null @@ -1,9 +0,0 @@ -import UIKit - -extension UIPopoverPresentationController { - - enum PopoverAnchor { - case view(UIView) - case barButtonItem(UIBarButtonItem) - } -} diff --git a/WordPress/Classes/ViewRelated/Post/PostSharingController.swift b/WordPress/Classes/ViewRelated/Post/PostSharingController.swift index ea9fc0930b03..cc888440cadc 100644 --- a/WordPress/Classes/ViewRelated/Post/PostSharingController.swift +++ b/WordPress/Classes/ViewRelated/Post/PostSharingController.swift @@ -42,10 +42,10 @@ import SVProgressHUD } @objc func sharePost(_ title: String?, link: String?, fromView anchorView: UIView, inViewController viewController: UIViewController) { - sharePost(title, link: link, fromAnchor: .view(anchorView), inViewController: viewController) + sharePost(title, link: link, fromAnchor: anchorView, inViewController: viewController) } - private func sharePost(_ title: String?, link: String?, fromAnchor anchor: PopoverAnchor, inViewController viewController: UIViewController) { + private func sharePost(_ title: String?, link: String?, fromAnchor anchor: UIPopoverPresentationControllerSourceItem, inViewController viewController: UIViewController) { let controller = shareController(title, link: link) if !UIDevice.isPad() { viewController.present(controller, animated: true) @@ -57,13 +57,7 @@ import SVProgressHUD viewController.present(controller, animated: true) if let presentationController = controller.popoverPresentationController { presentationController.permittedArrowDirections = .any - switch anchor { - case .barButtonItem(let item): - presentationController.barButtonItem = item - case .view(let anchorView): - presentationController.sourceView = anchorView - presentationController.sourceRect = anchorView.bounds - } + presentationController.sourceItem = anchor } } @@ -91,7 +85,7 @@ import SVProgressHUD inViewController: viewController) } - func shareReaderPost(_ post: ReaderPost, fromAnchor anchor: PopoverAnchor, inViewController viewController: UIViewController) { + func shareReaderPost(_ post: ReaderPost, fromAnchor anchor: UIPopoverPresentationControllerSourceItem, inViewController viewController: UIViewController) { sharePost( post.titleForDisplay(), link: post.permaLink, @@ -127,6 +121,4 @@ import SVProgressHUD } } - - typealias PopoverAnchor = UIPopoverPresentationController.PopoverAnchor } diff --git a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift index 8f417261f36d..db1e0099953f 100644 --- a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift +++ b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift @@ -217,12 +217,12 @@ class ReaderDetailCoordinator { /// Share the current post /// func share(fromView anchorView: UIView) { - self.share(fromAnchor: .view(anchorView)) + self.share(fromAnchor: anchorView) } /// Share the current post /// - func share(fromAnchor anchor: UIPopoverPresentationController.PopoverAnchor) { + func share(fromAnchor anchor: UIPopoverPresentationControllerSourceItem) { guard let post = post, let view = viewController else { return } @@ -419,31 +419,6 @@ class ReaderDetailCoordinator { WPAppAnalytics.track(.readerSitePreviewed, withProperties: properties) } - /// Show a menu with options for the current post's site - /// - private func showMenu(_ anchor: UIPopoverPresentationController.PopoverAnchor) { - guard let post = post, - let context = post.managedObjectContext, - let viewController = viewController, - let followCommentsService = FollowCommentsService(post: post) else { - return - } - - self.followCommentsService = followCommentsService - - ReaderMenuAction(logged: ReaderHelpers.isLoggedIn()).execute( - post: post, - context: context, - readerTopic: readerTopic, - anchor: anchor, - vc: viewController, - source: ReaderPostMenuSource.details, - followCommentsService: followCommentsService - ) - - WPAnalytics.trackReader(.readerArticleDetailMoreTapped) - } - private func showTopic(_ topic: String) { let controller = ReaderStreamViewController.controllerWithTagSlug(topic) viewController?.navigationController?.pushViewController(controller, animated: true) @@ -717,14 +692,6 @@ extension ReaderDetailCoordinator: ReaderDetailHeaderViewDelegate { previewSite() } - func didTapMenuButton(_ sender: UIBarButtonItem) { - showMenu(.barButtonItem(sender)) - } - - func didTapMenuButton(_ sender: UIView) { - showMenu(.view(sender)) - } - func didTapTagButton() { showTag() } diff --git a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift index 7cb5817cebb1..5e4564e6fc04 100644 --- a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift @@ -702,11 +702,7 @@ class ReaderDetailViewController: UIViewController, ReaderDetailView { /// Ask the coordinator to present the share sheet /// @objc func didTapShareButton(_ sender: UIBarButtonItem) { - coordinator?.share(fromAnchor: .barButtonItem(sender)) - } - - @objc func didTapMenuButton(_ sender: UIBarButtonItem) { - coordinator?.didTapMenuButton(sender) + coordinator?.share(fromAnchor: sender) } @objc func didTapBrowserButton(_ sender: UIBarButtonItem) { @@ -1108,17 +1104,32 @@ private extension ReaderDetailViewController { } func moreButtonItem(enabled: Bool = true) -> UIBarButtonItem? { - guard let icon = UIImage(named: "icon-menu-vertical-ellipsis") else { - return nil - } - - let button = barButtonItem(with: icon, action: #selector(didTapMenuButton(_:))) + let button = UIBarButtonItem(image: UIImage(systemName: "ellipsis"), menu: nil) + button.menu = UIMenu(options: .displayInline, children: [ + UIDeferredMenuElement.uncached { [weak self, weak button] callback in + guard let self, let button else { + return callback([]) + } + callback(self.makeMoreMenu(button)) + } + ]) button.accessibilityLabel = Strings.moreButtonAccessibilityLabel button.isEnabled = enabled - return button } + func makeMoreMenu(_ anchor: UIPopoverPresentationControllerSourceItem) -> [UIMenuElement] { + guard let post else { + return [] + } + return ReaderPostMenu( + post: post, + topic: nil, + anchor: anchor, + viewController: self + ).makeMenu() + } + func shareButtonItem(enabled: Bool = true) -> UIBarButtonItem? { let button = barButtonItem(with: .gridicon(.shareiOS), action: #selector(didTapShareButton(_:))) button.accessibilityLabel = Strings.shareButtonAccessibilityLabel diff --git a/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailNewHeaderView.swift b/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailNewHeaderView.swift index 2621c60151f8..1f22d26d2f57 100644 --- a/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailNewHeaderView.swift +++ b/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailNewHeaderView.swift @@ -3,7 +3,6 @@ import WordPressUI protocol ReaderDetailHeaderViewDelegate: AnyObject { func didTapBlogName() - func didTapMenuButton(_ sender: UIView) func didTapHeaderAvatar() func didTapFollowButton(completion: @escaping () -> Void) func didSelectTopic(_ topic: String) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift b/WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift index 5dad962a93d3..be86283afe20 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift @@ -8,28 +8,7 @@ final class ReaderMenuAction { func execute(post: ReaderPost, context: NSManagedObjectContext, readerTopic: ReaderAbstractTopic? = nil, - anchor: UIView, - vc: UIViewController, - source: ReaderPostMenuSource, - followCommentsService: FollowCommentsService, - showAdditionalItems: Bool = false - ) { - self.execute( - post: post, - context: context, - readerTopic: readerTopic, - anchor: .view(anchor), - vc: vc, - source: source, - followCommentsService: followCommentsService, - showAdditionalItems: showAdditionalItems - ) - } - - func execute(post: ReaderPost, - context: NSManagedObjectContext, - readerTopic: ReaderAbstractTopic? = nil, - anchor: ReaderShowMenuAction.PopoverAnchor, + anchor: UIPopoverPresentationControllerSourceItem, vc: UIViewController, source: ReaderPostMenuSource, followCommentsService: FollowCommentsService, diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderPostCell.swift b/WordPress/Classes/ViewRelated/Reader/ReaderPostCell.swift index 6725916567e8..54feb9bf4d02 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderPostCell.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderPostCell.swift @@ -280,7 +280,7 @@ private final class ReaderPostCellView: UIView { return ReaderPostMenu( post: viewModel.post, topic: viewController.readerTopic, - button: buttonMore, + anchor: buttonMore, viewController: viewController ).makeMenu() } diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift b/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift index 5805cac25673..2297547322b7 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift @@ -5,7 +5,7 @@ import SafariServices struct ReaderPostMenu { let post: ReaderPost let topic: ReaderAbstractTopic? - weak var button: UIButton? + weak var anchor: UIPopoverPresentationControllerSourceItem? weak var viewController: UIViewController? var context = ContextManager.shared.mainContext @@ -54,7 +54,7 @@ struct ReaderPostMenu { private var share: UIAction { UIAction(Strings.share, systemImage: "square.and.arrow.up") { guard let viewController else { return } - ReaderShareAction().execute(with: post, context: context, anchor: button ?? viewController.view, vc: viewController) + ReaderShareAction().execute(with: post, context: context, anchor: anchor ?? viewController.view, vc: viewController) track(.share) } } @@ -145,7 +145,7 @@ struct ReaderPostMenu { private func manageNotifications(for siteID: Int) -> UIAction { UIAction(Strings.manageNotifications, systemImage: "bell") { guard let viewController else { return } - NotificationSiteSubscriptionViewController.show(forSiteID: siteID, sourceItem: button ?? viewController.view, from: viewController) + NotificationSiteSubscriptionViewController.show(forSiteID: siteID, sourceItem: anchor ?? viewController.view, from: viewController) track(.manageNotifications) } } diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderShareAction.swift b/WordPress/Classes/ViewRelated/Reader/ReaderShareAction.swift index 0847e8c54b75..cf5b9f72ab43 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderShareAction.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderShareAction.swift @@ -1,10 +1,8 @@ +import UIKit + /// Encapsulates a command share a post final class ReaderShareAction { - func execute(with post: ReaderPost, context: NSManagedObjectContext, anchor: UIView, vc: UIViewController) { - self.execute(with: post, context: context, anchor: .view(anchor), vc: vc) - } - - func execute(with post: ReaderPost, context: NSManagedObjectContext, anchor: UIPopoverPresentationController.PopoverAnchor, vc: UIViewController) { + func execute(with post: ReaderPost, context: NSManagedObjectContext, anchor: UIPopoverPresentationControllerSourceItem, vc: UIViewController) { let postID = post.objectID if let post: ReaderPost = ReaderActionHelpers.existingObject(for: postID, in: context) { let sharingController = PostSharingController() diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift b/WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift index 9d72ed702aed..7d898327512f 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift @@ -11,7 +11,7 @@ final class ReaderShowMenuAction { context: NSManagedObjectContext, siteTopic: ReaderSiteTopic? = nil, readerTopic: ReaderAbstractTopic? = nil, - anchor: PopoverAnchor, + anchor: UIPopoverPresentationControllerSourceItem, vc: UIViewController, source: ReaderPostMenuSource, followCommentsService: FollowCommentsService, @@ -224,13 +224,7 @@ final class ReaderShowMenuAction { vc.present(alertController, animated: true) if let presentationController = alertController.popoverPresentationController { presentationController.permittedArrowDirections = .any - switch anchor { - case .barButtonItem(let item): - presentationController.barButtonItem = item - case .view(let anchor): - presentationController.sourceView = anchor - presentationController.sourceRect = anchor.bounds - } + presentationController.sourceItem = anchor } } else { vc.present(alertController, animated: true) @@ -317,8 +311,4 @@ final class ReaderShowMenuAction { let userInfo: [String: Any] = [ReaderNotificationKeys.post: post, ReaderNotificationKeys.result: result] center.post(name: .ReaderUserBlockingDidEnd, object: nil, userInfo: userInfo) } - - // MARK: - Types - - typealias PopoverAnchor = UIPopoverPresentationController.PopoverAnchor } diff --git a/WordPress/Resources/AppImages.xcassets/icon-menu-vertical-ellipsis.imageset/Contents.json b/WordPress/Resources/AppImages.xcassets/icon-menu-vertical-ellipsis.imageset/Contents.json deleted file mode 100644 index 1c4534e95db1..000000000000 --- a/WordPress/Resources/AppImages.xcassets/icon-menu-vertical-ellipsis.imageset/Contents.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "images" : [ - { - "filename" : "icon-menu-vertical-ellipsis.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/WordPress/Resources/AppImages.xcassets/icon-menu-vertical-ellipsis.imageset/icon-menu-vertical-ellipsis.pdf b/WordPress/Resources/AppImages.xcassets/icon-menu-vertical-ellipsis.imageset/icon-menu-vertical-ellipsis.pdf deleted file mode 100644 index dccb0e9cda28f1e1e2aa7444526da2b7719ca174..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3899 zcmai%c{G&m|Hmy;7!qZPlsj1?vs;pVnMB!IjD0W|+te6KWGl;qk!($rWXZl2MKol| zk{*+6Nl3P2%aUDwGcCWT=k)!a?|tUXeVxzszCP!=-tYU5*Ck=Bqjwx8j{r+FjW3Q* z=PuoU-P8<50#JZp?+QM75`Y-uJe^4{0E%8R1t5BOcM^_Bf4gHzI31h=!4U_jse!#n zL>$%w?8mHX+zxJpa@9=Ak`5OcyhFw<)!xqy)UYGH=03e6Dmj3G+z=Z`NMPmUCbRRZ zY#F=m`-I`!FOGaVdBjh_J+oC0>tK2dTCK+GaXnIIIm+em9$C;_QSZZJR(wZ0efK^0 zGqRcayYeFO+v3W5gbmWLt{~{kzK*Xwp6ok!X9t0L7mT ze(Rz1TaTZqDSuZ%&eAso(PSj&NskSH=-_2| zu`KM*0lZN;#Sb!x(ho6ai3pSQ(b=WP$18Ke@!WG}bflPrE+6OhYxaE{i#*27^(H#H z3j`?EL(opJl3ud@~va+w=c|NeOn#p+U8mNI}&K!cwFz1__uD9B^zrAUdk6k5ho`QdQFF=dyA@?l9G3-xqM|#KE$zRK(5YM(yMnTI9^OqTYNVYShq*vWRRrb zI7^aQ`3oWV4(R1_vJ5-|1{cWS$Se{YZ7OwN$(@j`X}e949Lo^KbO=2|-Xqr-52Z?s zWRXD`R<|WSIA>jD!%@%ar!tMNN_Taw-8E!_@}=0mnv~3NkAmy+3C%?uMIyWC^)%W)oy21V)H=kWI3#*cq$b=p`cH(R%d$tE?P8Trf4khWaGbpt9GQcAd` z%PfKMNO6guEf$%b#q>_Ntk?Aq9}Y6xR&Dj)Jij10L%XL*zK0ohpDBV+1(;UEE$$pD zuT4JBRN=8(V|=8@XdYl%+{IKeba&}+gu6{b(?>2T&X}1QcQ592H+k7liks=z2rug* zlvh*Q=Qb~>S9x|upDW}4ZflggoBmvIA^g*M zlTS$;VNotM;U`1QZ^}D@!-9K8f)6N2u?YpGx$(Jp+cE`)D;rnov$YabnY53xihHX2 zvjk3C^1#5Ywa;9N<4e8b;QrqxH$*wDqCH0pHO0&(R=DCEi4vJ|LRrIM?)5DDZnBZ? zgOQ=~P!>76Jt859ORPfxQ&`9;9@bl|@~2qv8lXp-YHyjqny|ObKG$6@F?EOfzXqMX zrf_Mu73kvgJ(oDSLeLuEh3WZr>e*9$VVja8SAl7y?-t*>v~XL}7GcW*NXhVkBJ>B8=L%k(6qzf47h z9o^9WLC25(E}P)UpMt8clN=jv8UoMkFoBK%)s70AkZu{8i^r~*k8c*+MkB@+;+Hq!BB8Q!HEYE zx_<3}eb2)jbEzVA9}WfHJF&-`F4)D{S(Z^AvcAR6sEBa4JQw;Xaw(|lfEC;mRRXHq z+efYmnQq)OBDvuA?AQ?B{I$LHUSI659;pQfiv%AYjuUOJle)=a0dl*x_sA_k++F+} zk1+cr`*s*_1JWck&xj-z!E>d_%3kK-jklW5^hG4kCi3Y=hzpvE%cN9~vzAnq zq#j9ZJK=~X9>8eW7?p^p1GW--6V#29q$T-`PK)Sj^`BKf{Z!+M#ue=crhD={yUh!3 zSEpGRQFQ`O2SU(^2+9&=w5>R?Fy1YBni3#kl+;J@rP#`+OW7U?KK(6ctBS>>UZdVD zG^^}FhTcd;gKD_GZfa(-{a^N}_EGlNKcZfkNIXjjO{m;wl&>*W_D15t5n-*a2Up%y zRh+3f@ecP6dI+tUz1fvG^X{gwG38kj*HeRL|75)bZ3w zWJ`sM1?OXs#kj@fV;g94%G|4SP7>uY${EEav$@AR)v^Z*Rf`?+%FUg#&X#xVw@#3^ zRMf1rsxox>(F(U!7rb`2Hx4lXx^#M%ZSdX!`{PYjW`@F zh%f9smSvHp(yZk0Dn6HOG`?#}b+dK| zY>99kbtv!18Ju`roPT`Sr*1Y-CDpoYP@v{)4Q+*cMQl@Y6UL?*=@&`mUVTgQk*)~~ z?BSjMG*Z>EKpth23Xpo(rJp;ThUt*$*wc~4$tCzju>1G{V&~-z@oLK?Gt{I1I1;{zu|R2UJh9#Idi4zykC%?FX*_vu8ww7 z&8fK7H?8QHSOEh8U%fW;3*8>{8QlO~imn00Tnowd~JcttZD6CV5(qtXwpkJcTuRqFSr1|)R_aocI(6Rian@L$Ri2Tm{ zzwu!eYZYBu64>Z6S!;x<6cy5l%z|oHzr^>NdG=QdVo{Qa(S?to2mOWQ2OW!;;(mg*(6d z?4VP5vFiXu%%=0Jef!7gk46&j6Q+kTffv^YU#*1AQXi~5*!2D2!|wZjaH@LAJjEVk z)Bn2UgLU!vtHsR4%9@KawHL6Km+kiA;~e8E;CYXzr%PSYJ-MH=KZgp(rA|;k2UO0c zy=xihs~h$R?qZH*eZi)7m`~(caOwfv>C0WH3R z|Lz^-bl;#wt>*BBm?*)>6BkKp)fHoJ(n`uohT20Zr8WysiTMN6&8_p4Lgx}?Yn8yX zKpi@{2F+WJ=d)c%96*C#%Vwh3P@Qn^b4} zwx%y`ozp4mr-$-tl{b1!x-v+H`K@-UP<04k$g8vTvek2(>xYKV*B>Ey9I)#I!bxy#ca3~Z7N5Pa(NCd(H z3YDV&=(;lmM}`FW?~;G^=tsmkfuR5l28RCs11O+S2o&H1{H!4mD7v?d2k`t=gCbyb zi~e0hz~O)DpzuF*P`ENZoPV!{B9#BoAz=SOhg6{F@b9$xgC^@09NF-JX=HTR{ nq=0}bD Date: Fri, 25 Oct 2024 15:26:10 -0400 Subject: [PATCH 32/55] Remove ReaderMenuAction --- .../ViewRelated/Reader/ReaderMenuAction.swift | 31 ------------------- .../Reader/ReaderPostCardCellViewModel.swift | 18 +---------- WordPress/WordPress.xcodeproj/project.pbxproj | 6 ---- 3 files changed, 1 insertion(+), 54 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift b/WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift deleted file mode 100644 index be86283afe20..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift +++ /dev/null @@ -1,31 +0,0 @@ -final class ReaderMenuAction { - private let isLoggedIn: Bool - - init(logged: Bool) { - isLoggedIn = logged - } - - func execute(post: ReaderPost, - context: NSManagedObjectContext, - readerTopic: ReaderAbstractTopic? = nil, - anchor: UIPopoverPresentationControllerSourceItem, - vc: UIViewController, - source: ReaderPostMenuSource, - followCommentsService: FollowCommentsService, - showAdditionalItems: Bool = false - ) { - let siteTopic: ReaderSiteTopic? = post.isFollowing ? (try? ReaderSiteTopic.lookup(withSiteID: post.siteID, in: context)) : nil - - ReaderShowMenuAction(loggedIn: isLoggedIn).execute( - with: post, - context: context, - siteTopic: siteTopic, - readerTopic: readerTopic, - anchor: anchor, - vc: vc, - source: source, - followCommentsService: followCommentsService, - showAdditionalItems: showAdditionalItems - ) - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderPostCardCellViewModel.swift b/WordPress/Classes/ViewRelated/Reader/ReaderPostCardCellViewModel.swift index 2b94c9e0cc83..75914f265c48 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderPostCardCellViewModel.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderPostCardCellViewModel.swift @@ -207,23 +207,7 @@ struct ReaderPostCardCellViewModel { } mutating func showMore(with anchor: UIView) { - guard let readerPost, - let parentViewController, - let followCommentsService = FollowCommentsService(post: readerPost) else { - return - } - self.followCommentsService = followCommentsService - - ReaderMenuAction(logged: actionVisibility.isEnabled).execute( - post: readerPost, - context: parentViewController.viewContext, - readerTopic: parentViewController.readerTopic, - anchor: anchor, - vc: parentViewController, - source: ReaderPostMenuSource.card, - followCommentsService: followCommentsService - ) - WPAnalytics.trackReader(.postCardMoreTapped) + // Do nothing } } diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 47985f877493..eaeac4948f2a 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -3357,7 +3357,6 @@ D8212CC320AA7F57008E8AE8 /* ReaderBlockSiteAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CC220AA7F57008E8AE8 /* ReaderBlockSiteAction.swift */; }; D8212CC520AA83F9008E8AE8 /* ReaderCommentAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CC420AA83F9008E8AE8 /* ReaderCommentAction.swift */; }; D8212CC720AA85C1008E8AE8 /* ReaderHeaderAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CC620AA85C1008E8AE8 /* ReaderHeaderAction.swift */; }; - D8212CC920AA87E5008E8AE8 /* ReaderMenuAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CC820AA87E5008E8AE8 /* ReaderMenuAction.swift */; }; D821C817210036D9002ED995 /* ActivityContentFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D821C816210036D9002ED995 /* ActivityContentFactoryTests.swift */; }; D821C819210037F8002ED995 /* activity-log-activity-content.json in Resources */ = {isa = PBXBuildFile; fileRef = D821C818210037F8002ED995 /* activity-log-activity-content.json */; }; D821C81B21003AE9002ED995 /* FormattableContentGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D821C81A21003AE9002ED995 /* FormattableContentGroupTests.swift */; }; @@ -4864,7 +4863,6 @@ FABB234B2602FC2C00C8785C /* UIBarButtonItem+MeBarButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3FCCAA1423F4A1A3004064C0 /* UIBarButtonItem+MeBarButton.swift */; }; FABB234C2602FC2C00C8785C /* PostSettingsViewController+FeaturedImageUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEECFFB2084DE2B009B8CDB /* PostSettingsViewController+FeaturedImageUpload.swift */; }; FABB234D2602FC2C00C8785C /* ReaderLikeAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CB020AA64E1008E8AE8 /* ReaderLikeAction.swift */; }; - FABB234E2602FC2C00C8785C /* ReaderMenuAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CC820AA87E5008E8AE8 /* ReaderMenuAction.swift */; }; FABB234F2602FC2C00C8785C /* PostSharingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 593F26601CAB00CA00F14073 /* PostSharingController.swift */; }; FABB23502602FC2C00C8785C /* LongPressGestureLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FA37B19215724E900C80377 /* LongPressGestureLabel.swift */; }; FABB23532602FC2C00C8785C /* UIImage+Export.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF70A3211FD5840500BC270D /* UIImage+Export.swift */; }; @@ -8804,7 +8802,6 @@ D8212CC220AA7F57008E8AE8 /* ReaderBlockSiteAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderBlockSiteAction.swift; sourceTree = ""; }; D8212CC420AA83F9008E8AE8 /* ReaderCommentAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderCommentAction.swift; sourceTree = ""; }; D8212CC620AA85C1008E8AE8 /* ReaderHeaderAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderHeaderAction.swift; sourceTree = ""; }; - D8212CC820AA87E5008E8AE8 /* ReaderMenuAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderMenuAction.swift; sourceTree = ""; }; D821C816210036D9002ED995 /* ActivityContentFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityContentFactoryTests.swift; sourceTree = ""; }; D821C818210037F8002ED995 /* activity-log-activity-content.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "activity-log-activity-content.json"; sourceTree = ""; }; D821C81A21003AE9002ED995 /* FormattableContentGroupTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormattableContentGroupTests.swift; sourceTree = ""; }; @@ -16987,7 +16984,6 @@ D8212CB220AA6861008E8AE8 /* ReaderFollowAction.swift */, D8212CC620AA85C1008E8AE8 /* ReaderHeaderAction.swift */, D8212CB020AA64E1008E8AE8 /* ReaderLikeAction.swift */, - D8212CC820AA87E5008E8AE8 /* ReaderMenuAction.swift */, 3F8CB10523A07B17007627BF /* ReaderReblogAction.swift */, 3F5B3EB023A851480060FF1F /* ReaderReblogFormatter.swift */, 3F5B3EAE23A851330060FF1F /* ReaderReblogPresenter.swift */, @@ -22164,7 +22160,6 @@ D8212CB120AA64E1008E8AE8 /* ReaderLikeAction.swift in Sources */, 0CDDCA082C8F4126005AACA3 /* ReaderTagsAddTagView.swift in Sources */, 01D7EBA42B7A4BBD00F14992 /* HashableImmutableRow.swift in Sources */, - D8212CC920AA87E5008E8AE8 /* ReaderMenuAction.swift in Sources */, 593F26611CAB00CA00F14073 /* PostSharingController.swift in Sources */, 2FA37B1A215724E900C80377 /* LongPressGestureLabel.swift in Sources */, 0C13ACC92BF406E700FF7405 /* VoiceToContentViewModel.swift in Sources */, @@ -25089,7 +25084,6 @@ FABB234D2602FC2C00C8785C /* ReaderLikeAction.swift in Sources */, 245562372C5C107800A15446 /* AcknowledgementsService.swift in Sources */, DCF892CD282FA3BB00BB71E1 /* SiteStatsImmuTableRows.swift in Sources */, - FABB234E2602FC2C00C8785C /* ReaderMenuAction.swift in Sources */, FABB234F2602FC2C00C8785C /* PostSharingController.swift in Sources */, FABB23502602FC2C00C8785C /* LongPressGestureLabel.swift in Sources */, FABB23532602FC2C00C8785C /* UIImage+Export.swift in Sources */, From 6ff6a63008196d7876ed528e5453dcc9ebf8383a Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 15:27:53 -0400 Subject: [PATCH 33/55] Remove ReaderShowMenuAction --- .../Reader/ReaderShowMenuAction.swift | 314 ------------------ WordPress/WordPress.xcodeproj/project.pbxproj | 6 - 2 files changed, 320 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift b/WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift deleted file mode 100644 index 7d898327512f..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift +++ /dev/null @@ -1,314 +0,0 @@ -import UIKit -/// Encapsulates a command to create and handle the extended menu for each post in Reader -final class ReaderShowMenuAction { - private let isLoggedIn: Bool - - init(loggedIn: Bool) { - isLoggedIn = loggedIn - } - - func execute(with post: ReaderPost, - context: NSManagedObjectContext, - siteTopic: ReaderSiteTopic? = nil, - readerTopic: ReaderAbstractTopic? = nil, - anchor: UIPopoverPresentationControllerSourceItem, - vc: UIViewController, - source: ReaderPostMenuSource, - followCommentsService: FollowCommentsService, - showAdditionalItems: Bool = false - ) { - - // Create the action sheet - let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) - alertController.addCancelActionWithTitle(ReaderPostMenuButtonTitles.cancel, handler: nil) - - // Block site button - if shouldShowBlockSiteMenuItem(readerTopic: readerTopic, post: post) || showAdditionalItems { - let handler: (UIAlertAction) -> Void = { action in - guard let post: ReaderPost = ReaderActionHelpers.existingObject(for: post.objectID, in: context) else { - return - } - self.postSiteBlockingWillBeginNotification(post) - ReaderBlockSiteAction(asBlocked: true).execute(with: post, context: context, completion: { - ReaderHelpers.dispatchSiteBlockedMessage(post: post, success: true) - self.postSiteBlockingDidFinish(post) - }, - failure: { error in - ReaderHelpers.dispatchSiteBlockedMessage(post: post, success: false) - self.postSiteBlockingDidFail(post, error: error) - }) - } - alertController.addActionWithTitle(ReaderPostMenuButtonTitles.blockSite, - style: .destructive, - handler: handler) - } - - // Block user button - if shouldShowBlockUserMenuItem(topic: readerTopic, post: post) || showAdditionalItems { - let handler: (UIAlertAction) -> Void = { _ in - guard let post: ReaderPost = ReaderActionHelpers.existingObject(for: post.objectID, in: context) else { - return - } - self.postUserBlockingWillBeginNotification(post) - let action = ReaderBlockUserAction(context: context) - action.execute(with: post, blocked: true) { result in - switch result { - case .success: - ReaderHelpers.dispatchUserBlockedMessage(post: post, success: true) - case .failure: - ReaderHelpers.dispatchUserBlockedMessage(post: post, success: false) - } - self.postUserBlockingDidFinishNotification(post, result: result) - } - } - alertController.addActionWithTitle( - ReaderPostMenuButtonTitles.blockUser, - style: .destructive, - handler: handler - ) - } - - // Report post button - if shouldShowReportPostMenuItem(readerTopic: readerTopic, post: post) || showAdditionalItems { - alertController.addActionWithTitle(ReaderPostMenuButtonTitles.reportPost, - style: .destructive, - handler: { (action: UIAlertAction) in - if let post: ReaderPost = ReaderActionHelpers.existingObject(for: post.objectID, in: context) { - ReaderReportPostAction().execute(with: post, context: context, origin: vc) - } - }) - } - - // Report user button - if shouldShowReportUserMenuItem(readerTopic: readerTopic, post: post) || showAdditionalItems { - let handler: (UIAlertAction) -> Void = { _ in - guard let post: ReaderPost = ReaderActionHelpers.existingObject(for: post.objectID, in: context) else { - return - } - ReaderReportPostAction().execute(with: post, target: .author, context: context, origin: vc) - } - alertController.addActionWithTitle(ReaderPostMenuButtonTitles.reportPostAuthor, style: .destructive, handler: handler) - } - - // Notification - if let siteTopic = siteTopic, isLoggedIn, post.isFollowing { - let isSubscribedForPostNotifications = siteTopic.isSubscribedForPostNotifications - let buttonTitle = isSubscribedForPostNotifications ? ReaderPostMenuButtonTitles.unsubscribe : ReaderPostMenuButtonTitles.subscribe - alertController.addActionWithTitle(buttonTitle, - style: .default, - handler: { (action: UIAlertAction) in - if let topic: ReaderSiteTopic = ReaderActionHelpers.existingObject(for: siteTopic.objectID, in: context) { - let subscribe = !topic.isSubscribedForPostNotifications - - ReaderSubscribingNotificationAction().execute(for: topic.siteID, context: context, subscribe: subscribe, completion: { - ReaderHelpers.dispatchToggleNotificationMessage(topic: topic, success: true) - }, failure: { _ in - ReaderHelpers.dispatchToggleNotificationMessage(topic: topic, success: false) - }) - } - }) - } - - // Reblog - // - // Only show the Reblog menu when: - // - The site is not private, - // - The user is logged in, - // - and the user uses accessibility content size. - if !post.isPrivate(), - isLoggedIn, - let vc = vc as? ReaderStreamViewController, - vc.traitCollection.preferredContentSizeCategory.isAccessibilityCategory { - let buttonTitle = ReaderPostCardCell.Constants.reblogButtonText - - alertController.addActionWithTitle(buttonTitle, style: .default) { _ in - ReaderReblogAction().execute(readerPost: post, origin: vc, reblogSource: .list) - } - } - - // Save post - if let vc = vc as? ReaderStreamViewController { - let buttonTitle = post.isSavedForLater ? ReaderPostMenuButtonTitles.removeSavedPost: ReaderPostMenuButtonTitles.savePost - - alertController.addActionWithTitle(buttonTitle, style: .default) { _ in - if vc.contentType == .saved { - vc.removePost(post) - } else { - vc.togglePostSave(post) - } - } - } - - // Following - if isLoggedIn { - let buttonTitle = post.isFollowing ? ReaderPostMenuButtonTitles.unfollow : ReaderPostMenuButtonTitles.follow - - alertController.addActionWithTitle(buttonTitle, - style: .default, - handler: { (action: UIAlertAction) in - if let post: ReaderPost = ReaderActionHelpers.existingObject(for: post.objectID, in: context) { - ReaderFollowAction().execute(with: post, - context: context, - completion: { follow in - ReaderHelpers.dispatchToggleFollowSiteMessage(post: post, follow: follow, success: true) - (vc as? ReaderStreamViewController)?.updateStreamHeaderIfNeeded() - }, failure: { follow, _ in - ReaderHelpers.dispatchToggleFollowSiteMessage(post: post, follow: follow, success: false) - }) - } - }) - } - - // Seen - if post.isSeenSupported { - alertController.addActionWithTitle(post.isSeen ? ReaderPostMenuButtonTitles.markUnseen : ReaderPostMenuButtonTitles.markSeen, - style: .default, - handler: { (action: UIAlertAction) in - - let event: WPAnalyticsEvent = post.isSeen ? .readerPostMarkUnseen : .readerPostMarkSeen - WPAnalytics.track(event, properties: ["source": source.description]) - - if let post: ReaderPost = ReaderActionHelpers.existingObject(for: post.objectID, in: context) { - ReaderSeenAction().execute(with: post, context: context, completion: { - ReaderHelpers.dispatchToggleSeenMessage(post: post, success: true) - - // Notify Reader Stream so the post card is updated. - NotificationCenter.default.post(name: .ReaderPostSeenToggled, - object: nil, - userInfo: [ReaderNotificationKeys.post: post]) - }, - failure: { _ in - ReaderHelpers.dispatchToggleSeenMessage(post: post, success: false) - }) - } - }) - } - - // Visit - alertController.addActionWithTitle(ReaderPostMenuButtonTitles.visit, - style: .default, - handler: { (action: UIAlertAction) in - ReaderVisitSiteAction().execute(with: post, context: context, origin: vc) - }) - - // Share - alertController.addActionWithTitle(ReaderPostMenuButtonTitles.share, - style: .default, - handler: { (action: UIAlertAction) in - ReaderShareAction().execute(with: post, context: context, anchor: anchor, vc: vc) - }) - - // Comment Subscription (Follow Comments by Email & Notifications) - if post.canSubscribeComments { - let buttonTitle = post.isSubscribedComments ? ReaderPostMenuButtonTitles.unFollowConversation : ReaderPostMenuButtonTitles.followConversation - alertController.addActionWithTitle( - buttonTitle, - style: .default, - handler: { (action: UIAlertAction) in - if let post: ReaderPost = ReaderActionHelpers.existingObject(for: post.objectID, in: context) { - Self.trackToggleCommentSubscription(isSubscribed: post.isSubscribedComments, post: post, sourceViewController: vc) - - ReaderSubscribeCommentsAction().execute( - with: post, - context: context, - followCommentsService: followCommentsService, - sourceViewController: vc) { - (vc as? ReaderDetailViewController)?.updateFollowButtonState() - } - } - }) - } - - if WPDeviceIdentification.isiPad() { - alertController.modalPresentationStyle = .popover - vc.present(alertController, animated: true) - if let presentationController = alertController.popoverPresentationController { - presentationController.permittedArrowDirections = .any - presentationController.sourceItem = anchor - } - } else { - vc.present(alertController, animated: true) - } - } - - private func shouldShowBlockSiteMenuItem(readerTopic: ReaderAbstractTopic?, post: ReaderPost) -> Bool { - guard let topic = readerTopic, - isLoggedIn else { - return false - } - - return ReaderHelpers.isTopicTag(topic) || - ReaderHelpers.topicIsDiscover(topic) || - ReaderHelpers.topicIsFreshlyPressed(topic) || - ReaderHelpers.topicIsFollowing(topic) - } - - private func shouldShowReportUserMenuItem(readerTopic: ReaderAbstractTopic?, post: ReaderPost) -> Bool { - return shouldShowReportPostMenuItem(readerTopic: readerTopic, post: post) - } - - private func shouldShowBlockUserMenuItem(topic: ReaderAbstractTopic?, post: ReaderPost) -> Bool { - return shouldShowReportUserMenuItem(readerTopic: topic, post: post) - && post.isWPCom - } - - private func shouldShowReportPostMenuItem(readerTopic: ReaderAbstractTopic?, post: ReaderPost) -> Bool { - return shouldShowBlockSiteMenuItem(readerTopic: readerTopic, post: post) - } - - private static func trackToggleCommentSubscription(isSubscribed: Bool, post: ReaderPost, sourceViewController: UIViewController) { - var properties = [String: Any]() - properties[WPAppAnalyticsKeyFollowAction] = isSubscribed ? "followed" : "unfollowed" - properties["notifications_enabled"] = isSubscribed - properties[WPAppAnalyticsKeyBlogID] = post.siteID - properties[WPAppAnalyticsKeySource] = Self.sourceForTrackingEvents(sourceViewController: sourceViewController) - WPAnalytics.trackReader(.readerMoreToggleFollowConversation, properties: properties) - } - - private static func sourceForTrackingEvents(sourceViewController: UIViewController) -> String { - if sourceViewController is ReaderDetailViewController { - return "reader_post_details_comments" - } else if sourceViewController is ReaderStreamViewController { - return "reader" - } - - return "unknown" - } - - // MARK: - Sending Notifications - - private func postSiteBlockingWillBeginNotification(_ post: ReaderPost) { - NotificationCenter.default.post(name: .ReaderSiteBlockingWillBegin, - object: nil, - userInfo: [ReaderNotificationKeys.post: post]) - } - - /// Notify Reader Cards Stream so the post card is updated. - private func postSiteBlockingDidFinish(_ post: ReaderPost) { - NotificationCenter.default.post(name: .ReaderSiteBlocked, - object: nil, - userInfo: [ReaderNotificationKeys.post: post]) - } - - private func postSiteBlockingDidFail(_ post: ReaderPost, error: Error?) { - var userInfo: [String: Any] = [ReaderNotificationKeys.post: post] - if let error { - userInfo[ReaderNotificationKeys.error] = error - } - NotificationCenter.default.post(name: .ReaderSiteBlockingFailed, - object: nil, - userInfo: userInfo) - } - - private func postUserBlockingWillBeginNotification(_ post: ReaderPost) { - NotificationCenter.default.post(name: .ReaderUserBlockingWillBegin, - object: nil, - userInfo: [ReaderNotificationKeys.post: post]) - } - - private func postUserBlockingDidFinishNotification(_ post: ReaderPost, result: Result) { - let center = NotificationCenter.default - let userInfo: [String: Any] = [ReaderNotificationKeys.post: post, ReaderNotificationKeys.result: result] - center.post(name: .ReaderUserBlockingDidEnd, object: nil, userInfo: userInfo) - } -} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index eaeac4948f2a..fa9b216e435f 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -3353,7 +3353,6 @@ D8212CB720AA7703008E8AE8 /* ReaderShareAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CB620AA7703008E8AE8 /* ReaderShareAction.swift */; }; D8212CB920AA77AD008E8AE8 /* ReaderActionHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CB820AA77AD008E8AE8 /* ReaderActionHelpers.swift */; }; D8212CBD20AA7A7A008E8AE8 /* ReaderVisitSiteAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CBC20AA7A7A008E8AE8 /* ReaderVisitSiteAction.swift */; }; - D8212CC120AA7C58008E8AE8 /* ReaderShowMenuAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CC020AA7C58008E8AE8 /* ReaderShowMenuAction.swift */; }; D8212CC320AA7F57008E8AE8 /* ReaderBlockSiteAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CC220AA7F57008E8AE8 /* ReaderBlockSiteAction.swift */; }; D8212CC520AA83F9008E8AE8 /* ReaderCommentAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CC420AA83F9008E8AE8 /* ReaderCommentAction.swift */; }; D8212CC720AA85C1008E8AE8 /* ReaderHeaderAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CC620AA85C1008E8AE8 /* ReaderHeaderAction.swift */; }; @@ -5098,7 +5097,6 @@ FABB246B2602FC2C00C8785C /* SiteManagementService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA4ADAD71C50687400F858D7 /* SiteManagementService.swift */; }; FABB246C2602FC2C00C8785C /* ActivityPostRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E4A773120F800CB001C706D /* ActivityPostRange.swift */; }; FABB246D2602FC2C00C8785C /* ReaderSelectInterestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32E1BFFB24AB9D28007A08F0 /* ReaderSelectInterestsViewController.swift */; }; - FABB246E2602FC2C00C8785C /* ReaderShowMenuAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8212CC020AA7C58008E8AE8 /* ReaderShowMenuAction.swift */; }; FABB24702602FC2C00C8785C /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5552D7F1CD1028C00B26DF6 /* String+Extensions.swift */; }; FABB24712602FC2C00C8785C /* CollapsableHeaderFilterBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 469EB16724D9AD8B00C764CB /* CollapsableHeaderFilterBar.swift */; }; FABB24722602FC2C00C8785C /* AutomatedTransferHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40247E012120FE3600AE1C3C /* AutomatedTransferHelper.swift */; }; @@ -8798,7 +8796,6 @@ D8212CB620AA7703008E8AE8 /* ReaderShareAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderShareAction.swift; sourceTree = ""; }; D8212CB820AA77AD008E8AE8 /* ReaderActionHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderActionHelpers.swift; sourceTree = ""; }; D8212CBC20AA7A7A008E8AE8 /* ReaderVisitSiteAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderVisitSiteAction.swift; sourceTree = ""; }; - D8212CC020AA7C58008E8AE8 /* ReaderShowMenuAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderShowMenuAction.swift; sourceTree = ""; }; D8212CC220AA7F57008E8AE8 /* ReaderBlockSiteAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderBlockSiteAction.swift; sourceTree = ""; }; D8212CC420AA83F9008E8AE8 /* ReaderCommentAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderCommentAction.swift; sourceTree = ""; }; D8212CC620AA85C1008E8AE8 /* ReaderHeaderAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderHeaderAction.swift; sourceTree = ""; }; @@ -16992,7 +16989,6 @@ D8160441209C1B0F00ABAFFA /* ReaderSaveForLaterAction.swift */, 981D464725B0D4E7000AA65C /* ReaderSeenAction.swift */, D8212CB620AA7703008E8AE8 /* ReaderShareAction.swift */, - D8212CC020AA7C58008E8AE8 /* ReaderShowMenuAction.swift */, 0C878ACF2CBDACF7006CF997 /* ReaderPostMenu.swift */, E6D6A12F2683ABE6004C24A7 /* ReaderSubscribeCommentsAction.swift */, D8212CB420AA68D5008E8AE8 /* ReaderSubscribingNotificationAction.swift */, @@ -22543,7 +22539,6 @@ FA4ADAD81C50687400F858D7 /* SiteManagementService.swift in Sources */, 7E4A773820F80414001C706D /* ActivityPostRange.swift in Sources */, 32E1BFFD24AB9D28007A08F0 /* ReaderSelectInterestsViewController.swift in Sources */, - D8212CC120AA7C58008E8AE8 /* ReaderShowMenuAction.swift in Sources */, 0CBF66D82C949231005F1EDC /* ImageViewController.swift in Sources */, B5552D831CD1062400B26DF6 /* String+Extensions.swift in Sources */, 806E53E127E01C7F0064315E /* DashboardStatsViewModel.swift in Sources */, @@ -25473,7 +25468,6 @@ FABB246C2602FC2C00C8785C /* ActivityPostRange.swift in Sources */, 3FF717FF291F07AB00323614 /* MigrationCenterViewConfiguration.swift in Sources */, FABB246D2602FC2C00C8785C /* ReaderSelectInterestsViewController.swift in Sources */, - FABB246E2602FC2C00C8785C /* ReaderShowMenuAction.swift in Sources */, 3FFDEF882918596B00B625CE /* MigrationDoneViewModel.swift in Sources */, FADC40A92A8BC2A200C19997 /* UIImage+Gravatar.swift in Sources */, 01DBFD8829BDCBF200F3720F /* JetpackNativeConnectionService.swift in Sources */, From 4fbe121e3241d8e767f35a0c1d5212416162f070 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 15:29:20 -0400 Subject: [PATCH 34/55] Remove ReaderPostCardCell --- .../Reader/ReaderPostCardCell.swift | 645 ------------------ .../Reader/ReaderTableConfiguration.swift | 10 - WordPress/WordPress.xcodeproj/project.pbxproj | 6 - 3 files changed, 661 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderPostCardCell.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderPostCardCell.swift b/WordPress/Classes/ViewRelated/Reader/ReaderPostCardCell.swift deleted file mode 100644 index 8b51e05a3da0..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderPostCardCell.swift +++ /dev/null @@ -1,645 +0,0 @@ -import UIKit - -class ReaderPostCardCell: UITableViewCell { - - // MARK: - Properties - - private let contentStackView = UIStackView() - private let postStackView = UIStackView() - - private let siteStackView = UIStackView() - private let siteIconContainerView = UIView() - private let siteIconImageView = UIImageView() - private let siteIconBorderView = UIView() - private let avatarContainerView = UIView() - private let avatarImageView = UIImageView() - private let siteTitleLabel = UILabel() - private let postDateLabel = UILabel() - - private let postTitleLabel = UILabel() - private let postSummaryLabel = UILabel() - private let featuredImageView = CachedAnimatedImageView() - private var featuredImageWidthConstraint: NSLayoutConstraint? - private let postCountsLabel = UILabel() - - private let controlsStackView = UIStackView() - private let reblogButton = UIButton() - private let commentButton = UIButton() - private let likeButton = UIButton() - private let fillerView = UIView() - private let menuButton = UIButton() - - private let separatorView = UIView() - - private lazy var imageLoader = ImageLoader(imageView: featuredImageView) - private var viewModel: ReaderPostCardCellViewModel? { - didSet { - configureLabels() - configureImages() - configureButtons() - configureAccessibility() - } - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - commonInit() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - commonInit() - } - - override func prepareForReuse() { - super.prepareForReuse() - imageLoader.prepareForReuse() - resetElements() - addMissingViews() - } - - func prepareForDisplay() { - updateSeparatorState() - } - - func configure(with viewModel: ReaderPostCardCellViewModel) { - self.viewModel = viewModel - } - - func enableSidebarMode() { - guard let imageWidthConstraint = featuredImageWidthConstraint else { - return // Already configured - } - imageWidthConstraint.isActive = false - featuredImageWidthConstraint = nil - - postStackView.spacing = 20 - postStackView.axis = .horizontal - postStackView.alignment = .top - - // Make sure it extends to the whole width of the cell - postStackView.widthAnchor.constraint(equalTo: readableContentGuide.widthAnchor) - .withPriority(751).isActive = true - - featuredImageView.widthAnchor.constraint(equalToConstant: 250) - .withPriority(751).isActive = true - - postTitleLabel.font = WPStyleGuide.fontForTextStyle(.title3, fontWeight: .medium) - postSummaryLabel.font = .preferredFont(forTextStyle: .body) - } - - // MARK: - Constants - - struct Constants { - struct ContentStackView { - static let margins: CGFloat = 16.0 - static let spacing: CGFloat = 8.0 - static let bottomAnchor: CGFloat = 2.0 - } - - struct SiteStackView { - static let avatarSpacing: CGFloat = -4.0 - static let iconSpacing: CGFloat = 8.0 - static let siteTitleSpacing: CGFloat = 4.0 - } - - struct ControlsStackView { - static let reblogSpacing: CGFloat = 16.0 - static let commentSpacing: CGFloat = 16.0 - static let likeSpacing: CGFloat = 8.0 - static let trailingConstraint: CGFloat = 10.0 - static let bottomConstraint: CGFloat = -ContentStackView.margins + 10.0 - } - - struct FeaturedImage { - static let cornerRadius: CGFloat = 5.0 - static let heightAspectMultiplier: CGFloat = 239.0 / 358.0 - } - - struct Accessibility { - static let siteStackViewHint = NSLocalizedString("reader.post.header.accessibility.hint", - value: "Opens the site details for the post.", - comment: "Accessibility hint for the site header on the reader post card cell") - static let reblogButtonHint = NSLocalizedString("reader.post.button.reblog.accessibility.hint", - value: "Reblogs the post.", - comment: "Accessibility hint for the reblog button on the reader post card cell") - static let commentButtonHint = NSLocalizedString("reader.post.button.comment.accessibility.hint", - value: "Opens the comments for the post.", - comment: "Accessibility hint for the comment button on the reader post card cell") - static let likeButtonHint = NSLocalizedString("reader.post.button.like.accessibility.hint", - value: "Likes the post.", - comment: "Accessibility hint for the like button on the reader post card cell") - static let likedButtonHint = NSLocalizedString("reader.post.button.liked.accessibility.hint", - value: "Unlikes the post.", - comment: "Accessibility hint for the liked button on the reader post card cell") - static let menuButtonLabel = NSLocalizedString("reader.post.button.menu.accessibility.label", - value: "More", - comment: "Accessibility label for the more menu button on the reader post card cell") - static let menuButtonHint = NSLocalizedString("reader.post.button.menu.accessibility.hint", - value: "Opens a menu with more actions.", - comment: "Accessibility hint for the site header on the reader post card cell") - } - - static let iconImageSize: CGFloat = 20.0 - static let avatarPlaceholder = UIImage(named: "gravatar") - static let siteIconPlaceholder = UIImage(named: "post-blavatar-placeholder") - static let fillerViewHuggingPriority = UILayoutPriority(249.0) - static let reblogButtonImage = UIImage(named: "icon-reader-reblog")?.withRenderingMode(.alwaysTemplate) - static let commentButtonImage = UIImage(named: "icon-reader-post-comment")?.withRenderingMode(.alwaysTemplate) - static let likeButtonImage = UIImage(named: "icon-reader-star-outline")?.withRenderingMode(.alwaysTemplate) - static let likedButtonImage = UIImage(named: "icon-reader-star-fill")?.withRenderingMode(.alwaysTemplate) - static let menuButtonImage = UIImage(named: "more-horizontal-mobile")?.withRenderingMode(.alwaysTemplate) - static let buttonMinimumSize: CGFloat = 44.0 - static let reblogButtonText = NSLocalizedString("reader.post.button.reblog", - value: "Reblog", - comment: "Text for the 'Reblog' button on the reader post card cell.") - static let commentButtonText = NSLocalizedString("reader.post.button.comment", - value: "Comment", - comment: "Text for the 'Comment' button on the reader post card cell.") - static let likeButtonText = NSLocalizedString("reader.post.button.like", - value: "Like", - comment: "Text for the 'Like' button on the reader post card cell.") - static let likedButtonText = NSLocalizedString("reader.post.button.liked", - value: "Liked", - comment: "Text for the 'Liked' button on the reader post card cell.") - static let borderColor = UIColor(light: .systemBackground.darkVariant().withAlphaComponent(0.1), - dark: .systemBackground.lightVariant().withAlphaComponent(0.2)) - static let borderWidth: CGFloat = 0.5 - static let imageSeparatorBorderWidth: CGFloat = 1.0 - static let separatorHeight: CGFloat = 0.5 - static let likeButtonIdentifier = "reader-like-button" - } - -} - -// MARK: - Private methods - -private extension ReaderPostCardCell { - - var usesAccessibilitySize: Bool { - traitCollection.preferredContentSizeCategory.isAccessibilityCategory - } - - var showsSeparator: Bool { - viewModel?.showsSeparator ?? true - } - - func commonInit() { - setupViews() - addViewConstraints() - } - - // MARK: - View setup - - func setupViews() { - setupContentView() - setupContentStackView() - - setupAvatarImage() - setupSiteIconImage() - setupSiteTitle() - setupPostDate() - setupSiteStackView() - - setupPostTitle() - setupPostSummary() - setupFeaturedImage() - setupPostCounts() - - setupControlButtons() - setupControlsStackView() - - setupSeparatorView() - } - - func setupContentView() { - contentView.backgroundColor = .systemBackground - } - - func setupContentStackView() { - contentStackView.translatesAutoresizingMaskIntoConstraints = false - contentStackView.axis = .vertical - contentStackView.alignment = .leading - contentStackView.spacing = Constants.ContentStackView.spacing - contentView.addSubview(contentStackView) - - postStackView.axis = .vertical - postStackView.alignment = .leading - postStackView.spacing = 8 - - postStackView.addArrangedSubviews([ - UIStackView(axis: .vertical, alignment: .leading, spacing: 8, [ - postTitleLabel, postSummaryLabel - ]), - featuredImageView - ]) - - contentStackView.addArrangedSubview(siteStackView) - if usesAccessibilitySize { - contentStackView.addArrangedSubview(postDateLabel) - } - contentStackView.addArrangedSubview(postStackView) - contentStackView.addArrangedSubview(postCountsLabel) - } - - func setupAvatarImage() { - setupIconImage(avatarImageView, - containerView: avatarContainerView, - image: Constants.avatarPlaceholder) - avatarContainerView.addSubview(avatarImageView) - } - - func setupSiteIconImage() { - setupIconImage(siteIconImageView, - containerView: siteIconContainerView, - image: Constants.siteIconPlaceholder) - siteIconImageView.layer.masksToBounds = false - siteIconBorderView.translatesAutoresizingMaskIntoConstraints = false - siteIconBorderView.layer.frame = CGRect(x: 0, y: 0, width: Constants.iconImageSize, height: Constants.iconImageSize) - siteIconBorderView.layer.cornerRadius = Constants.iconImageSize / 2.0 - siteIconBorderView.layer.borderWidth = Constants.borderWidth + Constants.imageSeparatorBorderWidth - siteIconBorderView.layer.borderColor = UIColor.secondarySystemGroupedBackground.cgColor - siteIconBorderView.layer.masksToBounds = true - siteIconBorderView.addSubview(siteIconImageView) - siteIconContainerView.addSubview(siteIconBorderView) - } - - func setupIconImage(_ imageView: UIImageView, containerView: UIView, image: UIImage?) { - containerView.translatesAutoresizingMaskIntoConstraints = false - imageView.translatesAutoresizingMaskIntoConstraints = false - imageView.layer.cornerRadius = Constants.iconImageSize / 2.0 - imageView.layer.masksToBounds = true - imageView.image = image - imageView.contentMode = .scaleAspectFill - imageView.layer.borderWidth = Constants.borderWidth - imageView.layer.borderColor = Constants.borderColor.cgColor - imageView.backgroundColor = .secondarySystemGroupedBackground - } - - func setupSiteTitle() { - siteTitleLabel.translatesAutoresizingMaskIntoConstraints = false - siteTitleLabel.font = .preferredFont(forTextStyle: .subheadline).semibold() - siteTitleLabel.numberOfLines = 1 - siteTitleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - } - - func setupPostDate() { - postDateLabel.translatesAutoresizingMaskIntoConstraints = false - postDateLabel.font = .preferredFont(forTextStyle: .footnote) - postDateLabel.numberOfLines = 1 - postDateLabel.textColor = .secondaryLabel - } - - func setupSiteStackView() { - siteStackView.translatesAutoresizingMaskIntoConstraints = false - siteStackView.setCustomSpacing(Constants.SiteStackView.avatarSpacing, after: avatarContainerView) - siteStackView.setCustomSpacing(Constants.SiteStackView.iconSpacing, after: siteIconContainerView) - siteStackView.setCustomSpacing(Constants.SiteStackView.siteTitleSpacing, after: siteTitleLabel) - - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTapSiteHeader)) - siteStackView.addGestureRecognizer(tapGesture) - - siteStackView.addArrangedSubviews([ - avatarContainerView, - siteIconContainerView, - siteTitleLabel - ]) - // if accessibility size - if !usesAccessibilitySize { - siteStackView.addArrangedSubview(postDateLabel) - } - } - - func setupPostTitle() { - postTitleLabel.translatesAutoresizingMaskIntoConstraints = false - postTitleLabel.font = .preferredFont(forTextStyle: .title3).semibold() - postTitleLabel.numberOfLines = 2 - postTitleLabel.setContentCompressionResistancePriority(.defaultHigh + 2, for: .vertical) - } - - func setupPostSummary() { - postSummaryLabel.translatesAutoresizingMaskIntoConstraints = false - postSummaryLabel.font = .preferredFont(forTextStyle: .footnote) - postSummaryLabel.numberOfLines = 3 - postSummaryLabel.setContentCompressionResistancePriority(.defaultHigh + 1, for: .vertical) - } - - func setupFeaturedImage() { - featuredImageView.translatesAutoresizingMaskIntoConstraints = false - featuredImageView.layer.cornerRadius = Constants.FeaturedImage.cornerRadius - featuredImageView.layer.masksToBounds = true - featuredImageView.contentMode = .scaleAspectFill - featuredImageView.layer.borderWidth = Constants.borderWidth - featuredImageView.layer.borderColor = Constants.borderColor.cgColor - } - - func setupPostCounts() { - postCountsLabel.font = .preferredFont(forTextStyle: .footnote) - postCountsLabel.numberOfLines = 1 - postCountsLabel.textColor = .secondaryLabel - } - - func setupControlButton(_ button: UIButton, image: UIImage?, text: String? = nil, action: Selector) { - button.translatesAutoresizingMaskIntoConstraints = false - button.tintColor = .secondaryLabel - button.titleLabel?.font = .preferredFont(forTextStyle: .footnote) - button.titleLabel?.lineBreakMode = .byTruncatingTail - button.setImage(image, for: .normal) - button.setTitleColor(.secondaryLabel, for: .normal) - button.setTitle(text, for: .normal) - button.addTarget(self, action: action, for: .touchUpInside) - controlsStackView.addArrangedSubview(button) - } - - func setupControlButtons() { - if !usesAccessibilitySize { - setupControlButton(reblogButton, - image: Constants.reblogButtonImage, - text: Constants.reblogButtonText, - action: #selector(didTapReblog)) - } - setupControlButton(commentButton, - image: Constants.commentButtonImage, - text: Constants.commentButtonText, - action: #selector(didTapComment)) - setupControlButton(likeButton, - image: Constants.likeButtonImage, - text: Constants.likeButtonText, - action: #selector(didTapLike)) - setupFillerView() - controlsStackView.addArrangedSubview(fillerView) - setupControlButton(menuButton, - image: Constants.menuButtonImage, - action: #selector(didTapMore)) - } - - func setupFillerView() { - fillerView.translatesAutoresizingMaskIntoConstraints = false - fillerView.setContentHuggingPriority(Constants.fillerViewHuggingPriority, for: .horizontal) - fillerView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - } - - func setupControlsStackView() { - controlsStackView.translatesAutoresizingMaskIntoConstraints = false - controlsStackView.setCustomSpacing(Constants.ControlsStackView.reblogSpacing, after: reblogButton) - controlsStackView.setCustomSpacing(Constants.ControlsStackView.commentSpacing, after: commentButton) - controlsStackView.setCustomSpacing(Constants.ControlsStackView.likeSpacing, after: likeButton) - contentView.addSubview(controlsStackView) - } - - func setupSeparatorView() { - separatorView.translatesAutoresizingMaskIntoConstraints = false - updateSeparatorState() - contentView.addSubview(separatorView) - } - - func updateSeparatorState() { - separatorView.backgroundColor = showsSeparator ? .separator : .clear - } - - // MARK: - View constraints - - func addViewConstraints() { - NSLayoutConstraint.activate( - contentViewConstraints() - + iconImageConstraints(avatarImageView, containerView: avatarContainerView) - + siteIconImageConstraints() - + featuredImageContraints() - + buttonStackViewConstraints() - + buttonConstraints() - + separatorViewConstraints() - ) - } - - func contentViewConstraints() -> [NSLayoutConstraint] { - let margins = Constants.ContentStackView.margins - return [ - contentStackView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), - contentStackView.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor), - contentStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: margins), - contentStackView.bottomAnchor.constraint(equalTo: controlsStackView.topAnchor, constant: Constants.ContentStackView.bottomAnchor) - ] - } - - func iconImageConstraints(_ imageView: UIImageView, containerView: UIView) -> [NSLayoutConstraint] { - return [ - containerView.heightAnchor.constraint(greaterThanOrEqualTo: imageView.heightAnchor), - containerView.widthAnchor.constraint(greaterThanOrEqualTo: imageView.widthAnchor), - imageView.heightAnchor.constraint(equalToConstant: Constants.iconImageSize), - imageView.widthAnchor.constraint(equalToConstant: Constants.iconImageSize), - imageView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor), - imageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor) - ] - } - - func siteIconImageConstraints() -> [NSLayoutConstraint] { - return [ - siteIconContainerView.heightAnchor.constraint(greaterThanOrEqualTo: siteIconBorderView.heightAnchor), - siteIconContainerView.widthAnchor.constraint(greaterThanOrEqualTo: siteIconBorderView.widthAnchor), - siteIconBorderView.heightAnchor.constraint(equalToConstant: Constants.iconImageSize + Constants.borderWidth + Constants.imageSeparatorBorderWidth), - siteIconBorderView.widthAnchor.constraint(equalToConstant: Constants.iconImageSize + Constants.borderWidth + Constants.imageSeparatorBorderWidth), - siteIconBorderView.centerXAnchor.constraint(equalTo: siteIconContainerView.centerXAnchor), - siteIconBorderView.centerYAnchor.constraint(equalTo: siteIconContainerView.centerYAnchor), - siteIconImageView.heightAnchor.constraint(equalToConstant: Constants.iconImageSize), - siteIconImageView.widthAnchor.constraint(equalToConstant: Constants.iconImageSize), - siteIconImageView.centerXAnchor.constraint(equalTo: siteIconBorderView.centerXAnchor), - siteIconImageView.centerYAnchor.constraint(equalTo: siteIconBorderView.centerYAnchor), - ] - } - - func featuredImageContraints() -> [NSLayoutConstraint] { - let heightAspectRatio = featuredImageView.heightAnchor.constraint(equalTo: featuredImageView.widthAnchor, multiplier: Constants.FeaturedImage.heightAspectMultiplier) - heightAspectRatio.priority = .defaultHigh - - let widthConstraint = featuredImageView.widthAnchor.constraint(equalTo: contentStackView.widthAnchor).withPriority(749) - featuredImageWidthConstraint = widthConstraint - return [widthConstraint, heightAspectRatio] - } - - func buttonStackViewConstraints() -> [NSLayoutConstraint] { - return [ - controlsStackView.leadingAnchor.constraint(equalTo: contentStackView.leadingAnchor), - controlsStackView.trailingAnchor.constraint(equalTo: contentStackView.trailingAnchor, - constant: Constants.ControlsStackView.trailingConstraint), - controlsStackView.bottomAnchor.constraint(equalTo: separatorView.topAnchor, - constant: Constants.ControlsStackView.bottomConstraint), - controlsStackView.heightAnchor.constraint(equalToConstant: Constants.buttonMinimumSize) - ] - } - - func buttonConstraints() -> [NSLayoutConstraint] { - let minimumSize = Constants.buttonMinimumSize - return [ - reblogButton.widthAnchor.constraint(greaterThanOrEqualToConstant: minimumSize), - commentButton.widthAnchor.constraint(greaterThanOrEqualToConstant: minimumSize), - likeButton.widthAnchor.constraint(greaterThanOrEqualToConstant: minimumSize), - menuButton.widthAnchor.constraint(greaterThanOrEqualToConstant: minimumSize), - ] - } - - func separatorViewConstraints() -> [NSLayoutConstraint] { - return [ - separatorView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), - separatorView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), - separatorView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), - separatorView.heightAnchor.constraint(equalToConstant: Constants.separatorHeight) - ] - } - - // MARK: - View configuration - - func configureLabels() { - configureLabel(siteTitleLabel, text: viewModel?.siteTitle) - configureLabel(postDateLabel, text: usesAccessibilitySize ? viewModel?.shortPostDate : viewModel?.postDate) - configureLabel(postTitleLabel, text: viewModel?.postTitle) - configureLabel(postSummaryLabel, text: viewModel?.postSummary) - configureLabel(postCountsLabel, text: viewModel?.postCounts) - } - - func configureLabel(_ label: UILabel, text: String?) { - guard let text else { - return - } - label.setText(text) - } - - func configureImages() { - configureAvatar() - configureSiteIcon() - configureFeaturedImage() - } - - func configureAvatar() { - guard let viewModel, viewModel.isAvatarEnabled else { - avatarContainerView.isHidden = true - return - } - viewModel.downloadAvatarIcon(for: avatarImageView) - } - - func configureSiteIcon() { - guard let viewModel, viewModel.isSiteIconEnabled else { - siteStackView.setCustomSpacing(Constants.SiteStackView.iconSpacing, after: avatarContainerView) - siteIconContainerView.isHidden = true - return - } - viewModel.downloadSiteIcon(for: siteIconImageView) - } - - func configureFeaturedImage() { - guard let viewModel, viewModel.isFeaturedImageEnabled else { - featuredImageView.isHidden = true - return - } - let imageViewSize = CGSize(width: featuredImageView.frame.width, - height: featuredImageView.frame.height) - viewModel.downloadFeaturedImage(with: imageLoader, size: imageViewSize) - } - - func configureButtons() { - guard let viewModel else { - return - } - reblogButton.isHidden = !viewModel.isReblogEnabled - commentButton.isHidden = !viewModel.isCommentsEnabled - if viewModel.isLikesEnabled { - configureLikeButton() - } else { - likeButton.isHidden = true - } - } - - func configureLikeButton() { - guard let isLiked = viewModel?.isPostLiked else { - return - } - likeButton.setTitle(isLiked ? Constants.likedButtonText : Constants.likeButtonText, for: .normal) - likeButton.setImage(isLiked ? Constants.likedButtonImage : Constants.likeButtonImage, for: .normal) - likeButton.tintColor = isLiked ? UIAppColor.jetpackGreen : .secondaryLabel - likeButton.setTitleColor(likeButton.tintColor, for: .normal) - } - - // MARK: - Accessibility - - func configureAccessibility() { - siteStackView.isAccessibilityElement = true - siteStackView.accessibilityLabel = [viewModel?.siteTitle, viewModel?.shortPostDate].compactMap { $0 }.joined(separator: ", ") - siteStackView.accessibilityHint = Constants.Accessibility.siteStackViewHint - siteStackView.accessibilityTraits = .button - - postCountsLabel.accessibilityLabel = [viewModel?.likeCount, viewModel?.commentCount].compactMap { $0 }.joined(separator: ", ") - - reblogButton.accessibilityHint = Constants.Accessibility.reblogButtonHint - commentButton.accessibilityHint = Constants.Accessibility.commentButtonHint - likeButton.accessibilityHint = viewModel?.isPostLiked == true ? Constants.Accessibility.likedButtonHint : Constants.Accessibility.likeButtonHint - likeButton.accessibilityIdentifier = Constants.likeButtonIdentifier - menuButton.accessibilityLabel = Constants.Accessibility.menuButtonLabel - menuButton.accessibilityHint = Constants.Accessibility.menuButtonHint - accessibilityElements = [ - siteStackView, postTitleLabel, postSummaryLabel, postCountsLabel, - reblogButton, commentButton, likeButton, menuButton - ].filter { $0 != reblogButton || !self.usesAccessibilitySize } // skip reblog button if a11y size is active. - } - - // MARK: - Cell reuse - - func addMissingViews() { - let siteHeaderViews = [avatarContainerView, siteIconContainerView, siteTitleLabel, postDateLabel] - let contentViews = [siteStackView, postTitleLabel, postSummaryLabel, featuredImageView, postCountsLabel] - let controlViews = [reblogButton, commentButton, likeButton].filter { - // skip reblog button if a11y size is active. - $0 != reblogButton || !self.usesAccessibilitySize - } - - for view in siteHeaderViews { - view.isHidden = false - } - for view in contentViews { - view.isHidden = false - } - for view in controlViews { - view.isHidden = false - } - - siteStackView.setCustomSpacing(Constants.SiteStackView.avatarSpacing, after: avatarContainerView) - siteStackView.setCustomSpacing(Constants.SiteStackView.iconSpacing, after: siteIconContainerView) - siteStackView.setCustomSpacing(Constants.SiteStackView.siteTitleSpacing, after: siteTitleLabel) - controlsStackView.setCustomSpacing(Constants.ControlsStackView.reblogSpacing, after: reblogButton) - controlsStackView.setCustomSpacing(Constants.ControlsStackView.commentSpacing, after: commentButton) - controlsStackView.setCustomSpacing(Constants.ControlsStackView.likeSpacing, after: likeButton) - } - - func resetElements() { - avatarImageView.image = Constants.avatarPlaceholder - siteIconImageView.image = Constants.siteIconPlaceholder - siteTitleLabel.text = nil - postDateLabel.text = nil - postTitleLabel.text = nil - postSummaryLabel.text = nil - featuredImageView.image = nil - postCountsLabel.text = nil - } - - // MARK: - Button actions - - @objc func didTapSiteHeader() { - viewModel?.showSiteDetails() - } - - @objc func didTapReblog() { - viewModel?.reblog() - } - - @objc func didTapComment() { - viewModel?.comment(with: self) - } - - @objc func didTapLike() { - viewModel?.toggleLike(with: self) - } - - @objc func didTapMore() { - viewModel?.showMore(with: menuButton) - } - -} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift index c0a2cf0aae19..547ed4ed31c3 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift @@ -2,7 +2,6 @@ final class ReaderTableConfiguration { private let footerViewNibName = "PostListFooterView" private let readerPostCellReuseIdentifier = "ReaderPostCellReuseIdentifier" - private let readerCardCellReuseIdentifier = "ReaderCardCellReuseIdentifier" private let readerBlockedCellNibName = "ReaderBlockedSiteCell" private let readerBlockedCellReuseIdentifier = "ReaderBlockedCellReuseIdentifier" private let readerGapMarkerCellNibName = "ReaderGapMarkerCell" @@ -15,7 +14,6 @@ final class ReaderTableConfiguration { func setup(_ tableView: UITableView) { setupAccessibility(tableView) setUpSeparator(tableView) - setUpCardCell(tableView) setUpBlockerCell(tableView) setUpGapMarkerCell(tableView) setUpCrossPostCell(tableView) @@ -33,10 +31,6 @@ final class ReaderTableConfiguration { } } - private func setUpCardCell(_ tableView: UITableView) { - tableView.register(ReaderPostCardCell.self, forCellReuseIdentifier: readerCardCellReuseIdentifier) - } - private func setUpBlockerCell(_ tableView: UITableView) { let nib = UINib(nibName: readerBlockedCellNibName, bundle: nil) tableView.register(nib, forCellReuseIdentifier: readerBlockedCellReuseIdentifier) @@ -68,10 +62,6 @@ final class ReaderTableConfiguration { return tableView.dequeueReusableCell(withIdentifier: readerCrossPostCellReuseIdentifier) as! ReaderCrossPostCell } - func postCardCell(_ tableView: UITableView) -> ReaderPostCardCell { - return tableView.dequeueReusableCell(withIdentifier: readerCardCellReuseIdentifier) as! ReaderPostCardCell - } - func postCell(in tableView: UITableView, for indexPath: IndexPath) -> ReaderPostCell { tableView.dequeueReusableCell(withIdentifier: readerPostCellReuseIdentifier, for: indexPath) as! ReaderPostCell } diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index fa9b216e435f..d45ee1ef89c5 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2442,8 +2442,6 @@ 8384C64128AAC82600EABE26 /* KeychainUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8384C64028AAC82600EABE26 /* KeychainUtils.swift */; }; 8384C64228AAC82600EABE26 /* KeychainUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8384C64028AAC82600EABE26 /* KeychainUtils.swift */; }; 8384C64428AAC85F00EABE26 /* KeychainUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8384C64328AAC85F00EABE26 /* KeychainUtilsTests.swift */; }; - 8386C6A32AC4E3C700568183 /* ReaderPostCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8386C6A22AC4E3C700568183 /* ReaderPostCardCell.swift */; }; - 8386C6A42AC4E3C700568183 /* ReaderPostCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8386C6A22AC4E3C700568183 /* ReaderPostCardCell.swift */; }; 83914BD12A2E89F30017A588 /* JetpackSocialNoConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83914BD02A2E89F30017A588 /* JetpackSocialNoConnectionView.swift */; }; 83914BD22A2E89F30017A588 /* JetpackSocialNoConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83914BD02A2E89F30017A588 /* JetpackSocialNoConnectionView.swift */; }; 83914BD42A2EA03A0017A588 /* PostSettingsViewController+JetpackSocial.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83914BD32A2EA03A0017A588 /* PostSettingsViewController+JetpackSocial.swift */; }; @@ -7953,7 +7951,6 @@ 837B49D6283C2AE80061A657 /* BloggingPromptSettingsReminderDays+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BloggingPromptSettingsReminderDays+CoreDataProperties.swift"; sourceTree = ""; }; 8384C64028AAC82600EABE26 /* KeychainUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainUtils.swift; sourceTree = ""; }; 8384C64328AAC85F00EABE26 /* KeychainUtilsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainUtilsTests.swift; sourceTree = ""; }; - 8386C6A22AC4E3C700568183 /* ReaderPostCardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderPostCardCell.swift; sourceTree = ""; }; 83914BD02A2E89F30017A588 /* JetpackSocialNoConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackSocialNoConnectionView.swift; sourceTree = ""; }; 83914BD32A2EA03A0017A588 /* PostSettingsViewController+JetpackSocial.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PostSettingsViewController+JetpackSocial.swift"; sourceTree = ""; }; 839435922847F2200019A94F /* WordPress 143.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 143.xcdatamodel"; sourceTree = ""; }; @@ -13274,7 +13271,6 @@ E6D3E84A1BEBD888002692E8 /* ReaderCrossPostCell.xib */, E6A3384F1BB0A70F00371587 /* ReaderGapMarkerCell.swift */, E6A3384D1BB0A50900371587 /* ReaderGapMarkerCell.xib */, - 8386C6A22AC4E3C700568183 /* ReaderPostCardCell.swift */, 0C9A78FE2CB971E30092D80E /* ReaderPostCell.swift */, 0C9A79012CB9724A0092D80E /* ReaderPostCellViewModel.swift */, 83204EDB2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift */, @@ -22802,7 +22798,6 @@ 837B49D7283C2AE80061A657 /* BloggingPromptSettings+CoreDataClass.swift in Sources */, 98BC522A27F6259700D6E8C2 /* BloggingPromptsFeatureDescriptionView.swift in Sources */, FAD9458E25B5678700F011B5 /* JetpackRestoreWarningCoordinator.swift in Sources */, - 8386C6A32AC4E3C700568183 /* ReaderPostCardCell.swift in Sources */, 4ADE3F912C6365E00046EC8A /* ApplicationTokenItemView.swift in Sources */, 805CC0C1296CF3B3002941DC /* JetpackNewUsersOverlaySecondaryView.swift in Sources */, B5E94D151FE04815000E7C20 /* UIImageView+SiteIcon.swift in Sources */, @@ -25850,7 +25845,6 @@ FABB25822602FC2C00C8785C /* MediaExporter.swift in Sources */, 1756DBE028328B76006E6DB9 /* DonutChartView.swift in Sources */, 8B15CDAC27EB89AD00A75749 /* BlogDashboardPostsParser.swift in Sources */, - 8386C6A42AC4E3C700568183 /* ReaderPostCardCell.swift in Sources */, 8BF9E03427B1A8A800915B27 /* DashboardCard.swift in Sources */, FABB25832602FC2C00C8785C /* ReaderRelatedPostsCell.swift in Sources */, FABB25842602FC2C00C8785C /* NoResultsViewController+FollowedSites.swift in Sources */, From 8e5733cdc84f1b73596d8d760ea77be8a43350ae Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 15:30:24 -0400 Subject: [PATCH 35/55] Remove ReaderPostCardCellViewModel --- .../Reader/ReaderPostCardCellViewModel.swift | 237 ------------------ .../Reader/ReaderStreamViewController.swift | 14 -- WordPress/WordPress.xcodeproj/project.pbxproj | 6 - 3 files changed, 257 deletions(-) delete mode 100644 WordPress/Classes/ViewRelated/Reader/ReaderPostCardCellViewModel.swift diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderPostCardCellViewModel.swift b/WordPress/Classes/ViewRelated/Reader/ReaderPostCardCellViewModel.swift deleted file mode 100644 index 75914f265c48..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderPostCardCellViewModel.swift +++ /dev/null @@ -1,237 +0,0 @@ - -struct ReaderPostCardCellViewModel { - - // MARK: - Properties - - var siteIconURL: URL? { - let scale = WordPressAppDelegate.shared?.window?.screen.scale ?? 1.0 - let size = ReaderPostCardCell.Constants.iconImageSize * scale - return contentProvider.siteIconForDisplay(ofSize: Int(size)) - } - - private var isRTL: Bool { - UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft - } - - var siteTitle: String? { - if let post = contentProvider as? ReaderPost, post.isP2Type(), let author = contentProvider.authorForDisplay() { - let strings = [author, contentProvider.blogNameForDisplay?()].compactMap { $0 } - return isRTL ? strings.reversed().joined(separator: " ◂ ") : strings.joined(separator: " ▸ ") - } - - return contentProvider.blogNameForDisplay?() - } - - var shortPostDate: String? { - contentProvider.dateForDisplay()?.toShortString() - } - - var postDate: String? { - guard let shortPostDate else { - return nil - } - let postDateFormat = isRTL ? "%@ •" : "• %@" - return siteTitle != nil ? String(format: postDateFormat, shortPostDate) : shortPostDate - } - - var postTitle: String? { - contentProvider.titleForDisplay() - } - - private var featuredImageIdealSize: CGSize? { - guard let window = WordPressAppDelegate.shared?.window else { - return nil - } - - let windowWidth = window.screen.bounds.width - let safeAreaOffset = window.safeAreaInsets.left + window.safeAreaInsets.right - let width = windowWidth - safeAreaOffset - ReaderPostCardCell.Constants.ContentStackView.margins * 2 - let height = width * ReaderPostCardCell.Constants.FeaturedImage.heightAspectMultiplier - return CGSize(width: width, height: height) - } - - var postSummary: String? { - contentProvider.contentPreviewForDisplay() - } - - var commentCount: String? { - guard isCommentsEnabled, - let count = contentProvider.commentCount()?.intValue, - count > 0 else { - return nil - } - return WPStyleGuide.commentCountForDisplay(count) - } - - var likeCount: String? { - guard isLikesEnabled, - let count = contentProvider.likeCount()?.intValue, - count > 0 else { - return nil - } - return WPStyleGuide.likeCountForDisplay(count) - } - - var postCounts: String? { - let countStrings = [likeCount, commentCount].compactMap { $0 } - return countStrings.count > 0 ? countStrings.joined(separator: " • ") : nil - } - - private var readerPost: ReaderPost? { - contentProvider as? ReaderPost - } - - var isPostLiked: Bool { - contentProvider.isLiked() - } - - var isAvatarEnabled: Bool { - guard let post = contentProvider as? ReaderPost else { - return false - } - return post.isP2Type() && contentProvider.avatarURLForDisplay() != nil - } - - var isSiteIconEnabled: Bool { - siteIconURL != nil - } - - var isReblogEnabled: Bool { - !contentProvider.isPrivate() && actionVisibility.isEnabled - } - - var isFeaturedImageEnabled: Bool { - contentProvider.featuredImageURLForDisplay?() != nil - } - - var isCommentsEnabled: Bool { - let usesWPComAPI = contentProvider.isWPCom() || contentProvider.isJetpack() - let commentCount = contentProvider.commentCount()?.intValue ?? 0 - let hasComments = commentCount > 0 - - return usesWPComAPI && (contentProvider.commentsOpen() || hasComments) - } - - var isLikesEnabled: Bool { - let likeCount = contentProvider.likeCount()?.intValue ?? 0 - return !contentProvider.isExternal() && (likeCount > 0 || actionVisibility.isEnabled) - } - - private let contentProvider: ReaderPostContentProvider - private let actionVisibility: ReaderActionsVisibility - private weak var parentViewController: ReaderStreamViewController? - - private var followCommentsService: FollowCommentsService? - - private(set) var showsSeparator: Bool - - init(contentProvider: ReaderPostContentProvider, - isLoggedIn: Bool, - showsSeparator: Bool = true, - parentViewController: ReaderStreamViewController) { - self.contentProvider = contentProvider - self.actionVisibility = .visible(enabled: isLoggedIn) - self.showsSeparator = showsSeparator - self.parentViewController = parentViewController - } - - // MARK: - Functions - - func downloadAvatarIcon(for imageView: UIImageView) { - guard let url = contentProvider.avatarURLForDisplay() else { - return - } - downloadImage(for: url, imageView: imageView) - } - - func downloadSiteIcon(for imageView: UIImageView) { - guard let url = siteIconURL else { - return - } - downloadImage(for: url, imageView: imageView) - } - - private func downloadImage(for url: URL, imageView: UIImageView) { - let mediaRequestAuthenticator = MediaRequestAuthenticator() - let host = MediaHost(with: contentProvider, failure: { error in - DDLogError("ReaderPostCardCellViewModel MediaHost error: \(error.localizedDescription)") - }) - Task { - do { - let request = try await mediaRequestAuthenticator.authenticatedRequest(for: url, host: host) - await imageView.downloadImage(usingRequest: request) - } catch { - DDLogError("\(error)") - } - } - } - - func downloadFeaturedImage(with imageLoader: ImageLoader, size: CGSize) { - guard let url = contentProvider.featuredImageURLForDisplay?() else { - return - } - let imageSize = featuredImageIdealSize ?? size - let host = MediaHost(with: contentProvider, failure: { error in - DDLogError("\(error)") - }) - imageLoader.loadImage(with: url, from: host, preferredSize: imageSize) - } - - func showSiteDetails() { - guard let readerPost, let parentViewController else { - return - } - ReaderHeaderAction().execute(post: readerPost, origin: parentViewController) - } - - func reblog() { - guard let readerPost, let parentViewController else { - return - } - ReaderReblogAction().execute(readerPost: readerPost, origin: parentViewController, reblogSource: .list) - } - - func comment(with cell: UITableViewCell) { - guard let readerPost, let parentViewController else { - return - } - ReaderCommentAction().execute(post: readerPost, origin: parentViewController, source: .postCard) - } - - func toggleLike(with cell: ReaderPostCardCell) { - guard let readerPost else { - return - } - - ReaderLikeAction().execute(with: readerPost) - } - - mutating func showMore(with anchor: UIView) { - // Do nothing - } -} - -enum ReaderActionsVisibility: Equatable { - case hidden - case visible(enabled: Bool) - - static func == (lhs: ReaderActionsVisibility, rhs: ReaderActionsVisibility) -> Bool { - switch (lhs, rhs) { - case (.hidden, .hidden): - return true - case (.visible(let lenabled), .visible(let renabled)): - return lenabled == renabled - default: - return false - } - } - - var isEnabled: Bool { - switch self { - case .hidden: - return false - case .visible(let enabled): - return enabled - } - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index bdb9db628ad5..744de12c1fd0 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -1486,20 +1486,6 @@ extension ReaderStreamViewController: WPTableViewHandlerDelegate { return cell } - guard FeatureFlag.readerReset.enabled else { - let cell = tableConfiguration.postCardCell(tableView) - if isSidebarModeEnabled { - cell.enableSidebarMode() - } - - let viewModel = ReaderPostCardCellViewModel(contentProvider: post, - isLoggedIn: isLoggedIn, - showsSeparator: showsSeparator, - parentViewController: self) - cell.configure(with: viewModel) - return cell - } - let cell = tableConfiguration.postCell(in: tableView, for: indexPath) let viewModel = ReaderPostCellViewModel(post: post, topic: readerTopic) viewModel.viewController = self diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index d45ee1ef89c5..cf7927bc4612 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -2396,8 +2396,6 @@ 8313B9EF298B1ACD000AF26E /* SiteSettingsViewController+Blogging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8313B9ED298B1ACD000AF26E /* SiteSettingsViewController+Blogging.swift */; }; 8313B9FA2995A03C000AF26E /* JetpackRemoteInstallCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8313B9F92995A03C000AF26E /* JetpackRemoteInstallCardView.swift */; }; 8313B9FB2995A03C000AF26E /* JetpackRemoteInstallCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8313B9F92995A03C000AF26E /* JetpackRemoteInstallCardView.swift */; }; - 83204EDC2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83204EDB2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift */; }; - 83204EDD2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83204EDB2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift */; }; 8320BDE5283D9359009DF2DE /* BlogService+BloggingPrompts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8320BDE4283D9359009DF2DE /* BlogService+BloggingPrompts.swift */; }; 8320BDE6283D9359009DF2DE /* BlogService+BloggingPrompts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8320BDE4283D9359009DF2DE /* BlogService+BloggingPrompts.swift */; }; 8323789928526E6E003F4443 /* AppConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA25F9FD2609AA830005E08F /* AppConfiguration.swift */; }; @@ -7917,7 +7915,6 @@ 83043E54126FA31400EC9953 /* MessageUI.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; 8313B9ED298B1ACD000AF26E /* SiteSettingsViewController+Blogging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SiteSettingsViewController+Blogging.swift"; sourceTree = ""; }; 8313B9F92995A03C000AF26E /* JetpackRemoteInstallCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackRemoteInstallCardView.swift; sourceTree = ""; }; - 83204EDB2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderPostCardCellViewModel.swift; sourceTree = ""; }; 8320BDE4283D9359009DF2DE /* BlogService+BloggingPrompts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BlogService+BloggingPrompts.swift"; sourceTree = ""; }; 8332D7442ADF263400EB97EF /* UIConfigurationTextAttributesTransformer+Font.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIConfigurationTextAttributesTransformer+Font.swift"; sourceTree = ""; }; 8332DD2329259AE300802F7D /* DataMigrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataMigrator.swift; sourceTree = ""; }; @@ -13273,7 +13270,6 @@ E6A3384D1BB0A50900371587 /* ReaderGapMarkerCell.xib */, 0C9A78FE2CB971E30092D80E /* ReaderPostCell.swift */, 0C9A79012CB9724A0092D80E /* ReaderPostCellViewModel.swift */, - 83204EDB2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift */, 3234BB322530EA980068DA40 /* ReaderRecommendedSiteCardCell.swift */, 3234BB332530EA980068DA40 /* ReaderRecommendedSiteCardCell.xib */, ); @@ -21395,7 +21391,6 @@ 5D51ADAF19A832AF00539C0B /* WordPress-20-21.xcmappingmodel in Sources */, C81CCD63243AECA100A83E27 /* TenorClient.swift in Sources */, F4D9188629D78C9100974A71 /* BlogDetailsViewController+Strings.swift in Sources */, - 83204EDC2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift in Sources */, 9A8ECE112254A3260043C8DA /* JetpackRemoteInstallViewModel.swift in Sources */, 5727EAF82284F5AC00822104 /* InteractivePostViewDelegate.swift in Sources */, 93C486511810445D00A24725 /* ActivityLogViewController.m in Sources */, @@ -25017,7 +25012,6 @@ 4A2C73E22A943D9000ACE79E /* TaggedManagedObjectID.swift in Sources */, FABB232C2602FC2C00C8785C /* PublicizeConnection.swift in Sources */, FABB232D2602FC2C00C8785C /* TenorPageable.swift in Sources */, - 83204EDD2ACE098B000C3229 /* ReaderPostCardCellViewModel.swift in Sources */, 83F76F322BC9DEC400C4F2A1 /* ReaderPost+Display.swift in Sources */, FABB232E2602FC2C00C8785C /* AccountService+MergeDuplicates.swift in Sources */, FABB232F2602FC2C00C8785C /* URL+Helpers.swift in Sources */, From b72b791654f661f2682a5399cc787241453770b2 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 15:31:09 -0400 Subject: [PATCH 36/55] Remove .serif FF --- WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift b/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift index 33c3238b877d..14fd9cf786eb 100644 --- a/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift +++ b/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift @@ -16,7 +16,6 @@ enum FeatureFlag: Int, CaseIterable { case newGutenberg case newGutenbergThemeStyles case newGutenbergPlugins - case serif case readerReset /// Returns a boolean indicating if the feature is enabled @@ -54,8 +53,6 @@ enum FeatureFlag: Int, CaseIterable { return false case .newGutenbergPlugins: return false - case .serif: - return false case .readerReset: return BuildConfiguration.current != .appStore } @@ -94,7 +91,6 @@ extension FeatureFlag { case .newGutenberg: "Experimental Block Editor" case .newGutenbergThemeStyles: "Experimental Block Editor Styles" case .newGutenbergPlugins: "Experimental Block Editor Plugins" - case .serif: "Serif" case .readerReset: "Reader Reset" } } From 699555fd99c7eef92265b1c815bcc802c0b1229b Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 15:33:44 -0400 Subject: [PATCH 37/55] Remove .readerReset FF --- .../BuildInformation/FeatureFlag.swift | 4 ---- .../Reader/ReaderDiscoverViewController.swift | 8 +++----- .../ReaderStreamViewController+Helper.swift | 6 ++---- .../Reader/ReaderStreamViewController.swift | 14 ------------- .../Reader/ReaderTableConfiguration.swift | 7 ------- .../Reader/WPStyleGuide+Reader.swift | 20 ------------------- .../UITests/Utils/XCTest+Extensions.swift | 2 -- 7 files changed, 5 insertions(+), 56 deletions(-) diff --git a/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift b/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift index 14fd9cf786eb..4227d3c174c9 100644 --- a/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift +++ b/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift @@ -16,7 +16,6 @@ enum FeatureFlag: Int, CaseIterable { case newGutenberg case newGutenbergThemeStyles case newGutenbergPlugins - case readerReset /// Returns a boolean indicating if the feature is enabled var enabled: Bool { @@ -53,8 +52,6 @@ enum FeatureFlag: Int, CaseIterable { return false case .newGutenbergPlugins: return false - case .readerReset: - return BuildConfiguration.current != .appStore } } @@ -91,7 +88,6 @@ extension FeatureFlag { case .newGutenberg: "Experimental Block Editor" case .newGutenbergThemeStyles: "Experimental Block Editor Styles" case .newGutenbergPlugins: "Experimental Block Editor Plugins" - case .readerReset: "Reader Reset" } } } diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift index f1e6a72d16e1..35bfd4e57522 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift @@ -91,11 +91,9 @@ class ReaderDiscoverViewController: UIViewController, ReaderDiscoverHeaderViewDe self.streamVC = streamVC - if FeatureFlag.readerReset.enabled { - // Important to set before `viewDidLoad` - streamVC.isEmbeddedInDiscover = true - streamVC.setHeaderView(headerView) - } + // Important to set before `viewDidLoad` + streamVC.isEmbeddedInDiscover = true + streamVC.setHeaderView(headerView) addChild(streamVC) view.addSubview(streamVC.view) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift index 41fb8c1c25bd..f0373482404c 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift @@ -11,10 +11,8 @@ extension ReaderStreamViewController { } func headerForStream(_ topic: ReaderAbstractTopic?, isLoggedIn: Bool, container: UITableViewController) -> UIView? { - if FeatureFlag.readerReset.enabled, let topic { - if ReaderHelpers.topicIsFollowing(topic) { - return ReaderStreamTitleView.makeForFollowing() - } + if let topic, ReaderHelpers.topicIsFollowing(topic) { + return ReaderStreamTitleView.makeForFollowing() } if let topic, let header = headerForStream(topic) { diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 744de12c1fd0..f77f1086ee98 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -608,19 +608,6 @@ import AutomatticTracks } return } - - if ReaderHelpers.isTopicTag(topic) || ReaderHelpers.isTopicSite(topic) { - title = "" - } else { - title = topic.title - } - - if FeatureFlag.readerReset.enabled { - configureNavigationTitle(for: topic) - } - } - - private func configureNavigationTitle(for topic: ReaderAbstractTopic) { func setCustomTitleView(_ title: String) { self.title = title titleView.textLabel.text = title @@ -1494,7 +1481,6 @@ extension ReaderStreamViewController: WPTableViewHandlerDelegate { } func hideSeparator(for cell: UITableViewCell) { - guard FeatureFlag.readerReset.enabled else { return } cell.separatorInset = UIEdgeInsets(.leading, 9999) } diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift b/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift index 547ed4ed31c3..65f516f3a0a9 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderTableConfiguration.swift @@ -13,7 +13,6 @@ final class ReaderTableConfiguration { func setup(_ tableView: UITableView) { setupAccessibility(tableView) - setUpSeparator(tableView) setUpBlockerCell(tableView) setUpGapMarkerCell(tableView) setUpCrossPostCell(tableView) @@ -25,12 +24,6 @@ final class ReaderTableConfiguration { tableView.accessibilityIdentifier = "reader_table_view" } - private func setUpSeparator(_ tableView: UITableView) { - if !FeatureFlag.readerReset.enabled { - tableView.separatorStyle = .none - } - } - private func setUpBlockerCell(_ tableView: UITableView) { let nib = UINib(nibName: readerBlockedCellNibName, bundle: nil) tableView.register(nib, forCellReuseIdentifier: readerBlockedCellReuseIdentifier) diff --git a/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift b/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift index dc1bc377354e..96fcb5e2a93a 100644 --- a/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift +++ b/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift @@ -261,26 +261,6 @@ extension WPStyleGuide { } } - /// Applies the filter button style to the button passed as an argument - class func applyReaderFilterButtonStyle(_ button: UIButton) { - let icon = UIImage.gridicon(.filter) - - button.setImage(icon, for: .normal) - applyReaderActionButtonStyle(button, titleColor: UIColor(light: .black, dark: .white)) - } - /// Applies the filter button title to the button passed as an argument - class func applyReaderFilterButtonTitle(_ button: UIButton, title: String) { - button.setTitle(title, for: .normal) - button.setTitle(title, for: .highlighted) - } - /// Applies the reset filter button style to the button passed as an argument - class func applyReaderResetFilterButtonStyle(_ button: UIButton) { - let icon = UIImage.gridicon(.crossSmall) - - button.setImage(icon, for: .normal) - applyReaderActionButtonStyle(button, imageColor: UIColor(light: .black, dark: .white)) - } - // MARK: - Gap Marker Styles @objc public class func applyGapMarkerButtonStyle(_ button: UIButton) { diff --git a/WordPress/UITests/Utils/XCTest+Extensions.swift b/WordPress/UITests/Utils/XCTest+Extensions.swift index 33336cd4fad0..8ba92def173b 100644 --- a/WordPress/UITests/Utils/XCTest+Extensions.swift +++ b/WordPress/UITests/Utils/XCTest+Extensions.swift @@ -53,8 +53,6 @@ extension XCTestCase { app.launchArguments.append(contentsOf: ["-ui-test-select-wpcom-site", selectWPComSite]) } - app.launchArguments.append(contentsOf: ["-ff-override-Reader Reset", "false"]) - if removeBeforeLaunching { removeApp(app) } From 895c121c2bbf862e62b1c5723d0629b5958cdefa Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 15:35:41 -0400 Subject: [PATCH 38/55] Remove unused WPStyleGuide+Reader --- .../Reader/WPStyleGuide+Reader.swift | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift b/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift index 96fcb5e2a93a..44a7e62c5d42 100644 --- a/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift +++ b/WordPress/Classes/ViewRelated/Reader/WPStyleGuide+Reader.swift @@ -29,10 +29,6 @@ extension WPStyleGuide { .separator } - @objc public class func readerCardCellHighlightedBorderColor() -> UIColor { - UIAppColor.neutral(.shade10) - } - public class func readerCardBlogIconBorderColor() -> UIColor { return UIColor(light: UIAppColor.gray(.shade0), dark: .systemGray5) } @@ -86,16 +82,6 @@ extension WPStyleGuide { // MARK: - Apply Card Styles - @objc public class func applyReaderCardSiteButtonStyle(_ button: UIButton) { - guard let titleLabel = button.titleLabel else { - return - } - WPStyleGuide.configureLabel(titleLabel, textStyle: Cards.buttonTextStyle) - button.setTitleColor(UIAppColor.primary, for: UIControl.State()) - button.setTitleColor(UIAppColor.primaryDark, for: .highlighted) - button.setTitleColor(.label, for: .disabled) - } - public class func applyReaderCardAttributionLabelStyle(_ label: UILabel) { label.textColor = UIColor( light: UIAppColor.gray(.shade80), @@ -103,15 +89,6 @@ extension WPStyleGuide { ) } - @objc public class func applyReaderCardActionButtonStyle(_ button: UIButton) { - guard let titleLabel = button.titleLabel else { - return - } - WPStyleGuide.configureLabel(titleLabel, textStyle: Cards.buttonTextStyle) - - WPStyleGuide.applyReaderActionButtonStyle(button) - } - // MARK: - Apply Stream Header Styles @objc public class func applyReaderStreamHeaderTitleStyle(_ label: UILabel, usesNewStyle: Bool = false) { From 3cb736f4400629e9449c27a8b2b46d3729e77c16 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 15:36:46 -0400 Subject: [PATCH 39/55] Fix build --- .../App Configuration/AppStyleGuide.swift | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift b/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift index ee668abbe59c..791c349676c3 100644 --- a/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift +++ b/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift @@ -4,42 +4,42 @@ import WordPressUI import ColorStudio struct AppStyleGuide { - - #if IS_JETPACK - static let navigationBarStandardFont: UIFont = Feature.enabled(.serif) ? WPStyleGuide.fixedSerifFontForTextStyle(.headline, fontWeight: .semibold) : WPStyleGuide.fontForTextStyle(.headline, fontWeight: .semibold) - static let navigationBarLargeFont: UIFont = Feature.enabled(.serif) ? WPStyleGuide.fixedSerifFontForTextStyle(.largeTitle, fontWeight: .semibold) : WPStyleGuide.fontForTextStyle(.largeTitle, fontWeight: .semibold) - static let epilogueTitleFont: UIFont = Feature.enabled(.serif) ? WPStyleGuide.fixedSerifFontForTextStyle(.largeTitle, fontWeight: .semibold) : WPStyleGuide.fontForTextStyle(.largeTitle, fontWeight: .semibold) - #endif - - #if IS_WORDPRESS + +#if IS_JETPACK + static let navigationBarStandardFont: UIFont = WPStyleGuide.fontForTextStyle(.headline, fontWeight: .semibold) + static let navigationBarLargeFont: UIFont = WPStyleGuide.fontForTextStyle(.largeTitle, fontWeight: .semibold) + static let epilogueTitleFont: UIFont = WPStyleGuide.fontForTextStyle(.largeTitle, fontWeight: .semibold) +#endif + +#if IS_WORDPRESS static let navigationBarStandardFont: UIFont = WPStyleGuide.fixedSerifFontForTextStyle(.headline, fontWeight: .semibold) static let navigationBarLargeFont: UIFont = WPStyleGuide.fixedSerifFontForTextStyle(.largeTitle, fontWeight: .semibold) static let epilogueTitleFont: UIFont = WPStyleGuide.fixedSerifFontForTextStyle(.largeTitle, fontWeight: .semibold) - #endif +#endif } // MARK: - Images extension AppStyleGuide { - #if IS_JETPACK +#if IS_JETPACK static let mySiteTabIcon = UIImage(named: "jetpack-icon-tab-mysites") - #endif - - #if IS_WORDPRESS +#endif + +#if IS_WORDPRESS static let mySiteTabIcon = UIImage(named: "icon-tab-mysites") - #endif +#endif } // MARK: - Fonts extension AppStyleGuide { - #if IS_JETPACK +#if IS_JETPACK static func prominentFont(textStyle: UIFont.TextStyle, weight: UIFont.Weight) -> UIFont { WPStyleGuide.fontForTextStyle(textStyle, fontWeight: weight) } - #endif - - #if IS_WORDPRESS +#endif + +#if IS_WORDPRESS static func prominentFont(textStyle: UIFont.TextStyle, weight: UIFont.Weight) -> UIFont { WPStyleGuide.serifFontForTextStyle(textStyle, fontWeight: weight) } - #endif +#endif } From accd5490c256f79bd91defa7a2babf5b7489e191 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 15:41:15 -0400 Subject: [PATCH 40/55] Fix build --- .../Classes/Utility/App Configuration/AppStyleGuide.swift | 8 ++++---- .../ViewRelated/Reader/ReaderStreamViewController.swift | 4 ---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift b/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift index 791c349676c3..c17bd994135b 100644 --- a/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift +++ b/WordPress/Classes/Utility/App Configuration/AppStyleGuide.swift @@ -4,13 +4,13 @@ import WordPressUI import ColorStudio struct AppStyleGuide { - + #if IS_JETPACK static let navigationBarStandardFont: UIFont = WPStyleGuide.fontForTextStyle(.headline, fontWeight: .semibold) static let navigationBarLargeFont: UIFont = WPStyleGuide.fontForTextStyle(.largeTitle, fontWeight: .semibold) static let epilogueTitleFont: UIFont = WPStyleGuide.fontForTextStyle(.largeTitle, fontWeight: .semibold) #endif - + #if IS_WORDPRESS static let navigationBarStandardFont: UIFont = WPStyleGuide.fixedSerifFontForTextStyle(.headline, fontWeight: .semibold) static let navigationBarLargeFont: UIFont = WPStyleGuide.fixedSerifFontForTextStyle(.largeTitle, fontWeight: .semibold) @@ -23,7 +23,7 @@ extension AppStyleGuide { #if IS_JETPACK static let mySiteTabIcon = UIImage(named: "jetpack-icon-tab-mysites") #endif - + #if IS_WORDPRESS static let mySiteTabIcon = UIImage(named: "icon-tab-mysites") #endif @@ -36,7 +36,7 @@ extension AppStyleGuide { WPStyleGuide.fontForTextStyle(textStyle, fontWeight: weight) } #endif - + #if IS_WORDPRESS static func prominentFont(textStyle: UIFont.TextStyle, weight: UIFont.Weight) -> UIFont { WPStyleGuide.serifFontForTextStyle(textStyle, fontWeight: weight) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index f77f1086ee98..6b11244da806 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -1492,10 +1492,6 @@ extension ReaderStreamViewController: WPTableViewHandlerDelegate { // Check to see if we need to load more. syncMoreContentIfNeeded(for: tableView, indexPathForVisibleRow: indexPath) - if let cell = cell as? ReaderPostCardCell { - cell.prepareForDisplay() - } - guard cell.isKind(of: ReaderCrossPostCell.self) else { return } From 1a446499d6dca9f9132b08d892bcb860bbaf4c53 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 17:16:10 -0400 Subject: [PATCH 41/55] Remove NetworkStatusReceiver --- .../ViewRelated/System/NetworkAware.swift | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/WordPress/Classes/ViewRelated/System/NetworkAware.swift b/WordPress/Classes/ViewRelated/System/NetworkAware.swift index bb5fcc79cbce..6d7e4f7bd2ca 100644 --- a/WordPress/Classes/ViewRelated/System/NetworkAware.swift +++ b/WordPress/Classes/ViewRelated/System/NetworkAware.swift @@ -70,25 +70,6 @@ extension NetworkStatusDelegate where Self: UIViewController { } } -// TODO: - READERNAV - This is being used for the new Reader, currently under development. Once it's released, there should only be one extension -protocol NetworkStatusReceiver {} - -extension NetworkStatusDelegate where Self: NetworkStatusReceiver { - func observeNetworkStatus() { - receiver = ReachabilityNotificationObserver(delegate: self) - } - - fileprivate var receiver: ReachabilityNotificationObserver? { - get { - return objc_getAssociatedObject(self, NetworkStatusAssociatedKeys.associatedObjectKey) as? ReachabilityNotificationObserver - } - - set { - objc_setAssociatedObject(self, NetworkStatusAssociatedKeys.associatedObjectKey, newValue, .OBJC_ASSOCIATION_RETAIN) - } - } -} - fileprivate struct NetworkStatusAssociatedKeys { static let associatedObjectKey = malloc(1)! } From f471b5b79545f945a9d9805cd125fd69ae8ad6f4 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 17:18:18 -0400 Subject: [PATCH 42/55] Remove unused reportStreamLoadFailure --- .../Reader/ReaderStreamViewController.swift | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 6b11244da806..720a2f7d392d 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -1,5 +1,4 @@ import Foundation - import SVProgressHUD import WordPressShared import WordPressFlux @@ -17,7 +16,6 @@ import AutomatticTracks /// - Syncing is performed on a derived (background) context. /// - Row heights are auto-calculated via UITableViewAutomaticDimension and estimated heights /// are cached via willDisplayCell. -/// @objc class ReaderStreamViewController: UIViewController, ReaderSiteBlockingControllerDelegate { // MARK: - Micro Controllers @@ -36,9 +34,6 @@ import AutomatticTracks // MARK: - Properties - /// Called if the stream or tag fails to load - var streamLoadFailureBlock: (() -> Void)? = nil - var tableView: UITableView! { return tableViewController.tableView } @@ -436,7 +431,6 @@ import AutomatticTracks self?.updateContent(synchronize: false) } self?.displayLoadingStreamFailed() - self?.reportStreamLoadFailure() return } self?.readerTopic = topic @@ -447,7 +441,6 @@ import AutomatticTracks self?.updateContent(synchronize: false) } self?.displayLoadingStreamFailed() - self?.reportStreamLoadFailure() }) } @@ -465,7 +458,6 @@ import AutomatticTracks guard let objectID = objectID, let topic = (try? context.existingObject(with: objectID)) as? ReaderAbstractTopic else { DDLogError("Reader: Error retriving an existing tag topic by its objectID") self?.displayLoadingStreamFailed() - self?.reportStreamLoadFailure() return } self?.readerTopic = topic @@ -473,7 +465,6 @@ import AutomatticTracks }, failure: { [weak self] (error: Error?) in self?.displayLoadingStreamFailed() - self?.reportStreamLoadFailure() }) } @@ -1329,16 +1320,8 @@ extension ReaderStreamViewController: WPContentSyncHelperDelegate { if let count = content.content?.count, count == 0 { displayLoadingStreamFailed() - reportStreamLoadFailure() } } - - private func reportStreamLoadFailure() { - streamLoadFailureBlock?() - - // We'll nil out the failure block so we don't perform multiple callbacks - streamLoadFailureBlock = nil - } } // MARK: - WPTableViewHandlerDelegate From 7beb6546102c19be3e9b72bc0f2216bb3424c27f Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 17:20:06 -0400 Subject: [PATCH 43/55] Remove unused scrollViewTranslationPublisher --- .../Reader/ReaderStreamViewController.swift | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 720a2f7d392d..02b106e3d2db 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -59,19 +59,12 @@ import AutomatticTracks guard let noFollowedSitesVC = noFollowedSitesViewController else { return noResultsStatusViewController } - return noFollowedSitesVC } } - private var coreDataStack: CoreDataStack { - ContextManager.shared - } - - /// An alias for the apps's main context - var viewContext: NSManagedObjectContext { - coreDataStack.mainContext - } + private var coreDataStack: CoreDataStack { ContextManager.shared } + var viewContext: NSManagedObjectContext { coreDataStack.mainContext } private(set) lazy var footerView: PostListFooterView = { return tableConfiguration.footer() From eb7b395eb32443e054fb08aa5db0d63de916eb63 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 17:23:16 -0400 Subject: [PATCH 44/55] Remove shouldDisplayNoTopicController --- .../Reader/ReaderSidebarViewModel.swift | 1 - .../Reader/ReaderStreamViewController.swift | 67 +------------------ 2 files changed, 1 insertion(+), 67 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift index 94e517040335..52e482bb5478 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift @@ -120,7 +120,6 @@ enum ReaderStaticScreen: String, CaseIterable, Identifiable, Hashable { } enum ReaderContentType { - case contentError case saved case topic } diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 02b106e3d2db..680271b1e809 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -78,8 +78,6 @@ import AutomatticTracks return refreshControl }() - private var noTopicController: UIViewController? - private let loadMoreThreashold = 4 private let refreshInterval = 300 @@ -236,7 +234,7 @@ import AutomatticTracks var isEmbeddedInDiscover = false - // MARK: - Factory Methods + // MARK: - Init /// Convenience method for instantiating an instance of ReaderStreamViewController /// for a existing topic. @@ -337,10 +335,6 @@ import AutomatticTracks didSetupView = true - guard !shouldDisplayNoTopicController else { - return - } - if readerTopic != nil || contentType == .saved { // Do not perform a sync since a sync will be executed in viewWillAppear anyway. This // prevents a possible internet connection error being shown twice. @@ -1859,65 +1853,6 @@ extension ReaderStreamViewController: UIViewControllerTransitioningDelegate { } } -// MARK: - View content types without a topic -private extension ReaderStreamViewController { - - var shouldDisplayNoTopicController: Bool { - switch contentType { - case .contentError: - displayContentErrorController() - return true - default: - removeNoTopicController() - return false - } - } - - func displayContentErrorController() { - let controller = noTopicViewController(title: NoTopicConstants.contentErrorTitle, - subtitle: NoTopicConstants.contentErrorSubtitle, - image: NoTopicConstants.contentErrorImage) - addNoTopicController(controller) - - view.isUserInteractionEnabled = true - } - - func noTopicViewController(title: String, - buttonTitle: String? = nil, - subtitle: String? = nil, - image: String? = nil) -> NoResultsViewController { - let controller = NoResultsViewController.controller() - controller.configure(title: title, - buttonTitle: buttonTitle, - subtitle: subtitle, - image: image) - - return controller - } - - func addNoTopicController(_ controller: NoResultsViewController) { - addChild(controller) - view.addSubview(controller.view) - controller.view.translatesAutoresizingMaskIntoConstraints = false - view.pinSubviewToAllEdges(controller.view) - controller.didMove(toParent: self) - noTopicController = controller - } - - func removeNoTopicController() { - if let controller = noTopicController as? NoResultsViewController { - controller.removeFromView() - noTopicController = nil - } - } - - enum NoTopicConstants { - static let contentErrorTitle = NSLocalizedString("Unable to load this content right now.", comment: "Default title shown for no-results when the device is offline.") - static let contentErrorSubtitle = NSLocalizedString("Check your network connection and try again.", comment: "Default subtitle for no-results when there is no connection") - static let contentErrorImage = "cloud" - } -} - // MARK: - Jetpack banner delegate extension ReaderStreamViewController: UITableViewDelegate, JPScrollViewDelegate { From c6ea4f6c8bf2747b9e2eb071f7e613290b3bf690 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 17:24:21 -0400 Subject: [PATCH 45/55] Remove ReaderStreamError --- .../Reader/ReaderStreamViewController.swift | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 680271b1e809..116d44b0400e 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -1413,7 +1413,7 @@ extension ReaderStreamViewController: WPTableViewHandlerDelegate { if let post = posts[safe: indexPath.row] { return cell(for: post, at: indexPath) } else { - logReaderError(.invalidIndexPath(row: indexPath.row, totalRows: posts.count)) + wpAssertionFailure("invalid_index_path") return .init() } } @@ -1471,7 +1471,7 @@ extension ReaderStreamViewController: WPTableViewHandlerDelegate { } guard let post = posts[safe: indexPath.row] else { - logReaderError(.invalidIndexPath(row: indexPath.row, totalRows: posts.count)) + wpAssertionFailure("invalid_index_path") return } @@ -1517,7 +1517,7 @@ extension ReaderStreamViewController: WPTableViewHandlerDelegate { } guard let apost = posts[safe: indexPath.row] else { - logReaderError(.invalidIndexPath(row: indexPath.row, totalRows: posts.count)) + wpAssertionFailure("invalid_index_path") return } @@ -1862,26 +1862,6 @@ extension ReaderStreamViewController: UITableViewDelegate, JPScrollViewDelegate } } -// MARK: - Custom Errors - -extension ReaderStreamViewController { - - enum ReaderStreamError: LocalizedError { - case invalidIndexPath(row: Int, totalRows: Int) - - var errorDescription: String? { - switch self { - case .invalidIndexPath(let row, let totalRows): - return "Reader Stream: tried to request index \(row) from \(totalRows) objects" - } - } - } - - func logReaderError(_ error: ReaderStreamError) { - CrashLogging.main.logError(error, tags: ["source": "reader_stream"]) - } -} - private enum Strings { static let postRemoved = NSLocalizedString("reader.savedPostRemovedNotificationTitle", value: "Saved post removed", comment: "Notification title for when saved post is removed") } From 9c75539c37d463dfd402aab268d25deb030159b4 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 17:25:04 -0400 Subject: [PATCH 46/55] Remove isSidebarModeEnabled --- .../Classes/ViewRelated/Reader/ReaderStreamViewController.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 116d44b0400e..e34ea9a2c676 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -230,8 +230,6 @@ import AutomatticTracks /// This is set to true after the Reader Manage view is dismissed var shouldForceRefresh = false - lazy var isSidebarModeEnabled = splitViewController?.isCollapsed == false - var isEmbeddedInDiscover = false // MARK: - Init From 107cbebc7422183cd1ef13eb5134b5aecd6ac1c3 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 17:29:13 -0400 Subject: [PATCH 47/55] Extract ReaderSelectInterestsConfiguration --- .../Reader/ReaderDiscoverViewController.swift | 6 +- .../Reader/ReaderStreamViewController.swift | 52 +++----------- .../ReaderSelectInterestsViewController.swift | 68 +++++++++++++++---- 3 files changed, 64 insertions(+), 62 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift index 35bfd4e57522..9dbc731c2a23 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderDiscoverViewController.swift @@ -336,10 +336,8 @@ private class ReaderDiscoverStreamViewController: ReaderStreamViewController { // MARK: - Select Interests Display private extension ReaderDiscoverStreamViewController { func displaySelectInterestsIfNeeded() { - selectInterestsViewController.userIsFollowingTopics { [weak self] isFollowing in - guard let self else { - return - } + selectInterestsVC.userIsFollowingTopics { [weak self] isFollowing in + guard let self else { return } if isFollowing { self.hideSelectInterestsView() } else { diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index e34ea9a2c676..0b1b2282152d 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -190,42 +190,8 @@ import AutomatticTracks private var showConfirmation = true - lazy var selectInterestsViewController: ReaderSelectInterestsViewController = { - let title = NSLocalizedString( - "reader.select.tags.title", - value: "Discover and follow blogs you love", - comment: "Reader select interests title label text" - ) - let subtitle = NSLocalizedString( - "reader.select.tags.subtitle", - value: "Choose your tags", - comment: "Reader select interests subtitle label text" - ) - let buttonTitleEnabled = NSLocalizedString( - "reader.select.tags.done", - value: "Done", - comment: "Reader select interests next button enabled title text" - ) - let buttonTitleDisabled = NSLocalizedString( - "reader.select.tags.continue", - value: "Select a few to continue", - comment: "Reader select interests next button disabled title text" - ) - let loading = NSLocalizedString( - "reader.select.tags.loading", - value: "Finding blogs and stories you’ll love...", - comment: "Label displayed to the user while loading their selected interests" - ) - - let configuration = ReaderSelectInterestsConfiguration( - title: title, - subtitle: subtitle, - buttonTitle: (enabled: buttonTitleEnabled, disabled: buttonTitleDisabled), - loading: loading - ) + lazy var selectInterestsVC = ReaderSelectInterestsViewController(configuration: .discover) - return ReaderSelectInterestsViewController(configuration: configuration) - }() /// Tracks whether or not we should force sync /// This is set to true after the Reader Manage view is dismissed var shouldForceRefresh = false @@ -1712,14 +1678,14 @@ extension ReaderStreamViewController { } func showSelectInterestsView() { - guard selectInterestsViewController.parent == nil else { + guard selectInterestsVC.parent == nil else { return } - selectInterestsViewController.view.frame = self.view.bounds - self.add(selectInterestsViewController) + selectInterestsVC.view.frame = self.view.bounds + self.add(selectInterestsVC) - selectInterestsViewController.didSaveInterests = { [weak self] _ in + selectInterestsVC.didSaveInterests = { [weak self] _ in guard let self else { return } @@ -1728,7 +1694,7 @@ extension ReaderStreamViewController { } func hideSelectInterestsView(showLoadingStream: Bool = true) { - guard selectInterestsViewController.parent != nil else { + guard selectInterestsVC.parent != nil else { if shouldForceRefresh { scrollViewToTop() displayLoadingStream() @@ -1744,10 +1710,10 @@ extension ReaderStreamViewController { syncIfAppropriate(forceSync: true) UIView.animate(withDuration: 0.2, animations: { - self.selectInterestsViewController.view.alpha = 0 + self.selectInterestsVC.view.alpha = 0 }) { _ in - self.selectInterestsViewController.remove() - self.selectInterestsViewController.view.alpha = 1 + self.selectInterestsVC.remove() + self.selectInterestsVC.view.alpha = 1 } } diff --git a/WordPress/Classes/ViewRelated/Reader/Select Interests/ReaderSelectInterestsViewController.swift b/WordPress/Classes/ViewRelated/Reader/Select Interests/ReaderSelectInterestsViewController.swift index 9334aeaa74a3..ce1094822be0 100644 --- a/WordPress/Classes/ViewRelated/Reader/Select Interests/ReaderSelectInterestsViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Select Interests/ReaderSelectInterestsViewController.swift @@ -11,21 +11,6 @@ struct ReaderSelectInterestsConfiguration { let subtitle: String? let buttonTitle: (enabled: String, disabled: String)? let loading: String - - static let `default` = ReaderSelectInterestsConfiguration( - title: NSLocalizedString( - "reader.select.interests.follow.title", - value: "Follow tags", - comment: "Screen title. Reader select interests title label text." - ), - subtitle: nil, - buttonTitle: nil, - loading: NSLocalizedString( - "reader.select.interests.following", - value: "Following new tags...", - comment: "Label displayed to the user while loading their selected interests" - ) - ) } class ReaderSelectInterestsViewController: UIViewController { @@ -416,3 +401,56 @@ extension ReaderSelectInterestsViewController { noResultsViewController.removeFromView() } } + +extension ReaderSelectInterestsConfiguration { + static let `default` = ReaderSelectInterestsConfiguration( + title: NSLocalizedString( + "reader.select.interests.follow.title", + value: "Follow tags", + comment: "Screen title. Reader select interests title label text." + ), + subtitle: nil, + buttonTitle: nil, + loading: NSLocalizedString( + "reader.select.interests.following", + value: "Following new tags...", + comment: "Label displayed to the user while loading their selected interests" + ) + ) + + /// Configuration for the "Discover" screen. + static var discover: ReaderSelectInterestsConfiguration { + let title = NSLocalizedString( + "reader.select.tags.title", + value: "Discover and follow blogs you love", + comment: "Reader select interests title label text" + ) + let subtitle = NSLocalizedString( + "reader.select.tags.subtitle", + value: "Choose your tags", + comment: "Reader select interests subtitle label text" + ) + let buttonTitleEnabled = NSLocalizedString( + "reader.select.tags.done", + value: "Done", + comment: "Reader select interests next button enabled title text" + ) + let buttonTitleDisabled = NSLocalizedString( + "reader.select.tags.continue", + value: "Select a few to continue", + comment: "Reader select interests next button disabled title text" + ) + let loading = NSLocalizedString( + "reader.select.tags.loading", + value: "Finding blogs and stories you’ll love...", + comment: "Label displayed to the user while loading their selected interests" + ) + + return ReaderSelectInterestsConfiguration( + title: title, + subtitle: subtitle, + buttonTitle: (enabled: buttonTitleEnabled, disabled: buttonTitleDisabled), + loading: loading + ) + } +} From a1a32251e0171104cf7e1a5fd2f8998cce3d8656 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 17:32:18 -0400 Subject: [PATCH 48/55] Remove ReaderStreamViewController from Storyboard --- .../ViewRelated/Reader/Reader.storyboard | 29 ++----------------- .../Reader/ReaderStreamViewController.swift | 4 +-- 2 files changed, 3 insertions(+), 30 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/Reader.storyboard b/WordPress/Classes/ViewRelated/Reader/Reader.storyboard index 010f7503846a..d647101a9c0b 100644 --- a/WordPress/Classes/ViewRelated/Reader/Reader.storyboard +++ b/WordPress/Classes/ViewRelated/Reader/Reader.storyboard @@ -1,34 +1,12 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - @@ -103,9 +81,6 @@ - - - diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 0b1b2282152d..691e84d36e0c 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -245,10 +245,8 @@ import AutomatticTracks /// - Returns: An instance of the controller /// @objc class func controllerWithTagSlug(_ tagSlug: String) -> ReaderStreamViewController { - let storyboard = UIStoryboard(name: "Reader", bundle: Bundle.main) - let controller = storyboard.instantiateViewController(withIdentifier: "ReaderStreamViewController") as! ReaderStreamViewController + let controller = ReaderStreamViewController() controller.tagSlug = tagSlug - return controller } From ce86a693b11104ae63622d08295e375044b889fa Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 21:00:38 -0400 Subject: [PATCH 49/55] Remove unused code from ReaderHelpers --- .../Reader/ReaderCellConfiguration.swift | 2 + .../ViewRelated/Reader/ReaderHelpers.swift | 98 ------------------- .../Reader/ReaderStreamViewController.swift | 3 +- 3 files changed, 3 insertions(+), 100 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderCellConfiguration.swift b/WordPress/Classes/ViewRelated/Reader/ReaderCellConfiguration.swift index 83a1cc5a632d..503e8ba61abf 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderCellConfiguration.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderCellConfiguration.swift @@ -1,3 +1,5 @@ +import UIKit + /// Configuration and population of cells in Reader final class ReaderCellConfiguration { func configureCrossPostCell(_ cell: ReaderCrossPostCell, withContent content: ReaderTableContent, atIndexPath indexPath: IndexPath) { diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift b/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift index afe98b3cf05b..4a3973c92ca9 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift @@ -31,77 +31,6 @@ struct ReaderNotificationKeys { static let topic = "topic" } -// Used for event tracking properties -enum ReaderPostMenuSource { - case card - case details - case tagCard - - var description: String { - switch self { - case .card: - return "post_card" - case .details: - return "post_details" - case .tagCard: - return "post_tag_card" - } - } -} - -// Titles for post menu options -struct ReaderPostMenuButtonTitles { - static let cancel = NSLocalizedString("Cancel", comment: "The title of a cancel button.") - static let blockSite = NSLocalizedString( - "reader.post.menu.block.blog", - value: "Block this blog", - comment: "The title of a button that triggers blocking a blog from the user's reader." - ) - static let blockUser = NSLocalizedString( - "reader.post.menu.block.user", - value: "Block this user", - comment: "The title of a button that triggers blocking a user from the user's reader." - ) - static let reportPost = NSLocalizedString("Report this post", comment: "The title of a button that triggers reporting of a post from the user's reader.") - static let reportPostAuthor = NSLocalizedString( - "reader.post.menu.report.user", - value: "Report this user", - comment: "The title of a button that triggers the reporting of a post's author." - ) - static let share = NSLocalizedString("Share", comment: "Verb. Title of a button. Pressing lets the user share a post to others.") - static let visit = NSLocalizedString("Visit", comment: "An option to visit the site to which a specific post belongs") - static let unfollow = NSLocalizedString( - "reader.post.menu.unsubscribe.blog", - value: "Unsubscribe from blog", - comment: "Verb. An option to unsubscribe from a blog." - ) - static let follow = NSLocalizedString( - "reader.post.menu.subscribe.blog", - value: "Subscribe to blog", - comment: "Verb. An option to subscribe to a blog." - ) - static let subscribe = NSLocalizedString( - "reader.post.menu.notifications.on", - value: "Turn on blog notifications", - comment: "Verb. An option to switch on blog notifications." - ) - static let unsubscribe = NSLocalizedString( - "reader.post.menu.notifications.off", - value: "Turn off blog notifications", - comment: "Verb. An option to switch off site notifications." - ) - static let markSeen = NSLocalizedString("Mark as seen", comment: "An option to mark a post as seen.") - static let markUnseen = NSLocalizedString("Mark as unseen", comment: "An option to mark a post as unseen.") - static let followConversation = NSLocalizedString("Follow conversation", comment: "Verb. Button title. Follow the comments on a post.") - static let unFollowConversation = NSLocalizedString("Unfollow conversation", comment: "Verb. Button title. The user is following the comments on a post.") - static let savePost = NSLocalizedString("reader.post.menu.save.post", - value: "Save", - comment: "The title of a button that saves a post.") - static let removeSavedPost = NSLocalizedString("reader.post.menu.remove.post", - value: "Remove Saved Post", - comment: "The title of a button that removes a saved post.") -} - /// A collection of helper methods used by the Reader. /// @objc open class ReaderHelpers: NSObject { @@ -223,18 +152,6 @@ struct ReaderPostMenuButtonTitles { return topic.path.hasSuffix("/read/liked") } - /// Check if the specified topic is for Posts Saved for Later - /// - /// - Parameters: - /// - topic: A ReaderAbstractTopic - /// - /// - Returns: True if the topic is for Saved For Later - /// - @objc open class func topicIsSavedForLater(_ topic: ReaderAbstractTopic) -> Bool { - //TODO. Update this logic with the right one. I am not sure how this is going to be modeeled now. - return topic.path.hasSuffix("/mock") - } - // MARK: Analytics Helpers class func trackLoadedTopic(_ topic: ReaderAbstractTopic, withProperties properties: [AnyHashable: Any]) { @@ -385,17 +302,6 @@ struct ReaderPostMenuButtonTitles { // MARK: ActionDispatcher Notification helper - class func dispatchToggleSeenMessage(post: ReaderPost, success: Bool) { - var notice: Notice { - if success { - return Notice(title: post.isSeen ? NoticeMessages.seenSuccess : NoticeMessages.unseenSuccess) - } - return Notice(title: post.isSeen ? NoticeMessages.unseenFail : NoticeMessages.seenFail) - } - - dispatchNotice(notice) - } - class func dispatchToggleFollowSiteMessage(post: ReaderPost, follow: Bool, success: Bool) { guard let siteID = post.siteID else { /// This is a workaround to prevent a crash from occurring when trying to pass a `nil` site ID to dispatchToggleFollowSiteMessage. @@ -538,10 +444,6 @@ struct ReaderPostMenuButtonTitles { } private struct NoticeMessages { - static let seenFail = NSLocalizedString("Unable to mark post seen", comment: "Notice title when updating a post's seen status failed.") - static let unseenFail = NSLocalizedString("Unable to mark post unseen", comment: "Notice title when updating a post's unseen status failed.") - static let seenSuccess = NSLocalizedString("Marked post as seen", comment: "Notice title when updating a post's seen status succeeds.") - static let unseenSuccess = NSLocalizedString("Marked post as unseen", comment: "Notice title when updating a post's unseen status succeeds.") static let followSuccess = NSLocalizedString( "reader.notice.subscribe.success", value: "Subscribed to %1$@", diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 691e84d36e0c..8fdde8e44da4 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -1754,9 +1754,8 @@ extension ReaderStreamViewController { } var readerEmptyImageName: String { - return "wp-illustration-reader-empty" + "wp-illustration-reader-empty" } - } // MARK: - NoResultsViewControllerDelegate From 08b5c7d7b05dee01d08c2979482ba8512074b837 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 25 Oct 2024 21:02:03 -0400 Subject: [PATCH 50/55] Remove unused code from ReaderPost+Display --- .../Reader/ReaderPost+Display.swift | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderPost+Display.swift b/WordPress/Classes/ViewRelated/Reader/ReaderPost+Display.swift index 5dc74feb13eb..1c38880941dc 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderPost+Display.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderPost+Display.swift @@ -1,3 +1,4 @@ +import Foundation extension ReaderPost { @@ -8,24 +9,4 @@ extension ReaderPost { return usesWPComAPI && (commentsOpen() || hasComments) } - - func isLikesEnabled(isLoggedIn: Bool) -> Bool { - let likeCount = likeCount()?.intValue ?? 0 - return !isExternal() && (likeCount > 0 || isLoggedIn) - } - - func shortDateForDisplay() -> String? { - let isRTL = UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft - guard let date = dateForDisplay()?.toShortString() else { - return nil - } - let postDateFormat = isRTL ? "%@ •" : "• %@" - return blogNameForDisplay() != nil ? String(format: postDateFormat, date) : date - } - - func summaryForDisplay(isPad: Bool = false) -> String? { - return contentPreviewForDisplay()? - .replacingOccurrences(of: "\n{2,}", with: "\n\n", options: .regularExpression) - } - } From 8b813d830349172592a32ff3060e01441761c067 Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 28 Oct 2024 10:15:48 -0400 Subject: [PATCH 51/55] Update UI tests --- .../Navigation/MainNavigationComponent.swift | 2 +- .../Navigation/SidebarNavComponent.swift | 2 +- .../Screens/Navigation/SidebarScreen.swift | 3 +- .../Screens/Navigation/TabNavComponent.swift | 4 +- .../Screens/ReaderMenuScreen.swift | 27 ++++++++++ .../Screens/ReaderScreen.swift | 49 +++++------------- .../Classes/System/ReaderPresenter.swift | 1 + .../ViewRelated/Reader/ReaderPostMenu.swift | 4 +- .../Reader/ReaderSidebarViewModel.swift | 25 ++++++---- WordPress/UITests/Tests/ReaderTests.swift | 50 +++++++++---------- 10 files changed, 87 insertions(+), 80 deletions(-) create mode 100644 Modules/Sources/UITestsFoundation/Screens/ReaderMenuScreen.swift diff --git a/Modules/Sources/UITestsFoundation/Screens/Navigation/MainNavigationComponent.swift b/Modules/Sources/UITestsFoundation/Screens/Navigation/MainNavigationComponent.swift index b34b8b4e3ba8..f51392d34040 100644 --- a/Modules/Sources/UITestsFoundation/Screens/Navigation/MainNavigationComponent.swift +++ b/Modules/Sources/UITestsFoundation/Screens/Navigation/MainNavigationComponent.swift @@ -3,7 +3,7 @@ import XCTest import UIKit public protocol MainNavigationComponent { - func goToReaderScreen() throws -> ReaderScreen + func goToReaderScreen() throws func goToNotificationsScreen() throws -> NotificationsScreen func goToMeScreen() throws -> MeTabScreen } diff --git a/Modules/Sources/UITestsFoundation/Screens/Navigation/SidebarNavComponent.swift b/Modules/Sources/UITestsFoundation/Screens/Navigation/SidebarNavComponent.swift index 06ff6d3ffaf5..3119c9e5c938 100644 --- a/Modules/Sources/UITestsFoundation/Screens/Navigation/SidebarNavComponent.swift +++ b/Modules/Sources/UITestsFoundation/Screens/Navigation/SidebarNavComponent.swift @@ -12,7 +12,7 @@ public class SidebarNavComponent: ScreenObject, MainNavigationComponent { try openSidebar().openMeScreen() } - public func goToReaderScreen() throws -> ReaderScreen { + public func goToReaderScreen() throws { try openSidebar().openReaderScreen() } diff --git a/Modules/Sources/UITestsFoundation/Screens/Navigation/SidebarScreen.swift b/Modules/Sources/UITestsFoundation/Screens/Navigation/SidebarScreen.swift index 073a20a2c8ba..c8d559ec56a5 100644 --- a/Modules/Sources/UITestsFoundation/Screens/Navigation/SidebarScreen.swift +++ b/Modules/Sources/UITestsFoundation/Screens/Navigation/SidebarScreen.swift @@ -14,10 +14,9 @@ public class SidebarScreen: ScreenObject { return try MeTabScreen() } - public func openReaderScreen() throws -> ReaderScreen { + public func openReaderScreen() { app.staticTexts["sidebar_reader"].firstMatch.tap() app.swipeLeft() // Close the sidebar - return try ReaderScreen() } public func openNotificationsScreen() throws -> NotificationsScreen { diff --git a/Modules/Sources/UITestsFoundation/Screens/Navigation/TabNavComponent.swift b/Modules/Sources/UITestsFoundation/Screens/Navigation/TabNavComponent.swift index b8643fa70aff..401488804826 100644 --- a/Modules/Sources/UITestsFoundation/Screens/Navigation/TabNavComponent.swift +++ b/Modules/Sources/UITestsFoundation/Screens/Navigation/TabNavComponent.swift @@ -54,10 +54,8 @@ public class TabNavComponent: ScreenObject, MainNavigationComponent { return try BlockEditorScreen() } - @discardableResult - public func goToReaderScreen() throws -> ReaderScreen { + public func goToReaderScreen() throws { readerTabButton.tap() - return try ReaderScreen() } public func goToNotificationsScreen() throws -> NotificationsScreen { diff --git a/Modules/Sources/UITestsFoundation/Screens/ReaderMenuScreen.swift b/Modules/Sources/UITestsFoundation/Screens/ReaderMenuScreen.swift new file mode 100644 index 000000000000..cb5cfcfb89b7 --- /dev/null +++ b/Modules/Sources/UITestsFoundation/Screens/ReaderMenuScreen.swift @@ -0,0 +1,27 @@ +import ScreenObject +import XCTest + +public final class ReaderMenuScreen: ScreenObject { + public init(app: XCUIApplication = XCUIApplication()) throws { + try super.init { + $0.collectionViews["reader_sidebar"].firstMatch + } + } + + public enum ReaderStream: String { + case recent + case discover + case saved + case likes + + func menuButton(_ app: XCUIApplication) -> XCUIElement { + app.staticTexts["reader_sidebar_\(rawValue)"].firstMatch + } + } + + @discardableResult + public func open(_ stream: ReaderStream) throws -> ReaderScreen { + stream.menuButton(app).tap() + return try ReaderScreen() + } +} diff --git a/Modules/Sources/UITestsFoundation/Screens/ReaderScreen.swift b/Modules/Sources/UITestsFoundation/Screens/ReaderScreen.swift index 0e2138428dcc..d37f96a24ccb 100644 --- a/Modules/Sources/UITestsFoundation/Screens/ReaderScreen.swift +++ b/Modules/Sources/UITestsFoundation/Screens/ReaderScreen.swift @@ -2,7 +2,6 @@ import ScreenObject import XCTest public class ReaderScreen: ScreenObject { - var readerNavigationMenuButton: XCUIElement { app.buttons["reader-navigation-button"] } var backButton: XCUIElement { app.buttons["Back"] } var dismissButton: XCUIElement { app.buttons["Dismiss"] } var firstPostLikeButton: XCUIElement { app.buttons["reader-like-button"].firstMatch } @@ -13,8 +12,6 @@ public class ReaderScreen: ScreenObject { var noResultsView: XCUIElement { app.staticTexts["no-results-label-stack-view"].firstMatch } var readerButton: XCUIElement { app.buttons["Reader"] } var readerTable: XCUIElement { app.tables["reader_table_view"] } - var moreButton: XCUIElement { app.buttons["More"] } - var savePostButton: XCUIElement { app.buttons["Save"] } var savedButton: XCUIElement { app.buttons["Saved"] } var tagCellButton: XCUIElement { app.cells["topics-card-cell-button"] } var visitButton: XCUIElement { app.buttons["Visit"] } @@ -32,13 +29,13 @@ public class ReaderScreen: ScreenObject { } public func openLastPostInSafari() throws -> ReaderScreen { - try getLastPost().buttons["More"].tap() - visitButton.tap() + try getLastPost().buttons["reader-more-button"].firstMatch.tap() + app.buttons["reader-view-post-in-safari"].firstMatch.tap() return self } public func openLastPostComments() throws -> CommentsScreen { - let commentButton = try getLastPost().buttons["Comment"] + let commentButton = try getLastPost().buttons["reader-comment-button"] guard commentButton.waitForIsHittable() else { throw UIElementNotFoundError(message: "ReaderScreen.Post: Comments button not loaded") } @@ -109,24 +106,7 @@ public class ReaderScreen: ScreenObject { // MARK: Stream switching actions - public enum ReaderStream: String { - case discover - case subscriptions - case saved - case liked - - var buttonIdentifier: String { - "Reader Navigation Menu Item, \(rawValue.capitalized)" - } - - func menuButton(_ app: XCUIApplication) -> XCUIElement { - if XCTestCase.isPad { - return app.staticTexts["reader_sidebar_\(rawValue)"].firstMatch - } else { - return app.buttons[buttonIdentifier].firstMatch - } - } - } + public typealias ReaderStream = ReaderMenuScreen.ReaderStream private func openNavigationMenu() { if XCTestCase.isPad { @@ -135,7 +115,7 @@ public class ReaderScreen: ScreenObject { app.buttons["ToggleSidebar"].tap() } } else { - readerNavigationMenuButton.tap() + app.navigationBars.firstMatch.buttons.element(boundBy: 0).tap() } } @@ -147,7 +127,7 @@ public class ReaderScreen: ScreenObject { } } - public func switchToStream(_ stream: ReaderStream) -> Self { + public func switchToStream(_ stream: ReaderStream) throws -> Self { openNavigationMenu() stream.menuButton(app).tap() closeNavigationMenu() @@ -173,9 +153,9 @@ public class ReaderScreen: ScreenObject { public func saveFirstPost() throws -> (ReaderScreen, String) { XCTAssertTrue(readerTable.isHittable) - let postLabel = readerTable.cells.firstMatch.label - moreButton.firstMatch.tap() - savePostButton.firstMatch.tap() + let cell = readerTable.cells.firstMatch + let postLabel = cell.label + cell.buttons["reader-bookmark-button"].firstMatch.tap() // An alert about saved post is displayed the first time a post is saved if let alert = try? FancyAlertComponent() { @@ -197,11 +177,9 @@ public class ReaderScreen: ScreenObject { return self } - public func verifyPostLikedOnFollowingTab(file: StaticString = #file, line: UInt = #line) -> Self { - XCTAssertTrue(readerTable.cells.firstMatch.waitForExistence(timeout: 3), file: file, line: line) - XCTAssertGreaterThan(readerTable.cells.count, 1, .postNotGreaterThanOneError, file: file, line: line) - XCTAssertTrue(firstPostLikeButton.label.hasPrefix(.postLiked), file: file, line: line) - + public func verifyFirstPostLiked(file: StaticString = #file, line: UInt = #line) -> Self { + let cell = readerTable.cells.firstMatch + XCTAssertEqual(cell.buttons["reader-like-button"].staticTexts.firstMatch.label, "35") return self } @@ -221,7 +199,7 @@ public class ReaderScreen: ScreenObject { public func verifyLikedPosts(state: String, file: StaticString = #file, line: UInt = #line) -> Self { if state == .withPosts { verifyNotEmptyPostList() - XCTAssertTrue(firstPostLikeButton.label.hasPrefix(.postLiked), file: file, line: line) + _ = verifyFirstPostLiked() } else if state == .withoutPosts { verifyEmptyPostList() } @@ -242,7 +220,6 @@ public class ReaderScreen: ScreenObject { private extension String { static let emptyListLabel = "Empty list" - static let postLiked = "Liked" static let postNotEqualOneError = "There should only be 1 post!" static let postNotEqualSavedPostError = "Post displayed does not match saved post!" static let postNotGreaterThanOneError = "There shouldn't only be 1 post!" diff --git a/WordPress/Classes/System/ReaderPresenter.swift b/WordPress/Classes/System/ReaderPresenter.swift index 68a7ebf01a9b..c0a99e8a4281 100644 --- a/WordPress/Classes/System/ReaderPresenter.swift +++ b/WordPress/Classes/System/ReaderPresenter.swift @@ -38,6 +38,7 @@ final class ReaderPresenter: NSObject, SplitViewDisplayable { // TODO: (reader) update to allow seamless transitions between split view and tabs @objc func prepareForTabBarPresentation() -> UINavigationController { sidebarViewModel.isCompact = true + sidebarViewModel.restoreSelection(defaultValue: nil) mainNavigationController.navigationBar.prefersLargeTitles = true mainNavigationController.viewControllers = [sidebar] sidebar.navigationItem.backButtonDisplayMode = .minimal diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift b/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift index 2297547322b7..654cae356312 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift @@ -96,11 +96,13 @@ struct ReaderPostMenu { private var viewPostInBrowser: UIAction? { guard let postURL = post.permaLink.flatMap(URL.init) else { return nil } - return UIAction(Strings.viewInBrowser, systemImage: "safari") { + let action = UIAction(Strings.viewInBrowser, systemImage: "safari") { let safariVC = SFSafariViewController(url: postURL) viewController?.present(safariVC, animated: true) track(.viewPostInBrowser) } + action.accessibilityIdentifier = "reader-view-post-in-safari" + return action } private var copyPostLink: UIAction? { diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift index 52e482bb5478..e54ad900af32 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewModel.swift @@ -10,6 +10,7 @@ final class ReaderSidebarViewModel: ObservableObject { private let tabItemsStore: ReaderMenuStoreProtocol private let contextManager: CoreDataStackSwift private var previousReloadTimestamp: Date? + private var isRestoringSelection = false @Published var isCompact = false @@ -19,11 +20,20 @@ final class ReaderSidebarViewModel: ObservableObject { contextManager: CoreDataStackSwift = ContextManager.shared) { self.tabItemsStore = menuStore self.contextManager = contextManager - let selection = UserDefaults.standard.readerSidebarSelection - self.selection = .main(selection ?? .recent) + self.restoreSelection(defaultValue: .main(.recent)) self.reloadMenuIfNeeded() } + func restoreSelection(defaultValue: ReaderSidebarItem?) { + isRestoringSelection = true // TODO: refactor this + defer { isRestoringSelection = false } + if let selection = UserDefaults.standard.readerSidebarSelection { + self.selection = .main(selection) + } else { + self.selection = defaultValue + } + } + func getTopic(for topicType: ReaderTopicType) -> ReaderAbstractTopic? { return try? ReaderAbstractTopic.lookupAllMenus(in: contextManager.mainContext).first { ReaderHelpers.topicType($0) == topicType @@ -42,7 +52,7 @@ final class ReaderSidebarViewModel: ObservableObject { } private func persistenSelection() { - if case .main(let screen)? = selection, + if !isRestoringSelection, case .main(let screen)? = selection, screen == .recent || screen == .discover { UserDefaults.standard.readerSidebarSelection = screen } @@ -107,15 +117,8 @@ enum ReaderStaticScreen: String, CaseIterable, Identifiable, Hashable { } } - // TODO: replace these values ones the sidebar gets integrated on iPhone var accessibilityIdentifier: String { - switch self { - case .recent: "reader_sidebar_subscriptions" - case .discover: "reader_sidebar_discover" - case .saved: "reader_sidebar_saved" - case .likes: "reader_sidebar_liked" - case .search: "reader_sidebar_search" - } + "reader_sidebar_\(rawValue)" } } diff --git a/WordPress/UITests/Tests/ReaderTests.swift b/WordPress/UITests/Tests/ReaderTests.swift index dd95314fbff3..5794d5584782 100644 --- a/WordPress/UITests/Tests/ReaderTests.swift +++ b/WordPress/UITests/Tests/ReaderTests.swift @@ -8,29 +8,37 @@ class ReaderTests: XCTestCase { try await WireMock.setUpScenario(scenario: "reader_subscriptions_flow") try await WireMock.setUpScenario(scenario: "reader_like_post_flow") - _ = try makeMainNavigationComponent() + try makeMainNavigationComponent() .goToReaderScreen() } + + func openStream(_ stream: ReaderMenuScreen.ReaderStream) throws -> ReaderScreen { + if XCTestCase.isPad { + return try ReaderScreen() + .switchToStream(stream) + } else { + // iPhone starts on the root screen before you make any selection + return try ReaderMenuScreen() + .open(stream) + } + } } class ReaderTests_01: ReaderTests { func testViewPost() throws { - try ReaderScreen() - .switchToStream(.subscriptions) + try openStream(.recent) .openLastPost() .verifyPostContentEquals(.expectedPostContent) } func testViewPostInSafari() throws { - try ReaderScreen() - .switchToStream(.subscriptions) + try openStream(.recent) .openLastPostInSafari() .verifyPostContentEquals(.expectedPostContent) } func testDiscover() throws { - try ReaderScreen() - .switchToStream(.discover) + try openStream(.discover) .selectTag() .verifyTagLoaded() .followTag() @@ -40,41 +48,33 @@ class ReaderTests_01: ReaderTests { class ReaderTests_02: ReaderTests { func testAddCommentToPost() throws { - try ReaderScreen() - .switchToStream(.subscriptions) + try openStream(.recent) .openLastPostComments() .verifyCommentsListEmpty() .replyToPost(.commentContent) .verifyCommentSent(.commentContent) } - func testInteractWithPost() throws { - try _testSavePost() - try _testLikePost() - } - - func _testSavePost() throws { + func testSavePost() throws { // Get saved post label - let (updatedReaderScreen, savedPostLabel) = try ReaderScreen() - .switchToStream(.saved) + let (updatedReaderScreen, savedPostLabel) = try openStream(.saved) .verifySavedPosts(state: .withoutPosts) - .switchToStream(.subscriptions) + .switchToStream(.recent) .saveFirstPost() // Open saved posts tab and validate that the correct saved post is displayed - updatedReaderScreen + try updatedReaderScreen .switchToStream(.saved) .verifySavedPosts(state: .withPosts, postLabel: savedPostLabel) } - func _testLikePost() throws { - try ReaderScreen() - .switchToStream(.liked) + func testLikePost() throws { + try openStream(.likes) .verifyLikedPosts(state: .withoutPosts) - .switchToStream(.subscriptions) + .switchToStream(.recent) .likeFirstPost() - .verifyPostLikedOnFollowingTab() - .switchToStream(.liked) + .verifyFirstPostLiked() + .switchToStream(.likes) .verifyLikedPosts(state: .withPosts) } } From 0335142911a630b5f87900091825bd30c3072824 Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 28 Oct 2024 10:23:12 -0400 Subject: [PATCH 52/55] Remove duplicated actions from ReaderPostMenu --- .../ViewRelated/Reader/ReaderPostMenu.swift | 59 +------------------ 1 file changed, 2 insertions(+), 57 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift b/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift index 654cae356312..bdcbf8629657 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderPostMenu.swift @@ -12,23 +12,15 @@ struct ReaderPostMenu { func makeMenu() -> [UIMenuElement] { return [ makePrimaryActions(), - makeSecondaryActions(), shouldShowReportOrBlockMenu ? makeBlockOrReportActions() : nil ].compactMap { $0 } } private func makePrimaryActions() -> UIMenu { - let menu = UIMenu(options: [.displayInline], children: [ - share, comment, like, bookmark, reblog - ].compactMap { $0 }) - menu.preferredElementSize = .medium - return menu - } - - private func makeSecondaryActions() -> UIMenu { UIMenu(options: [.displayInline], children: [ - viewPostInBrowser, + share, copyPostLink, + viewPostInBrowser, makeBlogMenu(), ].compactMap { $0 }) } @@ -59,41 +51,6 @@ struct ReaderPostMenu { } } - private var bookmark: UIAction { - let isBookmarked = post.isSavedForLater - return UIAction(isBookmarked ? Strings.bookmarked : Strings.bookmark, systemImage: isBookmarked ? "bookmark.fill" : "bookmark") { - guard let viewController else { return } - ReaderSaveForLaterAction().execute(with: post, origin: .otherStream, viewController: viewController) - track(isBookmarked ? .removeBookmark : .bookmark) - } - } - - private var reblog: UIAction { - UIAction(Strings.reblog, systemImage: "arrow.2.squarepath") { - guard let viewController else { return } - ReaderSaveForLaterAction().execute(with: post, origin: .otherStream, viewController: viewController) - track(.reblog) - } - } - - private var comment: UIAction? { - guard post.isCommentsEnabled else { return nil } - return UIAction(Strings.comment, systemImage: "message") { - guard let viewController else { return } - ReaderCommentAction().execute(post: post, origin: viewController, source: .postCard) - track(.comment) - } - } - - private var like: UIAction? { - guard post.isLikesEnabled else { return nil } - let isLiked = post.isLiked - return UIAction(isLiked ? Strings.liked : Strings.like, systemImage: isLiked ? "star.fill" : "star") { - ReaderLikeAction().execute(with: post) - track(isLiked ? .removeLike : .like) - } - } - private var viewPostInBrowser: UIAction? { guard let postURL = post.permaLink.flatMap(URL.init) else { return nil } let action = UIAction(Strings.viewInBrowser, systemImage: "safari") { @@ -220,12 +177,6 @@ private extension UIAction { private enum ReaderPostMenuAnalyticsButton: String { case share = "share" - case bookmark = "bookmark" - case removeBookmark = "remove_bookmark" - case like = "like" - case removeLike = "remove_like" - case comment = "comment" - case reblog = "reblog" case viewPostInBrowser = "view_in_browser" case copyPostLink = "copy_post_link" case goToBlog = "blog_open" @@ -241,12 +192,6 @@ private enum ReaderPostMenuAnalyticsButton: String { private enum Strings { static let share = NSLocalizedString("reader.postContextMenu.share", value: "Share", comment: "Context menu action") - static let bookmark = NSLocalizedString("reader.postContextMenu.bookmark", value: "Bookmark", comment: "Context menu action") - static let bookmarked = NSLocalizedString("reader.postContextMenu.bookmarked", value: "Bookmarked", comment: "Context menu action") - static let reblog = NSLocalizedString("reader.postContextMenu.reblog", value: "Reblog", comment: "Context menu action") - static let comment = NSLocalizedString("reader.postContextMenu.comment", value: "Comment", comment: "Context menu action") - static let like = NSLocalizedString("reader.postContextMenu.like", value: "Like", comment: "Context menu action") - static let liked = NSLocalizedString("reader.postContextMenu.liked", value: "Liked", comment: "Context menu action") static let viewInBrowser = NSLocalizedString("reader.postContextMenu.viewInBrowser", value: "View in Browser", comment: "Context menu action") static let copyLink = NSLocalizedString("reader.postContextMenu.copyLink", value: "Copy Link", comment: "Context menu action") static let blockOrReport = NSLocalizedString("reader.postContextMenu.blockOrReportMenu", value: "Block or Report", comment: "Context menu action") From 1dcdede4e59a051d7ef599dbb78dd97f80f952f7 Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 28 Oct 2024 11:23:25 -0400 Subject: [PATCH 53/55] Reimplement actionButtonPressed --- .../Classes/ViewRelated/Reader/ReaderStreamViewController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 8fdde8e44da4..42ddb2a70bef 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -1767,7 +1767,7 @@ extension ReaderStreamViewController: NoResultsViewControllerDelegate { } if ReaderHelpers.topicIsFollowing(topic) { - // TODO: (reader) reimplement + RootViewCoordinator.sharedPresenter.showReader(path: .discover) return } From 630721f400158dbb46404af84153003ce10c2f63 Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 28 Oct 2024 16:56:44 -0400 Subject: [PATCH 54/55] Load Reader lazily --- WordPress/Classes/System/ReaderPresenter.swift | 8 +++++--- .../ViewRelated/Reader/ReaderSidebarViewController.swift | 8 ++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/WordPress/Classes/System/ReaderPresenter.swift b/WordPress/Classes/System/ReaderPresenter.swift index c0a99e8a4281..bb865c953855 100644 --- a/WordPress/Classes/System/ReaderPresenter.swift +++ b/WordPress/Classes/System/ReaderPresenter.swift @@ -14,7 +14,7 @@ final class ReaderPresenter: NSObject, SplitViewDisplayable { var secondary: UINavigationController /// The navigation controller for the main content when shown using tabs. - private let mainNavigationController = UINavigationController() + private var mainNavigationController = UINavigationController() private var latestContentVC: UIViewController? private var viewContext: NSManagedObjectContext { @@ -37,12 +37,14 @@ final class ReaderPresenter: NSObject, SplitViewDisplayable { // TODO: (reader) update to allow seamless transitions between split view and tabs @objc func prepareForTabBarPresentation() -> UINavigationController { + sidebar.onViewDidLoad = { [weak self] in + self?.showInitialSelection() + } sidebarViewModel.isCompact = true sidebarViewModel.restoreSelection(defaultValue: nil) mainNavigationController.navigationBar.prefersLargeTitles = true - mainNavigationController.viewControllers = [sidebar] + mainNavigationController = UINavigationController(rootViewController: sidebar) // Loads sidebar lazily sidebar.navigationItem.backButtonDisplayMode = .minimal - showInitialSelection() return mainNavigationController } diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewController.swift index 508827c20bc1..f67e7ab00e7c 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderSidebarViewController.swift @@ -9,6 +9,8 @@ final class ReaderSidebarViewController: UIHostingController { private var viewContext: NSManagedObjectContext { ContextManager.shared.mainContext } var didAppear = false + var onViewDidLoad: (() -> Void)? + init(viewModel: ReaderSidebarViewModel) { self.viewModel = viewModel // - warning: The `managedObjectContext` has to be set here in order for @@ -25,6 +27,12 @@ final class ReaderSidebarViewController: UIHostingController { fatalError("init(coder:) has not been implemented") } + override func viewDidLoad() { + super.viewDidLoad() + + onViewDidLoad?() + } + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) From e67611af938c831e3b6ba19f784a8371b8f2870c Mon Sep 17 00:00:00 2001 From: kean Date: Wed, 30 Oct 2024 09:51:55 -0400 Subject: [PATCH 55/55] Fix tests --- .../WordPressTest/ReaderDetailCoordinatorTests.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/WordPress/WordPressTest/ReaderDetailCoordinatorTests.swift b/WordPress/WordPressTest/ReaderDetailCoordinatorTests.swift index 9c6951fafe03..f9c71a0debb1 100644 --- a/WordPress/WordPressTest/ReaderDetailCoordinatorTests.swift +++ b/WordPress/WordPressTest/ReaderDetailCoordinatorTests.swift @@ -137,13 +137,13 @@ class ReaderDetailCoordinatorTests: CoreDataTestCase { coordinator.share(fromView: button) - expect(postSharingControllerMock.didCallShareReaderPostWith).to(equal(post)) - if case let .view(view) = postSharingControllerMock.didCallShareReaderPostWithView { - expect(view).to(equal(button)) + XCTAssertEqual(postSharingControllerMock.didCallShareReaderPostWith, post) + if let view = postSharingControllerMock.didCallShareReaderPostWithView as? UIView { + XCTAssertEqual(view, button) } else { - fail("`postSharingControllerMock.didCallShareReaderPostWithView` should equal .view(button)") + XCTFail("`postSharingControllerMock.didCallShareReaderPostWithView` should equal .view(button)") } - expect(postSharingControllerMock.didCallShareReaderPostWithViewController).to(equal(viewMock)) + XCTAssertEqual(postSharingControllerMock.didCallShareReaderPostWithViewController, viewMock) } /// Present a site preview in the current view stack