From ae907e41a3ab80d57d07a13cb9a45222189ce866 Mon Sep 17 00:00:00 2001 From: amy-at-kickstarter <146007185+amy-at-kickstarter@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:58:43 -0500 Subject: [PATCH] MBL-1029: Refresh Discover page after a user is blocked (#1885) * MBL-1029: Refresh Discover page after a user is blocked * Add test * Add .ksr_blockedUser notification to blocking call in ProjectPageViewModel --- .../DiscoveryPageViewController.swift | 6 +++++ Library/Notifications.swift | 2 ++ .../ViewModels/CommentRepliesViewModel.swift | 5 ++++ Library/ViewModels/CommentsViewModel.swift | 5 ++++ .../ViewModels/DiscoveryPageViewModel.swift | 11 +++++++- .../DiscoveryPageViewModelTests.swift | 25 +++++++++++++++++++ Library/ViewModels/MessagesViewModel.swift | 6 +++++ Library/ViewModels/ProjectPageViewModel.swift | 8 +++++- 8 files changed, 66 insertions(+), 2 deletions(-) diff --git a/Kickstarter-iOS/Features/Discovery/Controller/DiscoveryPageViewController.swift b/Kickstarter-iOS/Features/Discovery/Controller/DiscoveryPageViewController.swift index a0156b0084..5e6f164fbf 100644 --- a/Kickstarter-iOS/Features/Discovery/Controller/DiscoveryPageViewController.swift +++ b/Kickstarter-iOS/Features/Discovery/Controller/DiscoveryPageViewController.swift @@ -18,6 +18,7 @@ internal final class DiscoveryPageViewController: UITableViewController { private var configUpdatedObserver: Any? private var currentEnvironmentChangedObserver: Any? + private var blockedUserObserver: Any? fileprivate let dataSource = DiscoveryProjectsDataSource() public weak var delegate: DiscoveryPageViewControllerDelegate? fileprivate var emptyStatesController: EmptyStatesViewController? @@ -77,6 +78,11 @@ internal final class DiscoveryPageViewController: UITableViewController { self?.viewModel.inputs.configUpdated(config: AppEnvironment.current.config) }) + self.blockedUserObserver = NotificationCenter.default + .addObserver(forName: .ksr_blockedUser, object: nil, queue: nil, using: { [weak self] _ in + self?.viewModel.inputs.blockedUser() + }) + let emptyVC = EmptyStatesViewController.configuredWith(emptyState: nil) self.emptyStatesController = emptyVC emptyVC.delegate = self diff --git a/Library/Notifications.swift b/Library/Notifications.swift index 7071fce2c1..1590d59529 100644 --- a/Library/Notifications.swift +++ b/Library/Notifications.swift @@ -17,6 +17,7 @@ public enum CurrentUserNotifications { public static let sessionStarted = "CurrentUserNotifications.sessionStarted" public static let showNotificationsDialog = "CurrentUserNotifications.showNotificationsDialog" public static let userUpdated = "CurrentUserNotifications.userUpdated" + public static let blockedUser = "CurrentUserNotifications.blockedUser" } public enum AppStateNotifications { @@ -61,4 +62,5 @@ extension Notification.Name { CurrentUserNotifications.localePreferencesChanged ) public static let ksr_userUpdated = Notification.Name(rawValue: CurrentUserNotifications.userUpdated) + public static let ksr_blockedUser = Notification.Name(rawValue: CurrentUserNotifications.blockedUser) } diff --git a/Library/ViewModels/CommentRepliesViewModel.swift b/Library/ViewModels/CommentRepliesViewModel.swift index a1fb211302..ffe4c96860 100644 --- a/Library/ViewModels/CommentRepliesViewModel.swift +++ b/Library/ViewModels/CommentRepliesViewModel.swift @@ -250,6 +250,11 @@ public final class CommentRepliesViewModel: CommentRepliesViewModelType, // TODO: Call blocking GraphQL mutation self.userBlocked = self.blockUserProperty.signal.map { true } + + self.userBlocked.observeValues { didBlock in + guard didBlock == true else { return } + NotificationCenter.default.post(.init(name: .ksr_blockedUser)) + } } private let blockUserProperty = MutableProperty(()) diff --git a/Library/ViewModels/CommentsViewModel.swift b/Library/ViewModels/CommentsViewModel.swift index 311143b939..abc0e1dd7d 100644 --- a/Library/ViewModels/CommentsViewModel.swift +++ b/Library/ViewModels/CommentsViewModel.swift @@ -359,6 +359,11 @@ public final class CommentsViewModel: CommentsViewModelType, // TODO: Call blocking GraphQL mutation self.userBlocked = self.blockUserProperty.signal.map { true } + + self.userBlocked.observeValues { didBlock in + guard didBlock == true else { return } + NotificationCenter.default.post(.init(name: .ksr_blockedUser)) + } } // Properties to assist with injecting these values into the existing data streams. diff --git a/Library/ViewModels/DiscoveryPageViewModel.swift b/Library/ViewModels/DiscoveryPageViewModel.swift index 1441d1bbce..4b2496a661 100644 --- a/Library/ViewModels/DiscoveryPageViewModel.swift +++ b/Library/ViewModels/DiscoveryPageViewModel.swift @@ -14,6 +14,9 @@ public protocol DiscoveryPageViewModelInputs { /// Call when the current environment has changed func currentEnvironmentChanged(environment: EnvironmentType) + /// Call when the logged in user has blocked another user + func blockedUser() + /// Call when onboarding has been completed func onboardingCompleted() @@ -174,7 +177,8 @@ public final class DiscoveryPageViewModel: DiscoveryPageViewModelType, Discovery let requestFirstPageWith = Signal.merge( firstPageParams, firstPageParams.takeWhen(environmentChanged), - firstPageParams.takeWhen(self.pulledToRefreshProperty.signal) + firstPageParams.takeWhen(self.pulledToRefreshProperty.signal), + firstPageParams.takeWhen(self.blockedUserProperty.signal) ) let paginatedProjects: Signal<[Project], Never> @@ -378,6 +382,11 @@ public final class DiscoveryPageViewModel: DiscoveryPageViewModelType, Discovery self.currentEnvironmentChangedProperty.value = environment } + fileprivate let blockedUserProperty = MutableProperty(()) + public func blockedUser() { + self.blockedUserProperty.value = () + } + fileprivate let onboardingCompletedProperty = MutableProperty(()) public func onboardingCompleted() { self.onboardingCompletedProperty.value = () diff --git a/Library/ViewModels/DiscoveryPageViewModelTests.swift b/Library/ViewModels/DiscoveryPageViewModelTests.swift index ceaa78a51e..20af4dbc70 100644 --- a/Library/ViewModels/DiscoveryPageViewModelTests.swift +++ b/Library/ViewModels/DiscoveryPageViewModelTests.swift @@ -1175,4 +1175,29 @@ internal final class DiscoveryPageViewModelTests: TestCase { XCTAssertEqual("ending_soon", segmentClientProps?["discover_sort"] as? String) } + + func testBlockedUserNotification_RefreshesProjects() { + let playlist = (0...10).map { idx in .template |> Project.lens.id .~ (idx + 42) } + let projectEnv = .template + |> DiscoveryEnvelope.lens.projects .~ playlist + + withEnvironment(apiService: MockService(fetchDiscoveryResponse: projectEnv)) { + self.vm.inputs.configureWith(sort: .magic) + self.vm.inputs.viewWillAppear() + self.vm.inputs.viewDidAppear() + self.vm.inputs.selectedFilter(.defaults) + + self.projectsAreLoading.assertValueCount(1) + + self.scheduler.advance() + + self.projectsAreLoading.assertValueCount(2) + + self.vm.inputs.blockedUser() + + self.scheduler.advance() + + self.projectsAreLoading.assertValueCount(4) + } + } } diff --git a/Library/ViewModels/MessagesViewModel.swift b/Library/ViewModels/MessagesViewModel.swift index d01990af3e..5d91374f26 100644 --- a/Library/ViewModels/MessagesViewModel.swift +++ b/Library/ViewModels/MessagesViewModel.swift @@ -1,3 +1,4 @@ +import Foundation import KsApi import Prelude import ReactiveSwift @@ -191,6 +192,11 @@ public final class MessagesViewModel: MessagesViewModelType, MessagesViewModelIn // TODO: Call blocking GraphQL mutation self.userBlocked = self.blockUserProperty.signal.map { true } + + self.userBlocked.observeValues { didBlock in + guard didBlock == true else { return } + NotificationCenter.default.post(.init(name: .ksr_blockedUser)) + } } private let backingInfoPressedProperty = MutableProperty(()) diff --git a/Library/ViewModels/ProjectPageViewModel.swift b/Library/ViewModels/ProjectPageViewModel.swift index 31cd1ab772..779f20a1ca 100644 --- a/Library/ViewModels/ProjectPageViewModel.swift +++ b/Library/ViewModels/ProjectPageViewModel.swift @@ -502,7 +502,13 @@ public final class ProjectPageViewModel: ProjectPageViewModelType, ProjectPageVi self.goToURL = self.didSelectCampaignImageLinkProperty.signal.skipNil() - self.userBlocked = self.blockUserProperty.signal.map { false } + // TODO: Call blocking GraphQL mutation + self.userBlocked = self.blockUserProperty.signal.map { true } + + self.userBlocked.observeValues { didBlock in + guard didBlock == true else { return } + NotificationCenter.default.post(.init(name: .ksr_blockedUser)) + } } fileprivate let askAQuestionCellTappedProperty = MutableProperty(())