From 39ae68c3dcd215f6dbbe294de9b3b007375cf3cc Mon Sep 17 00:00:00 2001 From: Dominik Kapusta Date: Thu, 10 Oct 2024 23:04:09 +0200 Subject: [PATCH] Refactor Core Data usage in RemoteMessagingStore (#3381) Task/Issue URL: https://app.asana.com/0/1201048563534612/1208493869353425/f Description: This change updates RMF client to use new async API from BSK's RemoteMessagingStore. --- DuckDuckGo.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 4 ++-- .../Model/RemoteMessageViewModel.swift | 18 +++++++++--------- DuckDuckGo/HomePage/View/HomePageView.swift | 2 +- .../HomePage/View/RemoteMessageView.swift | 10 ++++++++-- DuckDuckGo/Menus/MainMenuActions.swift | 4 +++- .../ActiveRemoteMessageModel.swift | 18 +++++++++++------- .../DataBrokerProtection/Package.swift | 2 +- .../NetworkProtectionMac/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- .../ActiveRemoteMessageModelTests.swift | 8 ++++---- 11 files changed, 42 insertions(+), 30 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index b45683f7fc..1d9de0b0aa 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -14288,7 +14288,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 198.4.0; + version = 199.0.0; }; }; 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index c95d9e4938..82d9c4dbfc 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "c642e92389688016e2dad549f6d6e7c4cd1642d3", - "version" : "198.4.0" + "revision" : "ec46d991838527dd8c7041a3673428c0e18e0fdc", + "version" : "199.0.0" } }, { diff --git a/DuckDuckGo/HomePage/Model/RemoteMessageViewModel.swift b/DuckDuckGo/HomePage/Model/RemoteMessageViewModel.swift index fb74d8f1aa..a7940cb5b9 100644 --- a/DuckDuckGo/HomePage/Model/RemoteMessageViewModel.swift +++ b/DuckDuckGo/HomePage/Model/RemoteMessageViewModel.swift @@ -69,32 +69,32 @@ struct RemoteMessageViewModel { } } - let onDidClose: (ButtonAction?) -> Void + let onDidClose: (ButtonAction?) async -> Void let onDidAppear: () -> Void let onDidDisappear: () -> Void let openURLHandler: (URL) -> Void func mapActionToViewModel(remoteAction: RemoteAction, buttonAction: RemoteMessageViewModel.ButtonAction, - onDidClose: @escaping (RemoteMessageViewModel.ButtonAction?) -> Void) -> () -> Void { + onDidClose: @escaping (RemoteMessageViewModel.ButtonAction?) async -> Void) -> () async -> Void { switch remoteAction { case .url(let value), .share(let value, _), .survey(let value): - return { + return { @MainActor in if let url = URL.makeURL(from: value) { openURLHandler(url) } - onDidClose(buttonAction) + await onDidClose(buttonAction) } case .appStore: - return { + return { @MainActor in let url = URL(string: "https://apps.apple.com/app/duckduckgo-privacy-browser/id663592361")! openURLHandler(url) - onDidClose(buttonAction) + await onDidClose(buttonAction) } case .dismiss: - return { - onDidClose(buttonAction) + return { @MainActor in + await onDidClose(buttonAction) } } } @@ -108,7 +108,7 @@ struct RemoteMessageButtonViewModel { let title: String var actionStyle: ActionStyle = .default - let action: () -> Void + let action: () async -> Void } extension RemoteAction { diff --git a/DuckDuckGo/HomePage/View/HomePageView.swift b/DuckDuckGo/HomePage/View/HomePageView.swift index 9abdc56ca9..234fef9112 100644 --- a/DuckDuckGo/HomePage/View/HomePageView.swift +++ b/DuckDuckGo/HomePage/View/HomePageView.swift @@ -143,7 +143,7 @@ extension HomePage.Views { messageId: remoteMessage.id, modelType: modelType, onDidClose: { action in - activeRemoteMessageModel.dismissRemoteMessage(with: action) + await activeRemoteMessageModel.dismissRemoteMessage(with: action) }, onDidAppear: { activeRemoteMessageModel.isViewOnScreen = true diff --git a/DuckDuckGo/HomePage/View/RemoteMessageView.swift b/DuckDuckGo/HomePage/View/RemoteMessageView.swift index 84fe0e2e61..5367283b8e 100644 --- a/DuckDuckGo/HomePage/View/RemoteMessageView.swift +++ b/DuckDuckGo/HomePage/View/RemoteMessageView.swift @@ -86,7 +86,9 @@ struct RemoteMessageView: View { private var closeButton: some View { HomePage.Views.CloseButton(icon: .close, size: 16) { - viewModel.onDidClose(.close) + Task { + await viewModel.onDidClose(.close) + } } .visibility(isHovering ? .visible : .invisible) .padding(6) @@ -159,7 +161,11 @@ extension RemoteMessageButtonViewModel { } var standardButton: some View { - Button(action: action) { + Button { + Task { @MainActor in + await action() + } + } label: { Text(title) } } diff --git a/DuckDuckGo/Menus/MainMenuActions.swift b/DuckDuckGo/Menus/MainMenuActions.swift index 6ab3b79972..1ee24f2f43 100644 --- a/DuckDuckGo/Menus/MainMenuActions.swift +++ b/DuckDuckGo/Menus/MainMenuActions.swift @@ -329,7 +329,9 @@ extension AppDelegate { } @objc func resetRemoteMessages(_ sender: Any?) { - remoteMessagingClient.store?.resetRemoteMessages() + Task { + await remoteMessagingClient.store?.resetRemoteMessages() + } } @objc func resetNewTabPageCustomization(_ sender: Any?) { diff --git a/DuckDuckGo/RemoteMessaging/ActiveRemoteMessageModel.swift b/DuckDuckGo/RemoteMessaging/ActiveRemoteMessageModel.swift index 854d989b07..757c209c62 100644 --- a/DuckDuckGo/RemoteMessaging/ActiveRemoteMessageModel.swift +++ b/DuckDuckGo/RemoteMessaging/ActiveRemoteMessageModel.swift @@ -86,7 +86,10 @@ final class ActiveRemoteMessageModel: ObservableObject { } .store(in: &cancellables) - let remoteMessagePublisher = $remoteMessage.compactMap({ $0 }).asVoid() + let remoteMessagePublisher = $remoteMessage + .compactMap({ $0 }) + .filter { [weak self] _ in self?.isViewOnScreen == true } + .asVoid() let isViewOnScreenPublisher = $isViewOnScreen.removeDuplicates().filter({ $0 }).asVoid() Publishers.Merge(remoteMessagePublisher, isViewOnScreenPublisher) .receive(on: DispatchQueue.main) @@ -94,8 +97,8 @@ final class ActiveRemoteMessageModel: ObservableObject { guard let self else { return } - if isViewOnScreen { - markRemoteMessageAsShown() + Task { + await self.markRemoteMessageAsShown() } } .store(in: &cancellables) @@ -103,12 +106,13 @@ final class ActiveRemoteMessageModel: ObservableObject { updateRemoteMessage() } - func dismissRemoteMessage(with action: RemoteMessageViewModel.ButtonAction?) { + @MainActor + func dismissRemoteMessage(with action: RemoteMessageViewModel.ButtonAction?) async { guard let remoteMessage else { return } - store()?.dismissRemoteMessage(withID: remoteMessage.id) + await store()?.dismissRemoteMessage(withID: remoteMessage.id) self.remoteMessage = nil let pixel: GeneralPixel? = { @@ -134,7 +138,7 @@ final class ActiveRemoteMessageModel: ObservableObject { } } - func markRemoteMessageAsShown() { + func markRemoteMessageAsShown() async { guard let remoteMessage, let store = store() else { return } @@ -147,7 +151,7 @@ final class ActiveRemoteMessageModel: ObservableObject { if remoteMessage.isMetricsEnabled { PixelKit.fire(GeneralPixel.remoteMessageShownUnique, withAdditionalParameters: ["message": remoteMessage.id]) } - store.updateRemoteMessage(withID: remoteMessage.id, asShown: true) + await store.updateRemoteMessage(withID: remoteMessage.id, asShown: true) } } diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index a3bf8dbd3c..941d65e0ca 100644 --- a/LocalPackages/DataBrokerProtection/Package.swift +++ b/LocalPackages/DataBrokerProtection/Package.swift @@ -29,7 +29,7 @@ let package = Package( targets: ["DataBrokerProtection"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "198.4.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "199.0.0"), .package(path: "../SwiftUIExtensions"), .package(path: "../XPCHelper"), ], diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index 3ec99f8d5e..ad8504daf5 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -32,7 +32,7 @@ let package = Package( .library(name: "VPNAppLauncher", targets: ["VPNAppLauncher"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "198.4.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "199.0.0"), .package(url: "https://github.com/airbnb/lottie-spm", exact: "4.4.3"), .package(path: "../AppLauncher"), .package(path: "../UDSHelper"), diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 941e451e46..42b328c5da 100644 --- a/LocalPackages/SubscriptionUI/Package.swift +++ b/LocalPackages/SubscriptionUI/Package.swift @@ -12,7 +12,7 @@ let package = Package( targets: ["SubscriptionUI"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "198.4.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "199.0.0"), .package(path: "../SwiftUIExtensions") ], targets: [ diff --git a/UnitTests/RemoteMessaging/ActiveRemoteMessageModelTests.swift b/UnitTests/RemoteMessaging/ActiveRemoteMessageModelTests.swift index 05d7194545..44631d4a62 100644 --- a/UnitTests/RemoteMessaging/ActiveRemoteMessageModelTests.swift +++ b/UnitTests/RemoteMessaging/ActiveRemoteMessageModelTests.swift @@ -55,18 +55,18 @@ final class ActiveRemoteMessageModelTests: XCTestCase { XCTAssertEqual(model.remoteMessage, message) } - func testWhenMessageIsDismissedThenItIsClearedFromModel() throws { + func testWhenMessageIsDismissedThenItIsClearedFromModel() async throws { store.scheduledRemoteMessage = message model = ActiveRemoteMessageModel( remoteMessagingStore: self.store, remoteMessagingAvailabilityProvider: MockRemoteMessagingAvailabilityProvider() ) - model.dismissRemoteMessage(with: .close) + await model.dismissRemoteMessage(with: .close) XCTAssertNil(model.remoteMessage) } - func testWhenMessageIsMarkedAsShownThenShownFlagIsSavedInStore() throws { + func testWhenMessageIsMarkedAsShownThenShownFlagIsSavedInStore() async throws { store.scheduledRemoteMessage = message model = ActiveRemoteMessageModel( remoteMessagingStore: self.store, @@ -74,7 +74,7 @@ final class ActiveRemoteMessageModelTests: XCTestCase { ) XCTAssertFalse(store.hasShownRemoteMessage(withID: message.id)) - model.markRemoteMessageAsShown() + await model.markRemoteMessageAsShown() XCTAssertTrue(store.hasShownRemoteMessage(withID: message.id)) } }