diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderAnnouncementHeaderView.swift b/WordPress/Classes/ViewRelated/Reader/ReaderAnnouncementHeaderView.swift deleted file mode 100644 index 5fa993b3732d..000000000000 --- a/WordPress/Classes/ViewRelated/Reader/ReaderAnnouncementHeaderView.swift +++ /dev/null @@ -1,191 +0,0 @@ -import SwiftUI -import DesignSystem - -class ReaderAnnouncementHeaderView: UITableViewHeaderFooterView, ReaderStreamHeader { - - weak var delegate: ReaderStreamHeaderDelegate? - - private let header: ReaderAnnouncementHeader - - init(doneButtonTapped: (() -> Void)? = nil) { - self.header = ReaderAnnouncementHeader { [doneButtonTapped] in - doneButtonTapped?() - } - - super.init(reuseIdentifier: ReaderSiteHeaderView.classNameWithoutNamespaces()) - setupViews() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func setupViews() { - let view = UIView.embedSwiftUIView(self.header) - addSubview(view) - NSLayoutConstraint.activate([ - view.topAnchor.constraint(equalTo: topAnchor), - view.bottomAnchor.constraint(equalTo: bottomAnchor), - view.leadingAnchor.constraint(equalTo: readableContentGuide.leadingAnchor), - view.trailingAnchor.constraint(equalTo: readableContentGuide.trailingAnchor) - ]) - - applyBackgroundColor(Constants.backgroundColor) - addBottomBorder(withColor: .separator) - } - - private func applyBackgroundColor(_ color: UIColor) { - let backgroundView = UIView(frame: bounds) - backgroundView.backgroundColor = color - self.backgroundView = backgroundView - } - - // MARK: ReaderStreamHeader - - func enableLoggedInFeatures(_ enable: Bool) { - // no-op - } - - func configureHeader(_ topic: ReaderAbstractTopic) { - // no-op; this header doesn't rely on the supplied topic. - } - - fileprivate struct Constants { - static let backgroundColor = UIColor.systemBackground - } -} - -// TODO: ReaderAnnouncementItem / Models - -// MARK: - SwiftUI View - -fileprivate struct ReaderAnnouncementHeader: View { - - // Determines what features should be listed (and its order). - let entries: [Entry] = [.tagsStream, .readingPreferences] - - var onButtonTap: (() -> Void)? = nil - - var body: some View { - VStack(alignment: .leading, spacing: .DS.Padding.double) { - Text(Strings.title) - .font(.callout) - .fontWeight(.semibold) - - ForEach(entries, id: \.title) { entry in - announcementEntryView(entry) - } - - DSButton(title: Strings.buttonTitle, - style: DSButtonStyle(emphasis: .primary, size: .large)) { - onButtonTap?() - } - } - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) - .padding(.vertical, .DS.Padding.medium) - .background(Color(ReaderAnnouncementHeaderView.Constants.backgroundColor)) - } - - // MARK: Constants - - private struct Strings { - static let title = NSLocalizedString( - "reader.announcement.title", - value: "New in Reader", - comment: "Title text for the announcement card component in the Reader." - ) - static let buttonTitle = NSLocalizedString( - "reader.announcement.button", - value: "Done", - comment: "Text for a button that dismisses the announcement card in the Reader." - ) - } -} - -// MARK: - Announcement Item - -fileprivate extension ReaderAnnouncementHeader { - - struct Entry { - static let tagsStream = Entry( - imageName: "reader-menu-tags", - title: NSLocalizedString( - "reader.announcement.entry.tagsStream.title", - value: "Tags Stream", - comment: "The title part of the feature announcement content for Tags Stream." - ), - description: NSLocalizedString( - "reader.announcement.entry.tagsStream.description", - value: "Tap the dropdown at the top and select Tags to access streams from your followed tags.", - comment: "The description part of the feature announcement content for Tags Stream." - ) - ) - - static let readingPreferences = Entry( - imageName: "reader-reading-preferences", - title: NSLocalizedString( - "reader.announcement.entry.readingPreferences.title", - value: "Reading Preferences", - comment: "The title part of the feature announcement content for Reading Preferences." - ), - description: NSLocalizedString( - "reader.announcement.entry.readingPreferences.description", - value: "Choose colors and fonts that suit you. When you’re reading a post tap the AA icon at the top of the screen.", - comment: "The description part of the feature announcement content for Reading Preferences." - ) - ) - - let imageName: String - let title: String - let description: String - } - - @ViewBuilder - func announcementEntryView(_ entry: Entry) -> some View { - HStack(spacing: .DS.Padding.double) { - Image(entry.imageName, bundle: nil) - .renderingMode(.template) - .resizable() - .frame(width: 24, height: 24) - .padding(12) - .foregroundColor(Color(.systemBackground)) - .background(.primary) - .clipShape(Circle()) - .accessibilityHidden(true) - - VStack(alignment: .leading, spacing: 1) { - Text(entry.title) - .font(.callout) - .fontWeight(.semibold) - Text(entry.description) - .font(.footnote) - .foregroundStyle(.secondary) - } - } - } -} - -// MARK: - Reader Announcement Coordinator - -class ReaderAnnouncementCoordinator { - - let repository: UserPersistentRepository = UserPersistentStoreFactory.instance() - - var canShowAnnouncement: Bool { - false - // return !isDismissed && RemoteFeatureFlag.readerAnnouncementCard.enabled() - } - - var isDismissed: Bool { - get { - repository.bool(forKey: Constants.key) - } - set { - repository.set(newValue, forKey: Constants.key) - } - } - - private struct Constants { - static let key = "readerAnnouncementCardDismissedKey" - } -} diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift index c6286706549d..e76c03cb003b 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController+Helper.swift @@ -25,10 +25,7 @@ extension ReaderStreamViewController { configure(header, topic: topic, isLoggedIn: isLoggedIn, delegate: self) return header } - - // The announcement header should have the lowest display priority. - // Only return the announcement when there's no other header. - return makeAnnouncementHeader() + return nil } func configure(_ header: ReaderHeader?, topic: ReaderAbstractTopic, isLoggedIn: Bool, delegate: ReaderStreamHeaderDelegate) { @@ -169,56 +166,6 @@ extension ReaderStreamViewController { } -// MARK: - Reader Announcement Header - -extension ReaderStreamViewController { - /// Returns a header view for Reader-related announcements. - /// Note that the announcement can also be shown on topicless streams (e.g., Saved, Tags). - /// - /// - Returns: A configured UIView, or nil if the conditions are not met. - func makeAnnouncementHeader() -> UIView? { - // don't show the announcement while searching. - if let readerTopic, - ReaderHelpers.isTopicSearchTopic(readerTopic) { - return nil - } - - guard readerAnnouncementCoordinator.canShowAnnouncement, - tableView.tableHeaderView == nil, - !isContentFiltered, - !contentIsEmpty() else { - return nil - } - - return ReaderAnnouncementHeaderView(doneButtonTapped: { [weak self] in - // Set the card as dismissed. - self?.readerAnnouncementCoordinator.isDismissed = true - WPAnalytics.track(.readerAnnouncementDismissed) - - // Animate the header removal so it feels less jarring. - UIView.animate(withDuration: 0.3) { - self?.tableView.tableHeaderView?.layer.opacity = 0.0 - } completion: { _ in - self?.tableView.performBatchUpdates({ - self?.tableView.tableHeaderView = nil - }) - } - }) - } - - // The header may be configured when the content is still empty (i.e., Discover stream). - // This method is added to provide a way to inject the announcement card outside of - // `configureStreamHeader()`. For example, after syncing completes. - func showAnnouncementHeaderIfNeeded(completion: (() -> Void)? = nil) { - guard let headerView = makeAnnouncementHeader() else { - return - } - - tableView.tableHeaderView = headerView - completion?() - } -} - // MARK: - Tracks extension ReaderStreamViewController { func trackSavedListAccessed() { diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift index 19c17a80c290..52366a803b9b 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderStreamViewController.swift @@ -218,10 +218,6 @@ import AutomatticTracks // 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() - /// Controls whether the Reader announcement card can be displayed. - /// - let readerAnnouncementCoordinator = ReaderAnnouncementCoordinator() - lazy var selectInterestsViewController: ReaderSelectInterestsViewController = { let title = NSLocalizedString( "reader.select.tags.title", @@ -480,8 +476,6 @@ import AutomatticTracks } /// Fetches a tag topic for the value of the `tagSlug` property - /// - // TODO: - READERNAV - Remove this when the new reader is released private func fetchTagTopic() { if isViewLoaded { displayLoadingStream() @@ -1051,14 +1045,6 @@ import AutomatticTracks } strongSelf.updateLastSyncedForTopic(objectID) } - - // Show the announcement card if possible. - // Context: `configureStreamHeader()` may be called while the content is still empty. - // Calling it here manually ensures that we know whether the content is actually empty or not. - self?.showAnnouncementHeaderIfNeeded { [weak self] in - self?.refreshTableViewHeaderLayout() - } - success?(hasMore) } } diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 833f231cc097..dd6616dbeea4 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -5675,8 +5675,6 @@ FE50965A2A17A69F00DDD071 /* TwitterDeprecationTableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE5096582A17A69F00DDD071 /* TwitterDeprecationTableFooterView.swift */; }; FE50965C2A20D0F300DDD071 /* CommentTableHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE50965B2A20D0F300DDD071 /* CommentTableHeaderView.swift */; }; FE50965D2A20D0F300DDD071 /* CommentTableHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE50965B2A20D0F300DDD071 /* CommentTableHeaderView.swift */; }; - FE59025F2BF2558300115D08 /* ReaderAnnouncementHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE59025E2BF2558300115D08 /* ReaderAnnouncementHeaderView.swift */; }; - FE5902602BF3795600115D08 /* ReaderAnnouncementHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE59025E2BF2558300115D08 /* ReaderAnnouncementHeaderView.swift */; }; FE6AFE432B18EDF200F76520 /* BloganuaryTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE6AFE422B18EDF200F76520 /* BloganuaryTracker.swift */; }; FE6AFE442B18EDF200F76520 /* BloganuaryTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE6AFE422B18EDF200F76520 /* BloganuaryTracker.swift */; }; FE6AFE472B1A351F00F76520 /* SOTWCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE6AFE462B1A351F00F76520 /* SOTWCardView.swift */; }; @@ -9778,7 +9776,6 @@ FE5096572A13D5BA00DDD071 /* WordPress 149.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 149.xcdatamodel"; sourceTree = ""; }; FE5096582A17A69F00DDD071 /* TwitterDeprecationTableFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwitterDeprecationTableFooterView.swift; sourceTree = ""; }; FE50965B2A20D0F300DDD071 /* CommentTableHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentTableHeaderView.swift; sourceTree = ""; }; - FE59025E2BF2558300115D08 /* ReaderAnnouncementHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderAnnouncementHeaderView.swift; sourceTree = ""; }; FE59DA9527D1FD0700624D26 /* WordPress 138.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 138.xcdatamodel"; sourceTree = ""; }; FE5F52D82AF9461200371A3A /* WordPress 153.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 153.xcdatamodel"; sourceTree = ""; }; FE6AFE422B18EDF200F76520 /* BloganuaryTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloganuaryTracker.swift; sourceTree = ""; }; @@ -17870,7 +17867,6 @@ E6D2E16B1B8B423B0000ED14 /* ReaderStreamHeader.swift */, E6D2E1661B8AAD8C0000ED14 /* ReaderTagStreamHeader.swift */, E6D2E1601B8AA4410000ED14 /* ReaderTagStreamHeader.xib */, - FE59025E2BF2558300115D08 /* ReaderAnnouncementHeaderView.swift */, ); name = Headers; sourceTree = ""; @@ -22554,7 +22550,6 @@ 8BD66ED42787530C00CCD95A /* PostsCardViewModel.swift in Sources */, 7E58879A20FE8D9300DB6F80 /* AppEnvironment.swift in Sources */, 591232691CCEAA5100B86207 /* AbstractPostListViewController.swift in Sources */, - FE5902602BF3795600115D08 /* ReaderAnnouncementHeaderView.swift in Sources */, E14200781C117A2E00B3B115 /* ManagedAccountSettings.swift in Sources */, 0C23F3362AC4AD3400EE6117 /* SiteMediaSelectionTitleView.swift in Sources */, 401AC82722DD2387006D78D4 /* Blog+Plans.swift in Sources */, @@ -25188,7 +25183,6 @@ FABB231F2602FC2C00C8785C /* SignupUsernameTableViewController.swift in Sources */, FABB23202602FC2C00C8785C /* Blog+Editor.swift in Sources */, FABB23212602FC2C00C8785C /* ReaderCardService.swift in Sources */, - FE59025F2BF2558300115D08 /* ReaderAnnouncementHeaderView.swift in Sources */, FABB23222602FC2C00C8785C /* UITableViewCell+Stats.swift in Sources */, FABB23232602FC2C00C8785C /* Delay.swift in Sources */, FABB23242602FC2C00C8785C /* Pageable.swift in Sources */,