diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 0755759da6..9f124bba37 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -7969,7 +7969,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProvider.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -8006,7 +8006,7 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -8098,7 +8098,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -8126,7 +8126,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -8276,7 +8276,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -8302,7 +8302,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGo.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; INFOPLIST_FILE = DuckDuckGo/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -8372,7 +8372,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -8407,7 +8407,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -8441,7 +8441,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -8472,7 +8472,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -8787,7 +8787,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -8819,7 +8819,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = ShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -8848,7 +8848,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = OpenAction/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 14.0; @@ -8882,7 +8882,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; INFOPLIST_FILE = Widgets/Info.plist; @@ -8913,7 +8913,7 @@ CODE_SIGN_ENTITLEMENTS = PacketTunnelProvider/PacketTunnelProviderAlpha.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; @@ -8946,11 +8946,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -9186,7 +9186,7 @@ CODE_SIGN_ENTITLEMENTS = DuckDuckGo/DuckDuckGoAlpha.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_ASSET_PATHS = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9214,7 +9214,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9247,7 +9247,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9285,7 +9285,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEAD_CODE_STRIPPING = NO; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; @@ -9321,7 +9321,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = HKE973VLUW; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -9356,11 +9356,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -9536,11 +9536,11 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -9569,10 +9569,10 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_CURRENT_VERSION = 2; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Core/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -9774,7 +9774,7 @@ repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 152.0.0; + version = 153.0.0; }; }; 9F8FE9472BAE50E50071E372 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 55804ac553..d43793703e 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" : "e32733e0e0b03bbac2fec160a2f967a15ed1794b", - "version" : "152.0.0" + "revision" : "b78ae617c7fe66244741f489158a1f40e567e674", + "version" : "153.0.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/content-scope-scripts", "state" : { - "revision" : "fa861c4eccb21d235e34070b208b78bdc32ece08", - "version" : "5.17.0" + "revision" : "ba2ad0c3a14a8c07d7be8b50a20b47efea207e86", + "version" : "5.19.0" } }, { diff --git a/DuckDuckGo/HomeMessage.xcassets/RemoteMessage/RemoteMessagePrivacyPro.imageset/Contents.json b/DuckDuckGo/HomeMessage.xcassets/RemoteMessage/RemoteMessagePrivacyShield.imageset/Contents.json similarity index 100% rename from DuckDuckGo/HomeMessage.xcassets/RemoteMessage/RemoteMessagePrivacyPro.imageset/Contents.json rename to DuckDuckGo/HomeMessage.xcassets/RemoteMessage/RemoteMessagePrivacyShield.imageset/Contents.json diff --git a/DuckDuckGo/HomeMessage.xcassets/RemoteMessage/RemoteMessagePrivacyPro.imageset/RemoteMessagePrivacyPro.pdf b/DuckDuckGo/HomeMessage.xcassets/RemoteMessage/RemoteMessagePrivacyShield.imageset/RemoteMessagePrivacyPro.pdf similarity index 100% rename from DuckDuckGo/HomeMessage.xcassets/RemoteMessage/RemoteMessagePrivacyPro.imageset/RemoteMessagePrivacyPro.pdf rename to DuckDuckGo/HomeMessage.xcassets/RemoteMessage/RemoteMessagePrivacyShield.imageset/RemoteMessagePrivacyPro.pdf diff --git a/DuckDuckGo/RemoteMessaging.swift b/DuckDuckGo/RemoteMessaging.swift index 494010a7ad..7dcd862ab4 100644 --- a/DuckDuckGo/RemoteMessaging.swift +++ b/DuckDuckGo/RemoteMessaging.swift @@ -141,6 +141,7 @@ struct RemoteMessaging { isWidgetInstalled: isWidgetInstalled) } + // swiftlint:disable:next function_body_length static private func fetchAndProcess(bookmarksCount: Int, favoritesCount: Int, remoteMessagingStore: RemoteMessagingStore = AppDependencyProvider.shared.remoteMessagingStore, @@ -159,10 +160,10 @@ struct RemoteMessaging { let activationDateStore = DefaultVPNActivationDateStore() let daysSinceNetworkProtectionEnabled = activationDateStore.daysSinceActivation() ?? -1 - let surveyActionMapper = DefaultRemoteMessagingSurveyURLBuilder(statisticsStore: statisticsStore) var privacyProDaysSinceSubscribed: Int = -1 var privacyProDaysUntilExpiry: Int = -1 + let surveyActionMapper: DefaultRemoteMessagingSurveyURLBuilder if let accessToken = AppDependencyProvider.shared.subscriptionManager.accountManager.accessToken { let subscriptionResult = await AppDependencyProvider.shared.subscriptionManager.subscriptionService.getSubscription( @@ -172,7 +173,12 @@ struct RemoteMessaging { if case let .success(subscription) = subscriptionResult { privacyProDaysSinceSubscribed = Calendar.current.numberOfDaysBetween(subscription.startedAt, and: Date()) ?? -1 privacyProDaysUntilExpiry = Calendar.current.numberOfDaysBetween(Date(), and: subscription.expiresOrRenewsAt) ?? -1 + surveyActionMapper = DefaultRemoteMessagingSurveyURLBuilder(statisticsStore: statisticsStore, subscription: subscription) + } else { + surveyActionMapper = DefaultRemoteMessagingSurveyURLBuilder(statisticsStore: statisticsStore, subscription: nil) } + } else { + surveyActionMapper = DefaultRemoteMessagingSurveyURLBuilder(statisticsStore: statisticsStore, subscription: nil) } let remoteMessagingConfigMatcher = RemoteMessagingConfigMatcher( diff --git a/DuckDuckGo/RemoteMessagingSurveyURLBuilder.swift b/DuckDuckGo/RemoteMessagingSurveyURLBuilder.swift index c6034c5e8f..1ea51ddc39 100644 --- a/DuckDuckGo/RemoteMessagingSurveyURLBuilder.swift +++ b/DuckDuckGo/RemoteMessagingSurveyURLBuilder.swift @@ -22,19 +22,23 @@ import BrowserServicesKit import RemoteMessaging import Core import Common +import Subscription struct DefaultRemoteMessagingSurveyURLBuilder: RemoteMessagingSurveyActionMapping { private let statisticsStore: StatisticsStore - private let activationDateStore: VPNActivationDateStore + private let vpnActivationDateStore: VPNActivationDateStore + private let subscription: Subscription? init(statisticsStore: StatisticsStore = StatisticsUserDefaults(), - activationDateStore: VPNActivationDateStore = DefaultVPNActivationDateStore()) { + vpnActivationDateStore: VPNActivationDateStore = DefaultVPNActivationDateStore(), + subscription: Subscription?) { self.statisticsStore = statisticsStore - self.activationDateStore = activationDateStore + self.vpnActivationDateStore = vpnActivationDateStore + self.subscription = subscription } - // swiftlint:disable:next cyclomatic_complexity + // swiftlint:disable:next cyclomatic_complexity function_body_length func add(parameters: [RemoteMessagingSurveyActionParameter], to surveyURL: URL) -> URL { guard var components = URLComponents(string: surveyURL.absoluteString) else { assertionFailure("Could not build URL components from survey URL") @@ -60,15 +64,56 @@ struct DefaultRemoteMessagingSurveyURLBuilder: RemoteMessagingSurveyActionMappin case .hardwareModel: let model = hardwareModel().addingPercentEncoding(withAllowedCharacters: .alphanumerics) queryItems.append(URLQueryItem(name: parameter.rawValue, value: model)) - case .lastActiveDate: - if let daysSinceLastActive = activationDateStore.daysSinceLastActive() { - queryItems.append(URLQueryItem(name: parameter.rawValue, value: String(describing: daysSinceLastActive))) - } case .daysInstalled: if let installDate = statisticsStore.installDate, - let daysSinceInstall = Calendar.current.numberOfDaysBetween(installDate, and: Date()) { + let daysSinceInstall = Calendar.current.numberOfDaysBetween(installDate, and: Date()) { queryItems.append(URLQueryItem(name: parameter.rawValue, value: String(describing: daysSinceInstall))) } + case .privacyProStatus: + switch subscription?.status { + case .autoRenewable: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "auto_renewable")) + case .notAutoRenewable: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "not_auto_renewable")) + case .gracePeriod: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "grace_period")) + case .inactive: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "inactive")) + case .expired: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "expired")) + case .unknown: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "unknown")) + case nil: break + } + case .privacyProPlatform: + + switch subscription?.platform { + case .apple: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "apple")) + case .google: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "google")) + case .stripe: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "stripe")) + case .unknown: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "unknown")) + case nil: break + } + case .privacyProBilling: + switch subscription?.billingPeriod { + case .monthly: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "monthly")) + case .yearly: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "yearly")) + case .unknown: queryItems.append(URLQueryItem(name: parameter.rawValue, value: "unknown")) + case nil: break + } + + case .privacyProDaysSincePurchase: + if let startDate = subscription?.startedAt, + let daysSincePurchase = Calendar.current.numberOfDaysBetween(startDate, and: Date()) { + queryItems.append(URLQueryItem(name: parameter.rawValue, value: String(describing: daysSincePurchase))) + } + case .privacyProDaysUntilExpiry: + if let expiryDate = subscription?.expiresOrRenewsAt, + let daysUntilExpiry = Calendar.current.numberOfDaysBetween(Date(), and: expiryDate) { + queryItems.append(URLQueryItem(name: parameter.rawValue, value: String(describing: daysUntilExpiry))) + } + case .vpnFirstUsed: + if let vpnFirstUsed = vpnActivationDateStore.daysSinceActivation() { + queryItems.append(URLQueryItem(name: parameter.rawValue, value: String(describing: vpnFirstUsed))) + } + case .vpnLastUsed: + if let vpnLastUsed = vpnActivationDateStore.daysSinceLastActive() { + queryItems.append(URLQueryItem(name: parameter.rawValue, value: String(describing: vpnLastUsed))) + } } }