From 6ae09d224507a6da41ed0794f6da08657fb6c35f Mon Sep 17 00:00:00 2001 From: Luca Schifino Date: Mon, 4 Nov 2024 16:01:15 +0100 Subject: [PATCH 01/59] Temporarily using ios-core feature branch --- Client.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 33 +++++++------------ 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index c083948e7ebe..5b5974eff86f 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -21497,7 +21497,7 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/ecosia/ios-core.git"; requirement = { - branch = main; + branch = "ls-mob-2959-braze-ntp-card-newsletter"; kind = branch; }; }; diff --git a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 067f83af1a6b..5446caf0ef9d 100644 --- a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -10,21 +10,21 @@ } }, { - "identity" : "braze-swift-sdk", + "identity" : "dip", "kind" : "remoteSourceControl", - "location" : "https://github.com/braze-inc/braze-swift-sdk", + "location" : "https://github.com/AliSoftware/Dip.git", "state" : { - "revision" : "36481467bc4f333a0a2e31bcdbf981ad8e526dd0", - "version" : "11.2.0" + "revision" : "c3b601df0ff22b06b6d5ff4943faf05c0bd3f9bb", + "version" : "7.1.1" } }, { - "identity" : "dip", + "identity" : "fmdb", "kind" : "remoteSourceControl", - "location" : "https://github.com/AliSoftware/Dip.git", + "location" : "https://github.com/ccgus/fmdb", "state" : { - "revision" : "c3b601df0ff22b06b6d5ff4943faf05c0bd3f9bb", - "version" : "7.1.1" + "revision" : "1227a3fa2b9916bfd75fe380eb45cd210e69e251", + "version" : "2.7.12" } }, { @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/ecosia/ios-core.git", "state" : { - "branch" : "main", - "revision" : "def9d182ab7c7fd65b092ab5d8044811ac1a3826" + "branch" : "ls-mob-2959-braze-ntp-card-newsletter", + "revision" : "12fe67a9e1ed8c8d74d1863c9b9cdae054d51100" } }, { @@ -108,15 +108,6 @@ "revision" : "b5d49206724ececd346bc1ac1a9474424e2f00df" } }, - { - "identity" : "sdwebimage", - "kind" : "remoteSourceControl", - "location" : "https://github.com/SDWebImage/SDWebImage.git", - "state" : { - "revision" : "10d06f6a33bafae8c164fbfd1f03391f6d4692b3", - "version" : "5.20.0" - } - }, { "identity" : "sentry-cocoa", "kind" : "remoteSourceControl", @@ -140,8 +131,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/snowplow/snowplow-ios-tracker.git", "state" : { - "revision" : "bf1495987d63dc3595270df1a1bb516bfef8585f", - "version" : "6.0.8" + "revision" : "1e16a929cef8e944bd41dc36a1d2779e06bd0a3c", + "version" : "5.2.0" } }, { From 32ba5ce08355ff13d705890ed9884ec48f970510 Mon Sep 17 00:00:00 2001 From: Luca Schifino Date: Tue, 5 Nov 2024 12:06:28 +0100 Subject: [PATCH 02/59] Add Braze package and BrazeService integration --- Client.xcodeproj/project.pbxproj | 25 +------------------ .../xcshareddata/swiftpm/Package.resolved | 18 +++++++++++++ 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index 5b5974eff86f..ab6a0553ff4d 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -27,15 +27,11 @@ 0BB5B30B1AC0AD1F0052877D /* LoginsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB5B30A1AC0AD1F0052877D /* LoginsHelper.swift */; }; 0BF0DB941A8545800039F300 /* URLBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF0DB931A8545800039F300 /* URLBarView.swift */; }; 0BF1B7E31AC60DEA00A7B407 /* InsetButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF1B7E21AC60DEA00A7B407 /* InsetButton.swift */; }; - 12147F2F2CDA3CD00009D300 /* NTPNewsletterCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F2E2CDA3CD00009D300 /* NTPNewsletterCardCell.swift */; }; - 12147F312CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F302CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift */; }; - 12147F332CDBA7230009D300 /* NewsletterCardExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F322CDBA7230009D300 /* NewsletterCardExperiment.swift */; }; 126509822CD924C00011BA36 /* BrazeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126509812CD924C00011BA36 /* BrazeService.swift */; }; 126509852CD925B40011BA36 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 126509842CD925B40011BA36 /* BrazeKit */; }; 126509872CD925B40011BA36 /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 126509862CD925B40011BA36 /* BrazeUI */; }; 1265098A2CDA32790011BA36 /* BrazeServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126509882CDA31890011BA36 /* BrazeServiceTests.swift */; }; - 1285E2B52CC293CA0053506B /* AnalyticsSpyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E2B42CC293CA0053506B /* AnalyticsSpyTests.swift */; }; - 1285E2B72CC68BF00053506B /* APNConsent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E2B62CC68BF00053506B /* APNConsent.swift */; }; + 1285E2B72CC68BF00053506B /* APNConsentOnLaunchExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E2B62CC68BF00053506B /* APNConsentOnLaunchExperiment.swift */; }; 158241282820698B00956B39 /* RustRemoteTabsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 158241272820698B00956B39 /* RustRemoteTabsTests.swift */; }; 15DE98FD27FCED4F00F1ECDB /* RustRemoteTabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15DE98FC27FCED4F00F1ECDB /* RustRemoteTabs.swift */; }; 1B3D99F1270E89D0006E1264 /* Telemetry in Frameworks */ = {isa = PBXBuildFile; productRef = 1B3D99F0270E89D0006E1264 /* Telemetry */; }; @@ -7964,33 +7960,14 @@ path = SearchQuickLinksMedium; sourceTree = ""; }; - 12147F2D2CDA3CB40009D300 /* Newsletter */ = { - isa = PBXGroup; - children = ( - 12147F2E2CDA3CD00009D300 /* NTPNewsletterCardCell.swift */, - 12147F302CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift */, - ); - path = Newsletter; - sourceTree = ""; - }; 126509802CD9249C0011BA36 /* Braze */ = { isa = PBXGroup; children = ( - 1285E2B62CC68BF00053506B /* APNConsent.swift */, 126509812CD924C00011BA36 /* BrazeService.swift */, ); path = Braze; sourceTree = ""; }; - 1285E2B32CC293A20053506B /* Analytics */ = { - isa = PBXGroup; - children = ( - 2CE294692B7FC5A5006C22B2 /* AnalyticsTests.swift */, - 1285E2B42CC293CA0053506B /* AnalyticsSpyTests.swift */, - ); - path = Analytics; - sourceTree = ""; - }; 1D7B78952ADF324E0011E9F2 /* Event Queue */ = { isa = PBXGroup; children = ( diff --git a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 5446caf0ef9d..b11c979f6de0 100644 --- a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -9,6 +9,15 @@ "version" : "3.0.0-beta-1" } }, + { + "identity" : "braze-swift-sdk", + "kind" : "remoteSourceControl", + "location" : "https://github.com/braze-inc/braze-swift-sdk", + "state" : { + "revision" : "36481467bc4f333a0a2e31bcdbf981ad8e526dd0", + "version" : "11.2.0" + } + }, { "identity" : "dip", "kind" : "remoteSourceControl", @@ -108,6 +117,15 @@ "revision" : "b5d49206724ececd346bc1ac1a9474424e2f00df" } }, + { + "identity" : "sdwebimage", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SDWebImage/SDWebImage.git", + "state" : { + "revision" : "10d06f6a33bafae8c164fbfd1f03391f6d4692b3", + "version" : "5.20.0" + } + }, { "identity" : "sentry-cocoa", "kind" : "remoteSourceControl", From f84ddde6ab9a9414c55c136ff1afb2f4ec084693 Mon Sep 17 00:00:00 2001 From: Luca Schifino Date: Wed, 6 Nov 2024 13:03:28 +0100 Subject: [PATCH 03/59] Create Newsletter Card and refactor nudge card superclass to simplify init --- Client.xcodeproj/project.pbxproj | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index ab6a0553ff4d..a83716d86646 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 0BB5B30B1AC0AD1F0052877D /* LoginsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB5B30A1AC0AD1F0052877D /* LoginsHelper.swift */; }; 0BF0DB941A8545800039F300 /* URLBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF0DB931A8545800039F300 /* URLBarView.swift */; }; 0BF1B7E31AC60DEA00A7B407 /* InsetButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF1B7E21AC60DEA00A7B407 /* InsetButton.swift */; }; + 12147F2F2CDA3CD00009D300 /* NTPNewsletterCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F2E2CDA3CD00009D300 /* NTPNewsletterCardCell.swift */; }; + 12147F312CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F302CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift */; }; 126509822CD924C00011BA36 /* BrazeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126509812CD924C00011BA36 /* BrazeService.swift */; }; 126509852CD925B40011BA36 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 126509842CD925B40011BA36 /* BrazeKit */; }; 126509872CD925B40011BA36 /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 126509862CD925B40011BA36 /* BrazeUI */; }; @@ -7960,6 +7962,15 @@ path = SearchQuickLinksMedium; sourceTree = ""; }; + 12147F2D2CDA3CB40009D300 /* Newsletter */ = { + isa = PBXGroup; + children = ( + 12147F2E2CDA3CD00009D300 /* NTPNewsletterCardCell.swift */, + 12147F302CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift */, + ); + path = Newsletter; + sourceTree = ""; + }; 126509802CD9249C0011BA36 /* Braze */ = { isa = PBXGroup; children = ( From 6205cc71b0620112ba78a0fd5ef8778fc1ee8fff Mon Sep 17 00:00:00 2001 From: Luca Schifino Date: Wed, 6 Nov 2024 16:47:50 +0100 Subject: [PATCH 04/59] Create experiment and link to card --- Client.xcodeproj/project.pbxproj | 1 + .../xcshareddata/swiftpm/Package.resolved | 2 +- .../Ecosia/Settings/EcosiaDebugSettings.swift | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index a83716d86646..dd93429d75b0 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 0BF1B7E31AC60DEA00A7B407 /* InsetButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF1B7E21AC60DEA00A7B407 /* InsetButton.swift */; }; 12147F2F2CDA3CD00009D300 /* NTPNewsletterCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F2E2CDA3CD00009D300 /* NTPNewsletterCardCell.swift */; }; 12147F312CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F302CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift */; }; + 12147F332CDBA7230009D300 /* NewsletterCardExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F322CDBA7230009D300 /* NewsletterCardExperiment.swift */; }; 126509822CD924C00011BA36 /* BrazeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126509812CD924C00011BA36 /* BrazeService.swift */; }; 126509852CD925B40011BA36 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 126509842CD925B40011BA36 /* BrazeKit */; }; 126509872CD925B40011BA36 /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 126509862CD925B40011BA36 /* BrazeUI */; }; diff --git a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b11c979f6de0..cf5005f8f9a7 100644 --- a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -69,7 +69,7 @@ "location" : "https://github.com/ecosia/ios-core.git", "state" : { "branch" : "ls-mob-2959-braze-ntp-card-newsletter", - "revision" : "12fe67a9e1ed8c8d74d1863c9b9cdae054d51100" + "revision" : "c65d3407196a6682b2e5f07ace2d0c0cd3c7c455" } }, { diff --git a/Client/Ecosia/Settings/EcosiaDebugSettings.swift b/Client/Ecosia/Settings/EcosiaDebugSettings.swift index 8efd4a0190a9..58528310d3c8 100644 --- a/Client/Ecosia/Settings/EcosiaDebugSettings.swift +++ b/Client/Ecosia/Settings/EcosiaDebugSettings.swift @@ -261,3 +261,30 @@ final class NewsletterCardDismissSetting: HiddenSetting { self.settings.tableView.reloadData() } } + +final class UnleashNewsletterCardSetting: UnleashVariantResetSetting { + override var titleName: String? { + "Newsletter Card" + } + + override var unleashEnabled: Bool? { + Unleash.isEnabled(.newsletterCard) + } +} + +final class NewsletterCardDismissSetting: HiddenSetting { + override var title: NSAttributedString? { + return NSAttributedString(string: "Debug: Unset Newsletter card dismissed", attributes: [NSAttributedString.Key.foregroundColor: UIColor.legacyTheme.tableView.rowText]) + } + + override var status: NSAttributedString? { + let attributes = [NSAttributedString.Key.foregroundColor: UIColor.legacyTheme.tableView.rowText] + let hintText = NewsletterCardExperiment.isDismissed ? "dismissed (Click to unset)" : "showing (Nothing to do here)" + return NSAttributedString(string: "Card is currently \(hintText)", attributes: attributes) + } + + override func onClick(_ navigationController: UINavigationController?) { + NewsletterCardExperiment.unsetDismissed() + self.settings.tableView.reloadData() + } +} From b91030430b1de91e9c75abfab5db4505a548fd6b Mon Sep 17 00:00:00 2001 From: Luca Schifino Date: Mon, 11 Nov 2024 12:21:44 +0100 Subject: [PATCH 05/59] Fix trailing whitespaces --- Client/Ecosia/Settings/EcosiaDebugSettings.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/Ecosia/Settings/EcosiaDebugSettings.swift b/Client/Ecosia/Settings/EcosiaDebugSettings.swift index 58528310d3c8..db2e24abff52 100644 --- a/Client/Ecosia/Settings/EcosiaDebugSettings.swift +++ b/Client/Ecosia/Settings/EcosiaDebugSettings.swift @@ -266,7 +266,7 @@ final class UnleashNewsletterCardSetting: UnleashVariantResetSetting { override var titleName: String? { "Newsletter Card" } - + override var unleashEnabled: Bool? { Unleash.isEnabled(.newsletterCard) } From 466bcfe4706f791077d3a859b88901feb3c364fb Mon Sep 17 00:00:00 2001 From: Luca Schifino Date: Wed, 13 Nov 2024 18:53:25 +0100 Subject: [PATCH 06/59] [MOB-2959] Use ios-core main again --- Client.xcodeproj/project.pbxproj | 2 +- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index dd93429d75b0..c39500f13d09 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -21486,7 +21486,7 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/ecosia/ios-core.git"; requirement = { - branch = "ls-mob-2959-braze-ntp-card-newsletter"; + branch = main; kind = branch; }; }; diff --git a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index cf5005f8f9a7..e3a327699c4d 100644 --- a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -68,8 +68,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/ecosia/ios-core.git", "state" : { - "branch" : "ls-mob-2959-braze-ntp-card-newsletter", - "revision" : "c65d3407196a6682b2e5f07ace2d0c0cd3c7c455" + "branch" : "main", + "revision" : "55fd76f4646b925b39168a1158396f36c6fd6f6f" } }, { From dbcdf5c32508cf0f779dee6007a9aa8fa8f93fce Mon Sep 17 00:00:00 2001 From: Luca Schifino Date: Fri, 15 Nov 2024 16:01:54 +0100 Subject: [PATCH 07/59] [MOB-3028] Create Ecosia Framework and move Braze there --- Client.xcodeproj/project.pbxproj | 1183 ++++++++++++++++- .../xcschemes/EcosiaFramework.xcscheme | 67 + Client/Application/AppDelegate.swift | 1 + .../HomepageViewController+Ecosia.swift | 1 + Client/Info.plist | 380 +++--- .../Ecosia => Ecosia}/Braze/APNConsent.swift | 1 + .../Braze/BrazeService.swift | 25 +- Ecosia/Ecosia.h | 15 + Ecosia/README.md | 2 + 9 files changed, 1402 insertions(+), 273 deletions(-) create mode 100644 Client.xcodeproj/xcshareddata/xcschemes/EcosiaFramework.xcscheme rename {Client/Ecosia => Ecosia}/Braze/APNConsent.swift (98%) rename {Client/Ecosia => Ecosia}/Braze/BrazeService.swift (82%) create mode 100644 Ecosia/Ecosia.h create mode 100644 Ecosia/README.md diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index c39500f13d09..32b319664a3d 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -30,10 +30,18 @@ 12147F2F2CDA3CD00009D300 /* NTPNewsletterCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F2E2CDA3CD00009D300 /* NTPNewsletterCardCell.swift */; }; 12147F312CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F302CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift */; }; 12147F332CDBA7230009D300 /* NewsletterCardExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F322CDBA7230009D300 /* NewsletterCardExperiment.swift */; }; - 126509822CD924C00011BA36 /* BrazeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126509812CD924C00011BA36 /* BrazeService.swift */; }; + 122935742CE78D0A00EC1297 /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; + 1229357C2CE78D0A00EC1297 /* Ecosia.h in Headers */ = {isa = PBXBuildFile; fileRef = 1229356C2CE78D0A00EC1297 /* Ecosia.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1229357F2CE78D0A00EC1297 /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; + 122935802CE78D0A00EC1297 /* Ecosia.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 1229358D2CE78D5D00EC1297 /* BrazeServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126509882CDA31890011BA36 /* BrazeServiceTests.swift */; }; + 1229358F2CE78EC400EC1297 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 1229358E2CE78EC400EC1297 /* Core */; }; + 122935912CE78ED500EC1297 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 122935902CE78ED500EC1297 /* BrazeKit */; }; + 122935932CE78ED500EC1297 /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 122935922CE78ED500EC1297 /* BrazeUI */; }; + 1229359C2CE7927900EC1297 /* BrazeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1229359B2CE7927800EC1297 /* BrazeService.swift */; }; 126509852CD925B40011BA36 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 126509842CD925B40011BA36 /* BrazeKit */; }; 126509872CD925B40011BA36 /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 126509862CD925B40011BA36 /* BrazeUI */; }; - 1265098A2CDA32790011BA36 /* BrazeServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126509882CDA31890011BA36 /* BrazeServiceTests.swift */; }; + 1285E2B52CC293CA0053506B /* AnalyticsSpyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E2B42CC293CA0053506B /* AnalyticsSpyTests.swift */; }; 1285E2B72CC68BF00053506B /* APNConsentOnLaunchExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E2B62CC68BF00053506B /* APNConsentOnLaunchExperiment.swift */; }; 158241282820698B00956B39 /* RustRemoteTabsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 158241272820698B00956B39 /* RustRemoteTabsTests.swift */; }; 15DE98FD27FCED4F00F1ECDB /* RustRemoteTabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15DE98FC27FCED4F00F1ECDB /* RustRemoteTabs.swift */; }; @@ -1617,6 +1625,27 @@ remoteGlobalIDString = 047F9B2624E1FE1C00CD7DF7; remoteInfo = WidgetKitExtension; }; + 122935752CE78D0A00EC1297 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F84B21B61A090F8100AAB793 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 122935692CE78D0A00EC1297; + remoteInfo = Ecosia; + }; + 122935772CE78D0A00EC1297 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F84B21B61A090F8100AAB793 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F84B21BD1A090F8100AAB793; + remoteInfo = Client; + }; + 1229357D2CE78D0A00EC1297 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F84B21B61A090F8100AAB793 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 122935692CE78D0A00EC1297; + remoteInfo = Ecosia; + }; 2827316A1ABC9BE700AA1954 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = F84B21B61A090F8100AAB793 /* Project object */; @@ -1852,6 +1881,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + 122935802CE78D0A00EC1297 /* Ecosia.framework in Copy Frameworks */, 43017ECB278E0C6700CED011 /* RustMozillaAppServices.framework in Copy Frameworks */, C82043C32523DD6A00740B71 /* Sync.framework in Copy Frameworks */, C87703D225223EA5006E38EB /* Shared.framework in Copy Frameworks */, @@ -2022,8 +2052,12 @@ 12147F2E2CDA3CD00009D300 /* NTPNewsletterCardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NTPNewsletterCardCell.swift; sourceTree = ""; }; 12147F302CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NTPNewsletterCardViewModel.swift; sourceTree = ""; }; 12147F322CDBA7230009D300 /* NewsletterCardExperiment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsletterCardExperiment.swift; sourceTree = ""; }; + 1229356A2CE78D0A00EC1297 /* Ecosia.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Ecosia.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1229356C2CE78D0A00EC1297 /* Ecosia.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Ecosia.h; sourceTree = ""; }; + 122935732CE78D0A00EC1297 /* EcosiaTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = EcosiaTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 1229359B2CE7927800EC1297 /* BrazeService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrazeService.swift; sourceTree = ""; }; + 1229359D2CE792B700EC1297 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 123045959E0F295753B4B4DB /* lo */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lo; path = lo.lproj/Today.strings; sourceTree = ""; }; - 126509812CD924C00011BA36 /* BrazeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrazeService.swift; sourceTree = ""; }; 126509882CDA31890011BA36 /* BrazeServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrazeServiceTests.swift; sourceTree = ""; }; 12674A038346A46589A0AC0B /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = "el.lproj/Default Browser.strings"; sourceTree = ""; }; 126A40A4A5AFDFD655B0FDF4 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/ClearHistoryConfirm.strings; sourceTree = ""; }; @@ -7755,6 +7789,24 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 122935672CE78D0A00EC1297 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 122935932CE78ED500EC1297 /* BrazeUI in Frameworks */, + 122935912CE78ED500EC1297 /* BrazeKit in Frameworks */, + 1229358F2CE78EC400EC1297 /* Core in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 122935702CE78D0A00EC1297 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 122935742CE78D0A00EC1297 /* Ecosia.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 2827315A1ABC9BE600AA1954 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -7799,6 +7851,7 @@ 2C6189F12B7B7D5D006B70D7 /* SnowplowTracker in Frameworks */, 43BE580E278BABCF00491291 /* RustMozillaAppServices.framework in Frameworks */, C82043852523DBF600740B71 /* Sync.framework in Frameworks */, + 1229357F2CE78D0A00EC1297 /* Ecosia.framework in Frameworks */, 5A37861929A2C337006B3A34 /* Sentry in Frameworks */, 8AF2D0FC2A5F272A00C7DD69 /* ComponentLibrary in Frameworks */, 5A871490292EA3910039A5BD /* SiteImageView in Frameworks */, @@ -7972,10 +8025,28 @@ path = Newsletter; sourceTree = ""; }; - 126509802CD9249C0011BA36 /* Braze */ = { + 1229356B2CE78D0A00EC1297 /* Ecosia */ = { + isa = PBXGroup; + children = ( + 122935962CE7913100EC1297 /* Braze */, + 1229356C2CE78D0A00EC1297 /* Ecosia.h */, + 1229359D2CE792B700EC1297 /* README.md */, + ); + path = Ecosia; + sourceTree = ""; + }; + 122935792CE78D0A00EC1297 /* EcosiaTests */ = { isa = PBXGroup; children = ( - 126509812CD924C00011BA36 /* BrazeService.swift */, + 126509882CDA31890011BA36 /* BrazeServiceTests.swift */, + ); + path = EcosiaTests; + sourceTree = ""; + }; + 122935962CE7913100EC1297 /* Braze */ = { + isa = PBXGroup; + children = ( + 1229359B2CE7927800EC1297 /* BrazeService.swift */, ); path = Braze; sourceTree = ""; @@ -8433,7 +8504,6 @@ 2C6189192B7A8A22006B70D7 /* Fake */, 2C6189232B7A8A22006B70D7 /* Helpers */, 2C61892D2B7A8A22006B70D7 /* Analytics */, - 126509802CD9249C0011BA36 /* Braze */, ); path = Ecosia; sourceTree = ""; @@ -8985,7 +9055,6 @@ 2CABD7272C12EF1E00A0750F /* PrivateModeButtonTests.swift */, 2C2349A22C57E5BC007A5894 /* EcosiaPerformanceTestHistory.swift */, 2CD48B7E2C7F7E4100A70908 /* EcosiaOverlayModeManagerTests.swift */, - 126509882CDA31890011BA36 /* BrazeServiceTests.swift */, ); path = EcosiaTests; sourceTree = ""; @@ -11980,6 +12049,8 @@ F8708D1E1A0970990051AB07 /* Extensions */, 047F9B2A24E1FE1C00CD7DF7 /* WidgetKit */, F8324A082649A188007E4BFA /* CredentialProvider */, + 1229356B2CE78D0A00EC1297 /* Ecosia */, + 122935792CE78D0A00EC1297 /* EcosiaTests */, 7B604FC11C496005006EEEC3 /* Frameworks */, F84B21BF1A090F8100AAB793 /* Products */, D34DC84C1A16C40C00D49B7B /* Providers */, @@ -12013,6 +12084,8 @@ 047F9B2724E1FE1C00CD7DF7 /* WidgetKitExtension.appex */, 43BE578A278BA4D900491291 /* RustMozillaAppServices.framework */, 2C6C90822C614A16007D9B43 /* EcosiaSnapshotTests.xctest */, + 1229356A2CE78D0A00EC1297 /* Ecosia.framework */, + 122935732CE78D0A00EC1297 /* EcosiaTests.xctest */, ); name = Products; sourceTree = ""; @@ -12319,6 +12392,17 @@ }; /* End PBXGroup section */ +/* Begin PBXHeadersBuildPhase section */ + 122935652CE78D0A00EC1297 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 1229357C2CE78D0A00EC1297 /* Ecosia.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + /* Begin PBXNativeTarget section */ 047F9B2624E1FE1C00CD7DF7 /* WidgetKitExtension */ = { isa = PBXNativeTarget; @@ -12348,6 +12432,48 @@ productReference = 047F9B2724E1FE1C00CD7DF7 /* WidgetKitExtension.appex */; productType = "com.apple.product-type.app-extension"; }; + 122935692CE78D0A00EC1297 /* Ecosia */ = { + isa = PBXNativeTarget; + buildConfigurationList = 122935812CE78D0A00EC1297 /* Build configuration list for PBXNativeTarget "Ecosia" */; + buildPhases = ( + 122935652CE78D0A00EC1297 /* Headers */, + 122935662CE78D0A00EC1297 /* Sources */, + 122935672CE78D0A00EC1297 /* Frameworks */, + 122935682CE78D0A00EC1297 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Ecosia; + packageProductDependencies = ( + 1229358E2CE78EC400EC1297 /* Core */, + 122935902CE78ED500EC1297 /* BrazeKit */, + 122935922CE78ED500EC1297 /* BrazeUI */, + ); + productName = Ecosia; + productReference = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; + productType = "com.apple.product-type.framework"; + }; + 122935722CE78D0A00EC1297 /* EcosiaTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 122935872CE78D0A00EC1297 /* Build configuration list for PBXNativeTarget "EcosiaTests" */; + buildPhases = ( + 1229356F2CE78D0A00EC1297 /* Sources */, + 122935702CE78D0A00EC1297 /* Frameworks */, + 122935712CE78D0A00EC1297 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 122935762CE78D0A00EC1297 /* PBXTargetDependency */, + 122935782CE78D0A00EC1297 /* PBXTargetDependency */, + ); + name = EcosiaTests; + productName = EcosiaTests; + productReference = 122935732CE78D0A00EC1297 /* EcosiaTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 2827315D1ABC9BE600AA1954 /* Sync */ = { isa = PBXNativeTarget; buildConfigurationList = 282731971ABC9BE800AA1954 /* Build configuration list for PBXNativeTarget "Sync" */; @@ -12641,6 +12767,7 @@ 288A2D9C1AB8B3260023ABC3 /* PBXTargetDependency */, F84B22521A0920C600AAB793 /* PBXTargetDependency */, 047F9B3124E1FE1F00CD7DF7 /* PBXTargetDependency */, + 1229357E2CE78D0A00EC1297 /* PBXTargetDependency */, ); name = Client; packageProductDependencies = ( @@ -12730,6 +12857,13 @@ 047F9B2624E1FE1C00CD7DF7 = { CreatedOnToolsVersion = 12.0; }; + 122935692CE78D0A00EC1297 = { + CreatedOnToolsVersion = 15.4; + }; + 122935722CE78D0A00EC1297 = { + CreatedOnToolsVersion = 15.4; + TestTargetID = F84B21BD1A090F8100AAB793; + }; 2827315D1ABC9BE600AA1954 = { CreatedOnToolsVersion = 6.2; LastSwiftMigration = 1000; @@ -12988,6 +13122,8 @@ 288A2D851AB8B3260023ABC3 /* Shared */, 2827315D1ABC9BE600AA1954 /* Sync */, 2C6C90812C614A16007D9B43 /* EcosiaSnapshotTests */, + 122935692CE78D0A00EC1297 /* Ecosia */, + 122935722CE78D0A00EC1297 /* EcosiaTests */, ); }; /* End PBXProject section */ @@ -13004,6 +13140,20 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 122935682CE78D0A00EC1297 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 122935712CE78D0A00EC1297 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 2827315C1ABC9BE600AA1954 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -13355,6 +13505,22 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 122935662CE78D0A00EC1297 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1229359C2CE7927900EC1297 /* BrazeService.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1229356F2CE78D0A00EC1297 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1229358D2CE78D5D00EC1297 /* BrazeServiceTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 282731591ABC9BE600AA1954 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -14203,7 +14369,6 @@ 74F80D342A0A52D700013C3D /* PrivacyPolicyViewController.swift in Sources */, 2C61894F2B7A8A22006B70D7 /* NTPLibaryCellViewModel.swift in Sources */, 274A36CE239EB9EC00A21587 /* LibraryViewController+LibraryPanelDelegate.swift in Sources */, - 126509822CD924C00011BA36 /* BrazeService.swift in Sources */, C869912D28917688007ACC5C /* WallpaperImageLoader.swift in Sources */, 96A5F73829928B3700234E5F /* GeneralizedImageFetcher.swift in Sources */, 1D7B78992ADF328E0011E9F2 /* AppEvent.swift in Sources */, @@ -14729,7 +14894,6 @@ ABB507CF2A136FB2009CAA67 /* UserConversionMetricsTests.swift in Sources */, 21FA8FB22AE856EB0013B815 /* MockTabTrayCoordinatorDelegate.swift in Sources */, C8699152289177F5007ACC5C /* WallpaperNetworkingTests.swift in Sources */, - 1265098A2CDA32790011BA36 /* BrazeServiceTests.swift in Sources */, E1AEC178286E0CF500062E29 /* HomepageViewControllerTests.swift in Sources */, 8ADEC6832A40F208002D2ED8 /* AppSettingsTableViewControllerTests.swift in Sources */, 5A475E8E29DB89C7009C13FD /* TabManagerTests.swift in Sources */, @@ -14803,6 +14967,21 @@ target = 047F9B2624E1FE1C00CD7DF7 /* WidgetKitExtension */; targetProxy = 047F9B3024E1FE1F00CD7DF7 /* PBXContainerItemProxy */; }; + 122935762CE78D0A00EC1297 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 122935692CE78D0A00EC1297 /* Ecosia */; + targetProxy = 122935752CE78D0A00EC1297 /* PBXContainerItemProxy */; + }; + 122935782CE78D0A00EC1297 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F84B21BD1A090F8100AAB793 /* Client */; + targetProxy = 122935772CE78D0A00EC1297 /* PBXContainerItemProxy */; + }; + 1229357E2CE78D0A00EC1297 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 122935692CE78D0A00EC1297 /* Ecosia */; + targetProxy = 1229357D2CE78D0A00EC1297 /* PBXContainerItemProxy */; + }; 2827316B1ABC9BE700AA1954 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 2827315D1ABC9BE600AA1954 /* Sync */; @@ -19565,57 +19744,934 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 282731771ABC9BE800AA1954 /* Debug */ = { + 122935822CE78D0A00EC1297 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CODE_SIGN_ENTITLEMENTS = ""; + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Manual; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 33YMRSYD2L; - GCC_WARN_INHIBIT_ALL_WARNINGS = YES; - INFOPLIST_FILE = Sync/Info.plist; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Sync/Sync-Bridging-Header.h"; - }; - name = Debug; - }; - 2827317A1ABC9BE800AA1954 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_ENTITLEMENTS = ""; - CODE_SIGN_IDENTITY = ""; - INFOPLIST_FILE = "firefox-ios/firefox-ios-tests/Tests/SyncTests/Info.plist"; - SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/firefox-ios/firefox-ios-tests/Tests/SyncTests/SyncTests-Bridging-Header.h"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client"; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = "$(MOZ_BUNDLE_DISPLAY_NAME)"; + INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; + INFOPLIST_KEY_NSCameraUsageDescription = "Firefox uses your camera to scan QR codes and take photos and video."; + INFOPLIST_KEY_NSFaceIDUsageDescription = "Firefox requires Face ID to access your saved passwords and payment methods."; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Mozilla. All rights reserved."; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Websites you visit may request your location."; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "Firefox uses your microphone to record and upload audio."; + INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "This lets you save photos."; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = EcosiaLaunchScreen; + INFOPLIST_KEY_UIRequiredDeviceCapabilities = armv7; + INFOPLIST_KEY_UIStatusBarHidden = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.ecosia.framework.Ecosia; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; }; name = Debug; }; - 288A2DA01AB8B3260023ABC3 /* Debug */ = { + 122935832CE78D0A00EC1297 /* BetaDebug */ = { isa = XCBuildConfiguration; buildSettings = { - APPLICATION_EXTENSION_API_ONLY = YES; - CODE_SIGN_ENTITLEMENTS = ""; + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 33YMRSYD2L; - GCC_WARN_INHIBIT_ALL_WARNINGS = YES; - INFOPLIST_FILE = "Shared/Supporting Files/Info.plist"; - LOCALIZED_STRING_MACRO_NAMES = ( - MZLocalizedString, - NSLocalizedString, - CFCopyLocalizedString, + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 33YMRSYD2L; + "DEVELOPMENT_TEAM[sdk=macosx*]" = 33YMRSYD2L; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = "$(MOZ_BUNDLE_DISPLAY_NAME)"; + INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; + INFOPLIST_KEY_NSCameraUsageDescription = "Firefox uses your camera to scan QR codes and take photos and video."; + INFOPLIST_KEY_NSFaceIDUsageDescription = "Firefox requires Face ID to access your saved passwords and payment methods."; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Mozilla. All rights reserved."; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Websites you visit may request your location."; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "Firefox uses your microphone to record and upload audio."; + INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "This lets you save photos."; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = EcosiaLaunchScreen; + INFOPLIST_KEY_UIRequiredDeviceCapabilities = armv7; + INFOPLIST_KEY_UIStatusBarHidden = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.ecosia.framework.Ecosia; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Shared/Shared-Bridging-Header.h"; - }; - name = Debug; - }; - 2C6189AB2B7A8B15006B70D7 /* Development_AppCenter */ = { + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = BetaDebug; + }; + 122935842CE78D0A00EC1297 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = "$(MOZ_BUNDLE_DISPLAY_NAME)"; + INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; + INFOPLIST_KEY_NSCameraUsageDescription = "Firefox uses your camera to scan QR codes and take photos and video."; + INFOPLIST_KEY_NSFaceIDUsageDescription = "Firefox requires Face ID to access your saved passwords and payment methods."; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Mozilla. All rights reserved."; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Websites you visit may request your location."; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "Firefox uses your microphone to record and upload audio."; + INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "This lets you save photos."; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = EcosiaLaunchScreen; + INFOPLIST_KEY_UIRequiredDeviceCapabilities = armv7; + INFOPLIST_KEY_UIStatusBarHidden = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.ecosia.framework.Ecosia; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 122935852CE78D0A00EC1297 /* Development_TestFlight */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = "$(MOZ_BUNDLE_DISPLAY_NAME)"; + INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; + INFOPLIST_KEY_NSCameraUsageDescription = "Firefox uses your camera to scan QR codes and take photos and video."; + INFOPLIST_KEY_NSFaceIDUsageDescription = "Firefox requires Face ID to access your saved passwords and payment methods."; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Mozilla. All rights reserved."; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Websites you visit may request your location."; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "Firefox uses your microphone to record and upload audio."; + INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "This lets you save photos."; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = EcosiaLaunchScreen; + INFOPLIST_KEY_UIRequiredDeviceCapabilities = armv7; + INFOPLIST_KEY_UIStatusBarHidden = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.ecosia.framework.Ecosia; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Development_TestFlight; + }; + 122935862CE78D0A00EC1297 /* Development_AppCenter */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + BUILD_LIBRARY_FOR_DISTRIBUTION = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_CFBundleDisplayName = "$(MOZ_BUNDLE_DISPLAY_NAME)"; + INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; + INFOPLIST_KEY_NSCameraUsageDescription = "Firefox uses your camera to scan QR codes and take photos and video."; + INFOPLIST_KEY_NSFaceIDUsageDescription = "Firefox requires Face ID to access your saved passwords and payment methods."; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Mozilla. All rights reserved."; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "Websites you visit may request your location."; + INFOPLIST_KEY_NSMicrophoneUsageDescription = "Firefox uses your microphone to record and upload audio."; + INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "This lets you save photos."; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = EcosiaLaunchScreen; + INFOPLIST_KEY_UIRequiredDeviceCapabilities = armv7; + INFOPLIST_KEY_UIStatusBarHidden = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 15; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.ecosia.framework.Ecosia; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_INSTALL_OBJC_HEADER = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Development_AppCenter; + }; + 122935882CE78D0A00EC1297 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 33YMRSYD2L; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.ecosia.framework.EcosiaTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Client"; + }; + name = Debug; + }; + 122935892CE78D0A00EC1297 /* BetaDebug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = 33YMRSYD2L; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.ecosia.framework.EcosiaTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Client"; + VALIDATE_PRODUCT = YES; + }; + name = BetaDebug; + }; + 1229358A2CE78D0A00EC1297 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = 33YMRSYD2L; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.ecosia.framework.EcosiaTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Client"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 1229358B2CE78D0A00EC1297 /* Development_TestFlight */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 33YMRSYD2L; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.ecosia.framework.EcosiaTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Client"; + }; + name = Development_TestFlight; + }; + 1229358C2CE78D0A00EC1297 /* Development_AppCenter */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = 33YMRSYD2L; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.5; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.ecosia.framework.EcosiaTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Client"; + }; + name = Development_AppCenter; + }; + 282731771ABC9BE800AA1954 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_ENTITLEMENTS = ""; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = NO; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 33YMRSYD2L; + GCC_WARN_INHIBIT_ALL_WARNINGS = YES; + INFOPLIST_FILE = Sync/Info.plist; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Sync/Sync-Bridging-Header.h"; + }; + name = Debug; + }; + 2827317A1ABC9BE800AA1954 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_ENTITLEMENTS = ""; + CODE_SIGN_IDENTITY = ""; + INFOPLIST_FILE = "firefox-ios/firefox-ios-tests/Tests/SyncTests/Info.plist"; + SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/firefox-ios/firefox-ios-tests/Tests/SyncTests/SyncTests-Bridging-Header.h"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Client.app/Client"; + }; + name = Debug; + }; + 288A2DA01AB8B3260023ABC3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_ENTITLEMENTS = ""; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = NO; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 33YMRSYD2L; + GCC_WARN_INHIBIT_ALL_WARNINGS = YES; + INFOPLIST_FILE = "Shared/Supporting Files/Info.plist"; + LOCALIZED_STRING_MACRO_NAMES = ( + MZLocalizedString, + NSLocalizedString, + CFCopyLocalizedString, + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OBJC_BRIDGING_HEADER = "$SRCROOT/Shared/Shared-Bridging-Header.h"; + }; + name = Debug; + }; + 2C6189AB2B7A8B15006B70D7 /* Development_AppCenter */ = { isa = XCBuildConfiguration; baseConfigurationReference = 2CBCAB0B2B88EEE40080AD68 /* EcosiaBeta.xcconfig */; buildSettings = { @@ -21259,6 +22315,30 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; + 122935812CE78D0A00EC1297 /* Build configuration list for PBXNativeTarget "Ecosia" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 122935822CE78D0A00EC1297 /* Debug */, + 122935832CE78D0A00EC1297 /* BetaDebug */, + 122935842CE78D0A00EC1297 /* Release */, + 122935852CE78D0A00EC1297 /* Development_TestFlight */, + 122935862CE78D0A00EC1297 /* Development_AppCenter */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + 122935872CE78D0A00EC1297 /* Build configuration list for PBXNativeTarget "EcosiaTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 122935882CE78D0A00EC1297 /* Debug */, + 122935892CE78D0A00EC1297 /* BetaDebug */, + 1229358A2CE78D0A00EC1297 /* Release */, + 1229358B2CE78D0A00EC1297 /* Development_TestFlight */, + 1229358C2CE78D0A00EC1297 /* Development_AppCenter */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; 282731971ABC9BE800AA1954 /* Build configuration list for PBXNativeTarget "Sync" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -21581,6 +22661,21 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 1229358E2CE78EC400EC1297 /* Core */ = { + isa = XCSwiftPackageProductDependency; + package = 2C61887D2B7A89E4006B70D7 /* XCRemoteSwiftPackageReference "ios-core" */; + productName = Core; + }; + 122935902CE78ED500EC1297 /* BrazeKit */ = { + isa = XCSwiftPackageProductDependency; + package = 126509832CD925B30011BA36 /* XCRemoteSwiftPackageReference "braze-swift-sdk" */; + productName = BrazeKit; + }; + 122935922CE78ED500EC1297 /* BrazeUI */ = { + isa = XCSwiftPackageProductDependency; + package = 126509832CD925B30011BA36 /* XCRemoteSwiftPackageReference "braze-swift-sdk" */; + productName = BrazeUI; + }; 126509842CD925B40011BA36 /* BrazeKit */ = { isa = XCSwiftPackageProductDependency; package = 126509832CD925B30011BA36 /* XCRemoteSwiftPackageReference "braze-swift-sdk" */; diff --git a/Client.xcodeproj/xcshareddata/xcschemes/EcosiaFramework.xcscheme b/Client.xcodeproj/xcshareddata/xcschemes/EcosiaFramework.xcscheme new file mode 100644 index 000000000000..1ad17baa59cf --- /dev/null +++ b/Client.xcodeproj/xcshareddata/xcschemes/EcosiaFramework.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Client/Application/AppDelegate.swift b/Client/Application/AppDelegate.swift index 69e49f66f9a9..26ffc750f833 100644 --- a/Client/Application/AppDelegate.swift +++ b/Client/Application/AppDelegate.swift @@ -11,6 +11,7 @@ import Common import TabDataStore // Ecosia: Import Core import Core +import Ecosia class AppDelegate: UIResponder, UIApplicationDelegate { let logger = DefaultLogger.shared diff --git a/Client/Ecosia/Extensions/HomepageViewController+Ecosia.swift b/Client/Ecosia/Extensions/HomepageViewController+Ecosia.swift index ea5ad4abee40..6eeb66f15bab 100644 --- a/Client/Ecosia/Extensions/HomepageViewController+Ecosia.swift +++ b/Client/Ecosia/Extensions/HomepageViewController+Ecosia.swift @@ -4,6 +4,7 @@ import UIKit import Core +import Ecosia protocol HomepageViewControllerDelegate: AnyObject { func homeDidTapSearchButton(_ home: HomepageViewController) diff --git a/Client/Info.plist b/Client/Info.plist index 0d44d6d3110f..f35c168b2570 100644 --- a/Client/Info.plist +++ b/Client/Info.plist @@ -2,222 +2,168 @@ - AdjustAppToken - $(ADJUST_APP_TOKEN) - AppIdentifierPrefix - $(APP_IDENTIFIER_PREFIX) - BGTaskSchedulerPermittedIdentifiers - - org.mozilla.ios.sync.part1 - org.mozilla.ios.sync.part2 - org.mozilla.ios.surface.notification.refresh - org.mozilla.ios.firefox.suggest.ingest - - BRAZE_API_KEY - $(BRAZE_API_KEY) - CFBundleDevelopmentRegion - en - CFBundleDisplayName - $(MOZ_BUNDLE_DISPLAY_NAME) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(MOZ_PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleSignature - ???? - CFBundleURLTypes - - - CFBundleURLName - com.ecosia.ecosiaapp - CFBundleURLSchemes - - $(MOZ_PUBLIC_URL_SCHEME) - $(MOZ_INTERNAL_URL_SCHEME) - http - https - - - - CFBundleVersion - 1 - CF_ACCESS_CLIENT_ID - $(CF_ACCESS_CLIENT_ID) - CF_ACCESS_CLIENT_SECRET - $(CF_ACCESS_CLIENT_SECRET) - INIntentsSupported - - QuickActionIntent - - ITSAppUsesNonExemptEncryption - - LSApplicationQueriesSchemes - - pocket - firefox-focus - firefox-klar - ymail - ms-outlook - airmail - italiaonline-mailto - mailru-mailto - mymail-mailto - readdle-spark - itms-books - org-appextension-feature-password-management - googlegmail - fastmail - protonmail - whatsapp - - LSRequiresIPhoneOS - - LSSupportsOpeningDocumentsInPlace - - MozDevelopmentTeam - $(DEVELOPMENT_TEAM) - MozInternalURLScheme - $(MOZ_INTERNAL_URL_SCHEME) - MozPublicURLScheme - $(MOZ_PUBLIC_URL_SCHEME) - MozWallpaperURLScheme - $(MOZ_WALLPAPER_ASSET_URL) - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - - NSCameraUsageDescription - Firefox uses your camera to scan QR codes and take photos and video. - NSFaceIDUsageDescription - Firefox requires Face ID to access your saved passwords and payment methods. - NSLocationWhenInUseUsageDescription - Websites you visit may request your location. - NSMicrophoneUsageDescription - Firefox uses your microphone to record and upload audio. - NSPhotoLibraryAddUsageDescription - This lets you save photos. - NSUserActivityTypes - - QuickActionIntent - QuickLinkSelectionIntent - com.ecosia.ecosiaapp.browsing - - NimbusURL - $(NIMBUS_URL) - PocketEnvironmentAPIKey - $(POCKET_API_KEY) - SentryCloudDSN - $(SENTRY_CLOUD_DSN) - UIAppFonts - - NewYorkMedium-Bold.otf - NewYorkMedium-BoldItalic.otf - NewYorkMedium-Regular.otf - NewYorkMedium-RegularItalic.otf - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneClassName - UIWindowScene - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - - - - - UIApplicationShortcutItems - - - UIApplicationShortcutItemIconFile - plusLarge - UIApplicationShortcutItemTitle - New Tab - UIApplicationShortcutItemType - $(PRODUCT_BUNDLE_IDENTIFIER).NewTab - - - UIApplicationShortcutItemIconFile - privateSearch - UIApplicationShortcutItemTitle - New Private Tab - UIApplicationShortcutItemType - $(PRODUCT_BUNDLE_IDENTIFIER).NewPrivateTab - - - UIApplicationShortcutItemIconFile - menu-ScanQRCode - UIApplicationShortcutItemTitle - Scan QR Code - UIApplicationShortcutItemType - $(PRODUCT_BUNDLE_IDENTIFIER).QRCode - - - UIApplicationSupportsIndirectInputEvents - - UIBackgroundModes - - fetch - processing - remote-notification - - UIFileSharingEnabled - - UILaunchStoryboardName - EcosiaLaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UIStatusBarHidden - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - UTImportedTypeDeclarations - - - UTTypeConformsTo - - public.url - - UTTypeDescription - 1Password Fill Browser Action - UTTypeIdentifier - org.appextension.fill-browser-action - UTTypeSize64IconFile - - - + AdjustAppToken + $(ADJUST_APP_TOKEN) + AppIdentifierPrefix + $(APP_IDENTIFIER_PREFIX) + BGTaskSchedulerPermittedIdentifiers + + org.mozilla.ios.sync.part1 + org.mozilla.ios.sync.part2 + org.mozilla.ios.surface.notification.refresh + org.mozilla.ios.firefox.suggest.ingest + + BRAZE_API_KEY + $(BRAZE_API_KEY) + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleURLName + com.ecosia.ecosiaapp + CFBundleURLSchemes + + $(MOZ_PUBLIC_URL_SCHEME) + $(MOZ_INTERNAL_URL_SCHEME) + http + https + + + + CF_ACCESS_CLIENT_ID + $(CF_ACCESS_CLIENT_ID) + CF_ACCESS_CLIENT_SECRET + $(CF_ACCESS_CLIENT_SECRET) + INIntentsSupported + + QuickActionIntent + + ITSAppUsesNonExemptEncryption + + LSApplicationQueriesSchemes + + pocket + firefox-focus + firefox-klar + ymail + ms-outlook + airmail + italiaonline-mailto + mailru-mailto + mymail-mailto + readdle-spark + itms-books + org-appextension-feature-password-management + googlegmail + fastmail + protonmail + whatsapp + + LSRequiresIPhoneOS + + MozDevelopmentTeam + $(DEVELOPMENT_TEAM) + MozInternalURLScheme + $(MOZ_INTERNAL_URL_SCHEME) + MozPublicURLScheme + $(MOZ_PUBLIC_URL_SCHEME) + MozWallpaperURLScheme + $(MOZ_WALLPAPER_ASSET_URL) + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSUserActivityTypes + + QuickActionIntent + QuickLinkSelectionIntent + com.ecosia.ecosiaapp.browsing + + NimbusURL + $(NIMBUS_URL) + PocketEnvironmentAPIKey + $(POCKET_API_KEY) + SentryCloudDSN + $(SENTRY_CLOUD_DSN) + UIAppFonts + + NewYorkMedium-Bold.otf + NewYorkMedium-BoldItalic.otf + NewYorkMedium-Regular.otf + NewYorkMedium-RegularItalic.otf + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneClassName + UIWindowScene + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + + + + + UIApplicationShortcutItems + + + UIApplicationShortcutItemIconFile + plusLarge + UIApplicationShortcutItemTitle + New Tab + UIApplicationShortcutItemType + $(PRODUCT_BUNDLE_IDENTIFIER).NewTab + + + UIApplicationShortcutItemIconFile + privateSearch + UIApplicationShortcutItemTitle + New Private Tab + UIApplicationShortcutItemType + $(PRODUCT_BUNDLE_IDENTIFIER).NewPrivateTab + + + UIApplicationShortcutItemIconFile + menu-ScanQRCode + UIApplicationShortcutItemTitle + Scan QR Code + UIApplicationShortcutItemType + $(PRODUCT_BUNDLE_IDENTIFIER).QRCode + + + UIBackgroundModes + + fetch + processing + remote-notification + + UIFileSharingEnabled + + UIViewControllerBasedStatusBarAppearance + + UTImportedTypeDeclarations + + + UTTypeConformsTo + + public.url + + UTTypeDescription + 1Password Fill Browser Action + UTTypeIdentifier + org.appextension.fill-browser-action + UTTypeSize64IconFile + + + diff --git a/Client/Ecosia/Braze/APNConsent.swift b/Ecosia/Braze/APNConsent.swift similarity index 98% rename from Client/Ecosia/Braze/APNConsent.swift rename to Ecosia/Braze/APNConsent.swift index d7d8a827546a..e243cc607d9d 100644 --- a/Client/Ecosia/Braze/APNConsent.swift +++ b/Ecosia/Braze/APNConsent.swift @@ -4,6 +4,7 @@ import Foundation import Core +import Ecosia struct APNConsent { private init() {} diff --git a/Client/Ecosia/Braze/BrazeService.swift b/Ecosia/Braze/BrazeService.swift similarity index 82% rename from Client/Ecosia/Braze/BrazeService.swift rename to Ecosia/Braze/BrazeService.swift index d2d1dea81e38..be066fded89e 100644 --- a/Client/Ecosia/Braze/BrazeService.swift +++ b/Ecosia/Braze/BrazeService.swift @@ -6,6 +6,7 @@ import Foundation import BrazeKit import BrazeUI import Core +import NotificationCenter final class BrazeService: NSObject { override private init() {} @@ -14,16 +15,16 @@ final class BrazeService: NSObject { private var userId: String { User.shared.analyticsId.uuidString } - private(set) var notificationAuthorizationStatus: UNAuthorizationStatus? + public private(set) var notificationAuthorizationStatus: UNAuthorizationStatus? private static var apiKey = EnvironmentFetcher.valueFromMainBundleOrProcessInfo(forKey: "BRAZE_API_KEY") ?? "" - static let shared = BrazeService() + public static let shared = BrazeService() - enum Error: Swift.Error { + public enum Error: Swift.Error { case invalidConfiguration case generic(description: String) } - enum CustomEvent: String { + public enum CustomEvent: String { case newsletterCardClick = "newsletter_card_click" } @@ -36,14 +37,14 @@ final class BrazeService: NSObject { } } - func registerDeviceToken(_ deviceToken: Data) { + public func registerDeviceToken(_ deviceToken: Data) { braze?.notifications.register(deviceToken: deviceToken) Task.detached(priority: .medium) { [weak self] in await self?.updateID(self?.userId) } } - func logCustomEvent(_ event: CustomEvent) { + public func logCustomEvent(_ event: CustomEvent) { self.braze?.logCustomEvent(name: event.rawValue) } @@ -144,16 +145,16 @@ extension BrazeService { extension BrazeService: BrazeInAppMessageUIDelegate { - func inAppMessage(_ ui: BrazeInAppMessageUI, didPresent message: Braze.InAppMessage, view: any InAppMessageView) { - Analytics.shared.brazeIAM(action: .view, messageOrButtonId: message.id) + public func inAppMessage(_ ui: BrazeInAppMessageUI, didPresent message: Braze.InAppMessage, view: any InAppMessageView) { +// Analytics.shared.brazeIAM(action: .view, messageOrButtonId: message.id) } - func inAppMessage(_ ui: BrazeInAppMessageUI, didDismiss message: Braze.InAppMessage, view: any InAppMessageView) { - Analytics.shared.brazeIAM(action: .dismiss, messageOrButtonId: message.id) + public func inAppMessage(_ ui: BrazeInAppMessageUI, didDismiss message: Braze.InAppMessage, view: any InAppMessageView) { +// Analytics.shared.brazeIAM(action: .dismiss, messageOrButtonId: message.id) } - func inAppMessage(_ ui: BrazeInAppMessageUI, shouldProcess clickAction: Braze.InAppMessage.ClickAction, buttonId: String?, message: Braze.InAppMessage, view: any InAppMessageView) -> Bool { - Analytics.shared.brazeIAM(action: .click, messageOrButtonId: buttonId) + public func inAppMessage(_ ui: BrazeInAppMessageUI, shouldProcess clickAction: Braze.InAppMessage.ClickAction, buttonId: String?, message: Braze.InAppMessage, view: any InAppMessageView) -> Bool { +// Analytics.shared.brazeIAM(action: .click, messageOrButtonId: buttonId) return true } } diff --git a/Ecosia/Ecosia.h b/Ecosia/Ecosia.h new file mode 100644 index 000000000000..84cd6108c21b --- /dev/null +++ b/Ecosia/Ecosia.h @@ -0,0 +1,15 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +#import + +//! Project version number for Ecosia. +FOUNDATION_EXPORT double EcosiaVersionNumber; + +//! Project version string for Ecosia. +FOUNDATION_EXPORT const unsigned char EcosiaVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Ecosia/README.md b/Ecosia/README.md new file mode 100644 index 000000000000..b2dac358812b --- /dev/null +++ b/Ecosia/README.md @@ -0,0 +1,2 @@ +# Ecosia Framework + From 11dfbf9a25e8c8dfd109d2ea31120efbbf763ec4 Mon Sep 17 00:00:00 2001 From: Luca Schifino Date: Fri, 15 Nov 2024 16:48:21 +0100 Subject: [PATCH 08/59] [MOB-3028] Move Analytics and dependencies to Ecosia framework --- Client.xcodeproj/project.pbxproj | 143 ++++++++++++------ .../Browser/BrowserCoordinator.swift | 1 + .../Launch/LaunchCoordinator.swift | 1 + Client/Coordinators/Router/RouteBuilder.swift | 1 + .../Ecosia/Bookmarks/BookmarksExchange.swift | 1 + .../Unleash/SeedCounterNTPExperiment.swift | 1 + ...ppSettingsTableViewController+Ecosia.swift | 1 + .../BrowserViewController+Ecosia.swift | 1 + .../Ecosia/Settings/EcosiaDebugSettings.swift | 1 + Client/Ecosia/Settings/EcosiaSettings.swift | 1 + ...PCustomizationSettingsViewController.swift | 1 + Client/Ecosia/UI/EmptyBookmarksView.swift | 1 + Client/Ecosia/UI/LoadingScreen.swift | 1 + Client/Ecosia/UI/MarketsController.swift | 1 + .../UI/MultiplyImpact/MultiplyImpact.swift | 1 + .../NTP/AboutEcosia/AboutEcosiaSection.swift | 1 + .../NTP/AboutEcosia/NTPAboutEcosiaCell.swift | 1 + .../CustomizableNTPSettingConfig.swift | 1 + Client/Ecosia/UI/NTP/DefaultBrowser.swift | 1 + .../UI/NTP/Library/NTPLibraryCell.swift | 1 + .../UI/NTP/News/NTPNewsCellViewModel.swift | 1 + .../Ecosia/UI/NTP/News/NewsController.swift | 1 + .../NTPNewsletterCardViewModel.swift | 1 + Client/Ecosia/UI/Onboarding/Welcome.swift | 1 + .../UI/Onboarding/WelcomeTour.Step.swift | 1 + Client/Ecosia/UI/Onboarding/WelcomeTour.swift | 1 + .../WhatsNewLocalDataProvider.swift | 1 + .../Browser/MainMenuActionHelper.swift | 1 + Client/Frontend/Home/HomepageViewModel.swift | 1 + .../Home/TopSites/TopSitesViewModel.swift | 1 + .../Library/Bookmarks/BookmarksPanel.swift | 1 + .../Settings/Main/DefaultBrowserSetting.swift | 1 + .../SearchBarSettingsViewModel.swift | 1 + .../TabManagerImplementation.swift | 1 + .../TabManagement/TabMigrationUtility.swift | 1 + .../Analytics/Analytics+Configuration.swift | 2 +- .../Analytics/Analytics.Values.swift | 60 ++++---- .../Analytics/Analytics.swift | 58 +++---- .../AnalyticsNotificationSettings.swift | 0 Ecosia/Braze/APNConsent.swift | 14 +- Ecosia/Braze/BrazeService.swift | 6 +- .../APNConsentOnLaunchExperiment.swift | 45 ++++++ .../Unleash/BrazeIntegrationExperiment.swift | 0 .../Unleash/NewsletterCardExperiment.swift | 14 +- .../Extensions/AppInfo+Ecosia.swift | 2 +- .../AppVersionInfoProvider.swift | 2 +- .../DefaultAppVersionInfoProvider.swift | 6 +- .../EcosiaInstallType+Extensions.swift | 2 +- .../EcosiaInstallType/EcosiaInstallType.swift | 6 +- .../Helpers/Version/Version+Extensions.swift | 0 .../Helpers/Version/Version.swift | 12 +- 51 files changed, 273 insertions(+), 133 deletions(-) rename {Client/Ecosia => Ecosia}/Analytics/Analytics+Configuration.swift (98%) rename {Client/Ecosia => Ecosia}/Analytics/Analytics.Values.swift (78%) rename {Client/Ecosia => Ecosia}/Analytics/Analytics.swift (85%) rename {Client/Ecosia => Ecosia}/Analytics/AnalyticsNotificationSettings.swift (100%) create mode 100644 Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift rename {Client/Ecosia => Ecosia}/Experiments/Unleash/BrazeIntegrationExperiment.swift (100%) rename {Client/Ecosia => Ecosia}/Experiments/Unleash/NewsletterCardExperiment.swift (78%) rename {Client/Ecosia => Ecosia}/Extensions/AppInfo+Ecosia.swift (96%) rename {Client/Ecosia => Ecosia}/Helpers/AppInfoProvider/AppVersionInfoProvider.swift (86%) rename {Client/Ecosia => Ecosia}/Helpers/AppInfoProvider/DefaultAppVersionInfoProvider.swift (68%) rename {Client/Ecosia => Ecosia}/Helpers/EcosiaInstallType/EcosiaInstallType+Extensions.swift (90%) rename {Client/Ecosia => Ecosia}/Helpers/EcosiaInstallType/EcosiaInstallType.swift (93%) rename {Client/Ecosia => Ecosia}/Helpers/Version/Version+Extensions.swift (100%) rename {Client/Ecosia => Ecosia}/Helpers/Version/Version.swift (87%) diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index 32b319664a3d..2fd58071a344 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -29,7 +29,6 @@ 0BF1B7E31AC60DEA00A7B407 /* InsetButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF1B7E21AC60DEA00A7B407 /* InsetButton.swift */; }; 12147F2F2CDA3CD00009D300 /* NTPNewsletterCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F2E2CDA3CD00009D300 /* NTPNewsletterCardCell.swift */; }; 12147F312CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F302CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift */; }; - 12147F332CDBA7230009D300 /* NewsletterCardExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F322CDBA7230009D300 /* NewsletterCardExperiment.swift */; }; 122935742CE78D0A00EC1297 /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; 1229357C2CE78D0A00EC1297 /* Ecosia.h in Headers */ = {isa = PBXBuildFile; fileRef = 1229356C2CE78D0A00EC1297 /* Ecosia.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1229357F2CE78D0A00EC1297 /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; @@ -39,10 +38,26 @@ 122935912CE78ED500EC1297 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 122935902CE78ED500EC1297 /* BrazeKit */; }; 122935932CE78ED500EC1297 /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 122935922CE78ED500EC1297 /* BrazeUI */; }; 1229359C2CE7927900EC1297 /* BrazeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1229359B2CE7927800EC1297 /* BrazeService.swift */; }; + 1229359E2CE79A2600EC1297 /* Analytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892E2B7A8A22006B70D7 /* Analytics.swift */; }; + 1229359F2CE79A2800EC1297 /* Analytics+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892F2B7A8A22006B70D7 /* Analytics+Configuration.swift */; }; + 122935A02CE79A3100EC1297 /* Analytics.Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189302B7A8A22006B70D7 /* Analytics.Values.swift */; }; + 122935A22CE79A9400EC1297 /* EcosiaInstallType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189282B7A8A22006B70D7 /* EcosiaInstallType.swift */; }; + 122935A42CE79A9A00EC1297 /* EcosiaInstallType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189292B7A8A22006B70D7 /* EcosiaInstallType+Extensions.swift */; }; + 122935A52CE79AF400EC1297 /* DefaultAppVersionInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189252B7A8A22006B70D7 /* DefaultAppVersionInfoProvider.swift */; }; + 122935A62CE79AF800EC1297 /* AppVersionInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189262B7A8A22006B70D7 /* AppVersionInfoProvider.swift */; }; + 122935A72CE79B0400EC1297 /* Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892B2B7A8A22006B70D7 /* Version.swift */; }; + 122935A82CE79B0800EC1297 /* Version+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892C2B7A8A22006B70D7 /* Version+Extensions.swift */; }; + 122935A92CE79CC800EC1297 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; }; + 122935AB2CE79D6F00EC1297 /* AppInfo+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189092B7A8A22006B70D7 /* AppInfo+Ecosia.swift */; }; + 122935AC2CE79DA200EC1297 /* BrazeIntegrationExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188F82B7A8A22006B70D7 /* BrazeIntegrationExperiment.swift */; }; + 122935AE2CE79DA900EC1297 /* APNConsentOnLaunchExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E2B62CC68BF00053506B /* APNConsentOnLaunchExperiment.swift */; }; + 122935AF2CE79DAD00EC1297 /* OnboardingRemoveExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CFE600B2CD3AAB6001F35D2 /* OnboardingRemoveExperiment.swift */; }; + 122935B02CE79DB100EC1297 /* NewsletterCardExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F322CDBA7230009D300 /* NewsletterCardExperiment.swift */; }; + 122935B32CE79E2400EC1297 /* SeedCounterNTPExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6B5B402CAAF3AA00F15323 /* SeedCounterNTPExperiment.swift */; }; + 122935B52CE79EF900EC1297 /* SnowplowTracker in Frameworks */ = {isa = PBXBuildFile; productRef = 122935B42CE79EF900EC1297 /* SnowplowTracker */; }; 126509852CD925B40011BA36 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 126509842CD925B40011BA36 /* BrazeKit */; }; 126509872CD925B40011BA36 /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 126509862CD925B40011BA36 /* BrazeUI */; }; 1285E2B52CC293CA0053506B /* AnalyticsSpyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E2B42CC293CA0053506B /* AnalyticsSpyTests.swift */; }; - 1285E2B72CC68BF00053506B /* APNConsentOnLaunchExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E2B62CC68BF00053506B /* APNConsentOnLaunchExperiment.swift */; }; 158241282820698B00956B39 /* RustRemoteTabsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 158241272820698B00956B39 /* RustRemoteTabsTests.swift */; }; 15DE98FD27FCED4F00F1ECDB /* RustRemoteTabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15DE98FC27FCED4F00F1ECDB /* RustRemoteTabs.swift */; }; 1B3D99F1270E89D0006E1264 /* Telemetry in Frameworks */ = {isa = PBXBuildFile; productRef = 1B3D99F0270E89D0006E1264 /* Telemetry */; }; @@ -300,7 +315,6 @@ 2C61897E2B7A8A22006B70D7 /* FeatureManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188EE2B7A8A22006B70D7 /* FeatureManagement.swift */; }; 2C61897F2B7A8A22006B70D7 /* EcosiaHomepageSectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188F12B7A8A22006B70D7 /* EcosiaHomepageSectionType.swift */; }; 2C6189802B7A8A22006B70D7 /* EcosiaTopSiteItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188F42B7A8A22006B70D7 /* EcosiaTopSiteItemCell.swift */; }; - 2C6189822B7A8A22006B70D7 /* BrazeIntegrationExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188F82B7A8A22006B70D7 /* BrazeIntegrationExperiment.swift */; }; 2C6189842B7A8A22006B70D7 /* WebsiteConnectionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188FB2B7A8A22006B70D7 /* WebsiteConnectionStatus.swift */; }; 2C6189862B7A8A22006B70D7 /* BrowserViewController+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189002B7A8A22006B70D7 /* BrowserViewController+Ecosia.swift */; }; 2C6189872B7A8A22006B70D7 /* LegacyThemeManager+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189012B7A8A22006B70D7 /* LegacyThemeManager+Ecosia.swift */; }; @@ -311,7 +325,6 @@ 2C61898C2B7A8A22006B70D7 /* HomepageViewController+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189062B7A8A22006B70D7 /* HomepageViewController+Ecosia.swift */; }; 2C61898D2B7A8A22006B70D7 /* SimpleToast+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189072B7A8A22006B70D7 /* SimpleToast+Ecosia.swift */; }; 2C61898E2B7A8A22006B70D7 /* UIView+maskedCorners.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189082B7A8A22006B70D7 /* UIView+maskedCorners.swift */; }; - 2C61898F2B7A8A22006B70D7 /* AppInfo+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189092B7A8A22006B70D7 /* AppInfo+Ecosia.swift */; }; 2C6189902B7A8A22006B70D7 /* NumberFormatter+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61890A2B7A8A22006B70D7 /* NumberFormatter+Ecosia.swift */; }; 2C6189912B7A8A22006B70D7 /* URL+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61890B2B7A8A22006B70D7 /* URL+Ecosia.swift */; }; 2C6189922B7A8A22006B70D7 /* BrowserCoordinator+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61890C2B7A8A22006B70D7 /* BrowserCoordinator+Ecosia.swift */; }; @@ -321,15 +334,6 @@ 2C6189972B7A8A22006B70D7 /* ConnectionStatusImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189122B7A8A22006B70D7 /* ConnectionStatusImage.swift */; }; 2C6189982B7A8A22006B70D7 /* BookmarksExchange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189172B7A8A22006B70D7 /* BookmarksExchange.swift */; }; 2C6189992B7A8A22006B70D7 /* markets.json in Resources */ = {isa = PBXBuildFile; fileRef = 2C6189182B7A8A22006B70D7 /* markets.json */; }; - 2C6189A22B7A8A22006B70D7 /* DefaultAppVersionInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189252B7A8A22006B70D7 /* DefaultAppVersionInfoProvider.swift */; }; - 2C6189A32B7A8A22006B70D7 /* AppVersionInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189262B7A8A22006B70D7 /* AppVersionInfoProvider.swift */; }; - 2C6189A42B7A8A22006B70D7 /* EcosiaInstallType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189282B7A8A22006B70D7 /* EcosiaInstallType.swift */; }; - 2C6189A52B7A8A22006B70D7 /* EcosiaInstallType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189292B7A8A22006B70D7 /* EcosiaInstallType+Extensions.swift */; }; - 2C6189A62B7A8A22006B70D7 /* Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892B2B7A8A22006B70D7 /* Version.swift */; }; - 2C6189A72B7A8A22006B70D7 /* Version+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892C2B7A8A22006B70D7 /* Version+Extensions.swift */; }; - 2C6189A82B7A8A22006B70D7 /* Analytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892E2B7A8A22006B70D7 /* Analytics.swift */; }; - 2C6189A92B7A8A22006B70D7 /* Analytics+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892F2B7A8A22006B70D7 /* Analytics+Configuration.swift */; }; - 2C6189AA2B7A8A22006B70D7 /* Analytics.Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189302B7A8A22006B70D7 /* Analytics.Values.swift */; }; 2C6189D12B7A8D3E006B70D7 /* EcosiaThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C32B7A8A22006B70D7 /* EcosiaThemeManager.swift */; }; 2C6189D22B7A8D69006B70D7 /* EcosiaThemeColourPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C42B7A8A22006B70D7 /* EcosiaThemeColourPalette.swift */; }; 2C6189DD2B7B7776006B70D7 /* AppInfo+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189092B7A8A22006B70D7 /* AppInfo+Ecosia.swift */; }; @@ -364,7 +368,6 @@ 2C69DA942C63B0C000D7F69F /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C69DA932C63B0C000D7F69F /* String+Extension.swift */; }; 2C6B5B3E2CAAF28000F15323 /* NTPSeedCounterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6B5B3A2CAAF27F00F15323 /* NTPSeedCounterCell.swift */; }; 2C6B5B3F2CAAF28000F15323 /* NTPSeedCounterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6B5B3B2CAAF27F00F15323 /* NTPSeedCounterViewModel.swift */; }; - 2C6B5B412CAAF3AA00F15323 /* SeedCounterNTPExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6B5B402CAAF3AA00F15323 /* SeedCounterNTPExperiment.swift */; }; 2C6C908F2C614A6C007D9B43 /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 2C6C908E2C614A6C007D9B43 /* SnapshotTesting */; }; 2C6C90902C614A76007D9B43 /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD368492C5BC31700972871 /* OnboardingTests.swift */; }; 2C728D7E2CBBDCDC00C7684B /* UnleashUserDefaultsSeedProgressManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C728D7D2CBBDCDC00C7684B /* UnleashUserDefaultsSeedProgressManagerTests.swift */; }; @@ -7793,6 +7796,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 122935A92CE79CC800EC1297 /* Shared.framework in Frameworks */, + 122935B52CE79EF900EC1297 /* SnowplowTracker in Frameworks */, 122935932CE78ED500EC1297 /* BrazeUI in Frameworks */, 122935912CE78ED500EC1297 /* BrazeKit in Frameworks */, 1229358F2CE78EC400EC1297 /* Core in Frameworks */, @@ -8028,7 +8033,11 @@ 1229356B2CE78D0A00EC1297 /* Ecosia */ = { isa = PBXGroup; children = ( + 2C61892D2B7A8A22006B70D7 /* Analytics */, 122935962CE7913100EC1297 /* Braze */, + 2C6188F52B7A8A22006B70D7 /* Experiments */, + 122935AA2CE79D4E00EC1297 /* Extensions */, + 122935A12CE79A8600EC1297 /* Helpers */, 1229356C2CE78D0A00EC1297 /* Ecosia.h */, 1229359D2CE792B700EC1297 /* README.md */, ); @@ -8051,6 +8060,49 @@ path = Braze; sourceTree = ""; }; + 122935A12CE79A8600EC1297 /* Helpers */ = { + isa = PBXGroup; + children = ( + 2C6189242B7A8A22006B70D7 /* AppInfoProvider */, + 2C6189272B7A8A22006B70D7 /* EcosiaInstallType */, + 2C61892A2B7A8A22006B70D7 /* Version */, + ); + path = Helpers; + sourceTree = ""; + }; + 122935AA2CE79D4E00EC1297 /* Extensions */ = { + isa = PBXGroup; + children = ( + 2C6189092B7A8A22006B70D7 /* AppInfo+Ecosia.swift */, + ); + path = Extensions; + sourceTree = ""; + }; + 122935B12CE79DFB00EC1297 /* Experiments */ = { + isa = PBXGroup; + children = ( + 122935B22CE79E0D00EC1297 /* Unleash */, + ); + path = Experiments; + sourceTree = ""; + }; + 122935B22CE79E0D00EC1297 /* Unleash */ = { + isa = PBXGroup; + children = ( + 2C6B5B402CAAF3AA00F15323 /* SeedCounterNTPExperiment.swift */, + ); + path = Unleash; + sourceTree = ""; + }; + 1285E2B32CC293A20053506B /* Analytics */ = { + isa = PBXGroup; + children = ( + 2CE294692B7FC5A5006C22B2 /* AnalyticsTests.swift */, + 1285E2B42CC293CA0053506B /* AnalyticsSpyTests.swift */, + ); + path = Analytics; + sourceTree = ""; + }; 1D7B78952ADF324E0011E9F2 /* Event Queue */ = { isa = PBXGroup; children = ( @@ -8494,16 +8546,14 @@ 2C6188DA2B7A8A22006B70D7 /* L10N */, 2C6188ED2B7A8A22006B70D7 /* FeatureManagement */, 2C6188EF2B7A8A22006B70D7 /* Frontend */, - 2C6188F52B7A8A22006B70D7 /* Experiments */, 2C6188FA2B7A8A22006B70D7 /* Network */, 2C6188FC2B7A8A22006B70D7 /* BrowserKitExtensions */, + 122935B12CE79DFB00EC1297 /* Experiments */, 2C6188FF2B7A8A22006B70D7 /* Extensions */, 2C6189132B7A8A22006B70D7 /* Entitlements */, 2C6189162B7A8A22006B70D7 /* Bookmarks */, 2C6189182B7A8A22006B70D7 /* markets.json */, 2C6189192B7A8A22006B70D7 /* Fake */, - 2C6189232B7A8A22006B70D7 /* Helpers */, - 2C61892D2B7A8A22006B70D7 /* Analytics */, ); path = Ecosia; sourceTree = ""; @@ -8780,9 +8830,10 @@ 2C6188F62B7A8A22006B70D7 /* Unleash */ = { isa = PBXGroup; children = ( + 1285E2B62CC68BF00053506B /* APNConsentOnLaunchExperiment.swift */, 2C6188F82B7A8A22006B70D7 /* BrazeIntegrationExperiment.swift */, - 2C6B5B402CAAF3AA00F15323 /* SeedCounterNTPExperiment.swift */, 12147F322CDBA7230009D300 /* NewsletterCardExperiment.swift */, + 2CFE600B2CD3AAB6001F35D2 /* OnboardingRemoveExperiment.swift */, ); path = Unleash; sourceTree = ""; @@ -8814,7 +8865,6 @@ 2C6189062B7A8A22006B70D7 /* HomepageViewController+Ecosia.swift */, 2C6189072B7A8A22006B70D7 /* SimpleToast+Ecosia.swift */, 2C6189082B7A8A22006B70D7 /* UIView+maskedCorners.swift */, - 2C6189092B7A8A22006B70D7 /* AppInfo+Ecosia.swift */, 2C61890A2B7A8A22006B70D7 /* NumberFormatter+Ecosia.swift */, 2C61890B2B7A8A22006B70D7 /* URL+Ecosia.swift */, 2C61890C2B7A8A22006B70D7 /* BrowserCoordinator+Ecosia.swift */, @@ -8863,16 +8913,6 @@ path = Fake; sourceTree = ""; }; - 2C6189232B7A8A22006B70D7 /* Helpers */ = { - isa = PBXGroup; - children = ( - 2C6189242B7A8A22006B70D7 /* AppInfoProvider */, - 2C6189272B7A8A22006B70D7 /* EcosiaInstallType */, - 2C61892A2B7A8A22006B70D7 /* Version */, - ); - path = Helpers; - sourceTree = ""; - }; 2C6189242B7A8A22006B70D7 /* AppInfoProvider */ = { isa = PBXGroup; children = ( @@ -12450,6 +12490,7 @@ 1229358E2CE78EC400EC1297 /* Core */, 122935902CE78ED500EC1297 /* BrazeKit */, 122935922CE78ED500EC1297 /* BrazeUI */, + 122935B42CE79EF900EC1297 /* SnowplowTracker */, ); productName = Ecosia; productReference = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; @@ -13509,7 +13550,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 122935A22CE79A9400EC1297 /* EcosiaInstallType.swift in Sources */, + 122935B02CE79DB100EC1297 /* NewsletterCardExperiment.swift in Sources */, + 122935A72CE79B0400EC1297 /* Version.swift in Sources */, + 122935A82CE79B0800EC1297 /* Version+Extensions.swift in Sources */, + 1229359E2CE79A2600EC1297 /* Analytics.swift in Sources */, + 122935AC2CE79DA200EC1297 /* BrazeIntegrationExperiment.swift in Sources */, + 122935AE2CE79DA900EC1297 /* APNConsentOnLaunchExperiment.swift in Sources */, + 122935AF2CE79DAD00EC1297 /* OnboardingRemoveExperiment.swift in Sources */, + 122935A52CE79AF400EC1297 /* DefaultAppVersionInfoProvider.swift in Sources */, + 1229359F2CE79A2800EC1297 /* Analytics+Configuration.swift in Sources */, 1229359C2CE7927900EC1297 /* BrazeService.swift in Sources */, + 122935A62CE79AF800EC1297 /* AppVersionInfoProvider.swift in Sources */, + 122935A02CE79A3100EC1297 /* Analytics.Values.swift in Sources */, + 122935A42CE79A9A00EC1297 /* EcosiaInstallType+Extensions.swift in Sources */, + 122935AB2CE79D6F00EC1297 /* AppInfo+Ecosia.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -13829,10 +13884,8 @@ 8A19ACB02A329078001C2147 /* AutofillCreditCardSettings.swift in Sources */, 2C61895D2B7A8A22006B70D7 /* NTPImpactRowView.swift in Sources */, E1E5BE252A28F7BE00248F77 /* PasswordDetailViewControllerModel.swift in Sources */, - 12147F332CDBA7230009D300 /* NewsletterCardExperiment.swift in Sources */, E1FE133129C22726002A65FF /* BackgroundFetchAndProcessingUtility.swift in Sources */, 8AD40FD527BB1C1000672675 /* LockButton.swift in Sources */, - 2C61898F2B7A8A22006B70D7 /* AppInfo+Ecosia.swift in Sources */, 5F130D2E2483508E00B0F7D0 /* FxAWebViewModel.swift in Sources */, 2109478928AFD24C00B73D44 /* OnboardingViewControllerProtocol.swift in Sources */, D0FCF7F51FE45842004A7995 /* UserScriptManager.swift in Sources */, @@ -13945,7 +13998,6 @@ FA6B2AC21D41F02D00429414 /* String+Punycode.swift in Sources */, E174963C2992B6A60096900A /* HostingTableViewSectionHeader.swift in Sources */, 8A471185287F6E4800F5A6EA /* SeparatorTableViewCell.swift in Sources */, - 2C6B5B412CAAF3AA00F15323 /* SeedCounterNTPExperiment.swift in Sources */, D301AAEE1A3A55B70078DD1D /* LegacyGridTabViewController.swift in Sources */, EB9A179B20E69A7F00B12184 /* LegacyThemeManager.swift in Sources */, EBFDB790211C83A5005CCA2F /* BrowserViewController+FindInPage.swift in Sources */, @@ -13970,7 +14022,6 @@ E1442FC2294782C3003680B0 /* NSAttributedString+Extension.swift in Sources */, 967A028E28FA026F003C35E3 /* SceneDelegate.swift in Sources */, 810FF3562B1783B0009F062C /* FeltPrivacyManager.swift in Sources */, - 2C6189A32B7A8A22006B70D7 /* AppVersionInfoProvider.swift in Sources */, C8B07A4128199500000AFCE7 /* NimbusFlaggableFeature.swift in Sources */, 0B62EFD21AD63CD100ACB9CD /* Clearables.swift in Sources */, 431C0CA925C890E500395CE4 /* DefaultBrowserOnboardingViewModel.swift in Sources */, @@ -13994,7 +14045,6 @@ E1442FD8294782D9003680B0 /* UIPasteboard+Extension.swift in Sources */, C8A4137428BE58C900D8EFEA /* WallpaperMetadataCodableProtocol.swift in Sources */, 8A93080927BFE88F0052167D /* PhotonActionSheetContainerCell.swift in Sources */, - 2C6189A52B7A8A22006B70D7 /* EcosiaInstallType+Extensions.swift in Sources */, C8B41E0A29F0284B00FE218A /* NimbusOnboardingFeatureLayer.swift in Sources */, BD4B2DE229BB4CD9005FAA50 /* SnackButton.swift in Sources */, F85C7F0E2711C556004BDBA4 /* SettingsViewController.swift in Sources */, @@ -14014,7 +14064,6 @@ D314E7F71A37B98700426A76 /* TabToolbar.swift in Sources */, 43D00493296FC48F00CB0F31 /* CreditCardSettingsEmptyView.swift in Sources */, 2C61896D2B7A8A22006B70D7 /* WelcomeTour.Step.swift in Sources */, - 2C6189A82B7A8A22006B70D7 /* Analytics.swift in Sources */, 2CCBB5252CAEA9DF006E2E10 /* SeedProgressView.swift in Sources */, CEFA977E1FAA6B490016F365 /* SyncContentSettingsViewController.swift in Sources */, C8CD80DC2A1E8C970097C3AE /* OnboardingTelemetryUtility.swift in Sources */, @@ -14059,7 +14108,6 @@ 8A2783F1275FFDC50080D29D /* KeyboardPressesHandler.swift in Sources */, E650755C1E37F747006961AC /* Swizzling.m in Sources */, 74821FC51DB56A2500EEEA72 /* OpenWithSettingsViewController.swift in Sources */, - 1285E2B72CC68BF00053506B /* APNConsent.swift in Sources */, C84656012887A0F700861B4A /* WallpaperMetadataUtility.swift in Sources */, E1B04A9D28E20A8300670E54 /* InstructionsView.swift in Sources */, D3B6923D1B9F9444004B87A4 /* FindInPageBar.swift in Sources */, @@ -14087,7 +14135,6 @@ CA90753824929B22005B794D /* NoLoginsView.swift in Sources */, E4B423BE1AB9FE6A007E66C8 /* ReaderModeCache.swift in Sources */, 396CDB55203C5B870034A3A3 /* TabTrayController+KeyCommands.swift in Sources */, - 2C6189AA2B7A8A22006B70D7 /* Analytics.Values.swift in Sources */, C855728629AEA3FB00AF32B0 /* SurveySurfaceViewController.swift in Sources */, 74E36D781B71323500D69DA1 /* SettingsContentViewController.swift in Sources */, EBB8950C21939E4100EB91A0 /* FirefoxTabContentBlocker.swift in Sources */, @@ -14128,7 +14175,6 @@ 9614BF4428AD1C6700D3F7EA /* AccountSyncHandler.swift in Sources */, 282DA4731A68C1E700A406E2 /* OpenSearchParser.swift in Sources */, 8A13FA8D2AD834FA007527AB /* BackgroundTabLoader.swift in Sources */, - 2C6189822B7A8A22006B70D7 /* BrazeIntegrationExperiment.swift in Sources */, D04CD74B216CF86B004FF5B0 /* DevicePickerViewController.swift in Sources */, 2C61896B2B7A8A22006B70D7 /* WelcomeTourRow.swift in Sources */, C8DC90BD2A06699E0008832B /* MarkupNode.swift in Sources */, @@ -14168,7 +14214,6 @@ 8ADC2A122A3375B900543DAA /* FxAEntryPoint.swift in Sources */, 12147F312CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift in Sources */, 216A0D7B2A40F08B008077BA /* ThemeSettingsAction.swift in Sources */, - 2C6189A22B7A8A22006B70D7 /* DefaultAppVersionInfoProvider.swift in Sources */, C2506C932A6A863600F2B76E /* HistoryCoordinator.swift in Sources */, 8A3EF8012A2FCFC900796E3A /* FasterInactiveTabs.swift in Sources */, CA7FC7D324A6A9B70012F347 /* PasswordManagerDataSourceHelper.swift in Sources */, @@ -14290,7 +14335,6 @@ E47616C71AB74CA600E7DD25 /* ReaderModeBarView.swift in Sources */, D821E90E2141B71C00452C55 /* SiriSettingsViewController.swift in Sources */, EBB89507219398E500EB91A0 /* ContentBlocker.swift in Sources */, - 2C6189A42B7A8A22006B70D7 /* EcosiaInstallType.swift in Sources */, 216A0D792A40E85A008077BA /* ThemeSettingsState.swift in Sources */, 5A3A2A0D287F742C00B79EAC /* BackgroundSyncUtility.swift in Sources */, 21AFCFEE2AE80B700027E9CE /* TabsCoordinator.swift in Sources */, @@ -14456,7 +14500,6 @@ 9636D92C27F9E50100771F5E /* GleanPlumbMessageStore.swift in Sources */, 213B67A627CE682B000542F5 /* StartAtHomeHelper.swift in Sources */, E10A1F752863BC51001EEA80 /* LegacyInactiveTabItemCell.swift in Sources */, - 2C6189A72B7A8A22006B70D7 /* Version+Extensions.swift in Sources */, 8A8629E2288096C40096DDB1 /* BookmarksFolderCell.swift in Sources */, DAE6DF1B29AD78DA0094BD1B /* BrowserViewController+ZoomPage.swift in Sources */, 8AB8574A27D97CE90075C173 /* HomePanelDelegate.swift in Sources */, @@ -14527,7 +14570,6 @@ C2D71B992A384F6A003DEC7A /* ThemedLeftAlignedTableViewCell.swift in Sources */, 21A7C44E283539170071D996 /* IntroViewModel.swift in Sources */, E1FF93E228A2E55700E6360E /* WallpaperSelectorViewController.swift in Sources */, - 2C6189A92B7A8A22006B70D7 /* Analytics+Configuration.swift in Sources */, D3A9949C1A3686BD008AD1AC /* BrowserViewController.swift in Sources */, 8A5D1CBB2A30DC0B005AD35C /* ConnectSetting.swift in Sources */, E6CF28E71CB43B7900151AB3 /* SensitiveViewController.swift in Sources */, @@ -14570,6 +14612,7 @@ BD4B2DE429BB4D9A005FAA50 /* TimerSnackBar.swift in Sources */, 810FF3582B1784E7009F062C /* PrivateModeAction.swift in Sources */, 21EA466A2B04130500AAAB2D /* TabsPanelState.swift in Sources */, + 122935B32CE79E2400EC1297 /* SeedCounterNTPExperiment.swift in Sources */, D04D1B862097859B0074B35F /* DownloadToast.swift in Sources */, C29B64EE2AD937D500F3244B /* QRCodeNavigationHandler.swift in Sources */, 8A19ACB42A3290D9001C2147 /* ContentBlockerSetting.swift in Sources */, @@ -14584,7 +14627,6 @@ 7B844E3D1BBDDB9D00E733A2 /* ChevronView.swift in Sources */, 43A5643823CD1E1C00B6857D /* UpdateViewController.swift in Sources */, 437A9B682681256800FB41C1 /* LegacyInactiveTabCell.swift in Sources */, - 2C6189A62B7A8A22006B70D7 /* Version.swift in Sources */, 1D69FF8D27B17286001F660E /* HomeLogoHeaderCell.swift in Sources */, E4C358551AF144BA00299F7E /* FSReadingList.m in Sources */, 8AE1E1CB27B18F560024C45E /* SearchBarSettingsViewController.swift in Sources */, @@ -19822,7 +19864,7 @@ INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -19924,7 +19966,7 @@ INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -20023,7 +20065,7 @@ INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -20127,7 +20169,7 @@ INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -20232,7 +20274,7 @@ INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -22676,6 +22718,11 @@ package = 126509832CD925B30011BA36 /* XCRemoteSwiftPackageReference "braze-swift-sdk" */; productName = BrazeUI; }; + 122935B42CE79EF900EC1297 /* SnowplowTracker */ = { + isa = XCSwiftPackageProductDependency; + package = 2C6189EF2B7B7D48006B70D7 /* XCRemoteSwiftPackageReference "snowplow-ios-tracker" */; + productName = SnowplowTracker; + }; 126509842CD925B40011BA36 /* BrazeKit */ = { isa = XCSwiftPackageProductDependency; package = 126509832CD925B30011BA36 /* XCRemoteSwiftPackageReference "braze-swift-sdk" */; diff --git a/Client/Coordinators/Browser/BrowserCoordinator.swift b/Client/Coordinators/Browser/BrowserCoordinator.swift index 0b3336e35dd2..5ac413853e5f 100644 --- a/Client/Coordinators/Browser/BrowserCoordinator.swift +++ b/Client/Coordinators/Browser/BrowserCoordinator.swift @@ -11,6 +11,7 @@ import Redux import TabDataStore // Ecosia: Import Core import Core +import Ecosia class BrowserCoordinator: BaseCoordinator, LaunchCoordinatorDelegate, diff --git a/Client/Coordinators/Launch/LaunchCoordinator.swift b/Client/Coordinators/Launch/LaunchCoordinator.swift index bdb1121b295d..b66b7b7bd06e 100644 --- a/Client/Coordinators/Launch/LaunchCoordinator.swift +++ b/Client/Coordinators/Launch/LaunchCoordinator.swift @@ -4,6 +4,7 @@ import Common import Foundation +import Ecosia protocol LaunchCoordinatorDelegate: AnyObject { func didFinishLaunch(from coordinator: LaunchCoordinator) diff --git a/Client/Coordinators/Router/RouteBuilder.swift b/Client/Coordinators/Router/RouteBuilder.swift index eedbe4749b5c..cd85ae3a66dd 100644 --- a/Client/Coordinators/Router/RouteBuilder.swift +++ b/Client/Coordinators/Router/RouteBuilder.swift @@ -5,6 +5,7 @@ import Foundation import CoreSpotlight import Shared +import Ecosia final class RouteBuilder { private var isPrivate = false diff --git a/Client/Ecosia/Bookmarks/BookmarksExchange.swift b/Client/Ecosia/Bookmarks/BookmarksExchange.swift index e8ef1de5c92b..7e5d71377f5f 100644 --- a/Client/Ecosia/Bookmarks/BookmarksExchange.swift +++ b/Client/Ecosia/Bookmarks/BookmarksExchange.swift @@ -6,6 +6,7 @@ import Foundation import Core import Shared import Storage +import Ecosia protocol BookmarksExchangable { func export(bookmarks: [Core.BookmarkItem], in viewController: UIViewController, barButtonItem: UIBarButtonItem) async throws diff --git a/Client/Ecosia/Experiments/Unleash/SeedCounterNTPExperiment.swift b/Client/Ecosia/Experiments/Unleash/SeedCounterNTPExperiment.swift index 15d73761dbcd..e1d429d8b8c7 100644 --- a/Client/Ecosia/Experiments/Unleash/SeedCounterNTPExperiment.swift +++ b/Client/Ecosia/Experiments/Unleash/SeedCounterNTPExperiment.swift @@ -4,6 +4,7 @@ import Foundation import Core +import Ecosia struct SeedCounterNTPExperiment { private enum Variant: String { diff --git a/Client/Ecosia/Extensions/AppSettingsTableViewController+Ecosia.swift b/Client/Ecosia/Extensions/AppSettingsTableViewController+Ecosia.swift index 4331fb567ed0..0623b91cb5ef 100644 --- a/Client/Ecosia/Extensions/AppSettingsTableViewController+Ecosia.swift +++ b/Client/Ecosia/Extensions/AppSettingsTableViewController+Ecosia.swift @@ -5,6 +5,7 @@ import Common import UIKit import Shared +import Ecosia extension AppSettingsTableViewController { diff --git a/Client/Ecosia/Extensions/BrowserViewController+Ecosia.swift b/Client/Ecosia/Extensions/BrowserViewController+Ecosia.swift index c44379ff1c52..48186962cab2 100644 --- a/Client/Ecosia/Extensions/BrowserViewController+Ecosia.swift +++ b/Client/Ecosia/Extensions/BrowserViewController+Ecosia.swift @@ -5,6 +5,7 @@ import UIKit import Core import Shared +import Ecosia extension BrowserViewController: HomepageViewControllerDelegate { func homeDidTapSearchButton(_ home: HomepageViewController) { diff --git a/Client/Ecosia/Settings/EcosiaDebugSettings.swift b/Client/Ecosia/Settings/EcosiaDebugSettings.swift index db2e24abff52..8601c3be551d 100644 --- a/Client/Ecosia/Settings/EcosiaDebugSettings.swift +++ b/Client/Ecosia/Settings/EcosiaDebugSettings.swift @@ -7,6 +7,7 @@ import UIKit import Core import Shared import Common +import Ecosia final class PushBackInstallation: HiddenSetting { override var title: NSAttributedString? { diff --git a/Client/Ecosia/Settings/EcosiaSettings.swift b/Client/Ecosia/Settings/EcosiaSettings.swift index 384453d591b9..b6d53ca087c0 100644 --- a/Client/Ecosia/Settings/EcosiaSettings.swift +++ b/Client/Ecosia/Settings/EcosiaSettings.swift @@ -6,6 +6,7 @@ import Foundation import Core import Shared import Common +import Ecosia var ecosiaDisclosureIndicator: UIImageView { let config = UIImage.SymbolConfiguration(pointSize: 16) diff --git a/Client/Ecosia/Settings/NTPCustomizationSettingsViewController.swift b/Client/Ecosia/Settings/NTPCustomizationSettingsViewController.swift index 1cb207094a6c..187884fd166c 100644 --- a/Client/Ecosia/Settings/NTPCustomizationSettingsViewController.swift +++ b/Client/Ecosia/Settings/NTPCustomizationSettingsViewController.swift @@ -5,6 +5,7 @@ import Foundation import Shared import Common +import Ecosia final class NTPCustomizationSettingsViewController: SettingsTableViewController { init() { diff --git a/Client/Ecosia/UI/EmptyBookmarksView.swift b/Client/Ecosia/UI/EmptyBookmarksView.swift index ff9ba0cfcf32..cd00c309d5a8 100644 --- a/Client/Ecosia/UI/EmptyBookmarksView.swift +++ b/Client/Ecosia/UI/EmptyBookmarksView.swift @@ -4,6 +4,7 @@ import UIKit import Common +import Ecosia final class EmptyBookmarksView: UIView, Themeable { diff --git a/Client/Ecosia/UI/LoadingScreen.swift b/Client/Ecosia/UI/LoadingScreen.swift index 63f5d4a8d8aa..a87a04bd1329 100644 --- a/Client/Ecosia/UI/LoadingScreen.swift +++ b/Client/Ecosia/UI/LoadingScreen.swift @@ -4,6 +4,7 @@ import UIKit import Core +import Ecosia final class LoadingScreen: UIViewController { private weak var profile: Profile! diff --git a/Client/Ecosia/UI/MarketsController.swift b/Client/Ecosia/UI/MarketsController.swift index cf1f2bb1eb1b..9962a25f3ef7 100644 --- a/Client/Ecosia/UI/MarketsController.swift +++ b/Client/Ecosia/UI/MarketsController.swift @@ -5,6 +5,7 @@ import Core import UIKit import Common +import Ecosia final class Markets { private(set) static var all: [Market] = { diff --git a/Client/Ecosia/UI/MultiplyImpact/MultiplyImpact.swift b/Client/Ecosia/UI/MultiplyImpact/MultiplyImpact.swift index 37ffb6e5c2cb..a5e5c7d55b58 100644 --- a/Client/Ecosia/UI/MultiplyImpact/MultiplyImpact.swift +++ b/Client/Ecosia/UI/MultiplyImpact/MultiplyImpact.swift @@ -8,6 +8,7 @@ import UniformTypeIdentifiers import MobileCoreServices import LinkPresentation import Common +import Ecosia class MultiplyImpact: UIViewController, Themeable { diff --git a/Client/Ecosia/UI/NTP/AboutEcosia/AboutEcosiaSection.swift b/Client/Ecosia/UI/NTP/AboutEcosia/AboutEcosiaSection.swift index a9cde8ee00b6..e78abdf1e492 100644 --- a/Client/Ecosia/UI/NTP/AboutEcosia/AboutEcosiaSection.swift +++ b/Client/Ecosia/UI/NTP/AboutEcosia/AboutEcosiaSection.swift @@ -4,6 +4,7 @@ import Foundation import Core +import Ecosia enum AboutEcosiaSection: Int, CaseIterable { case diff --git a/Client/Ecosia/UI/NTP/AboutEcosia/NTPAboutEcosiaCell.swift b/Client/Ecosia/UI/NTP/AboutEcosia/NTPAboutEcosiaCell.swift index f0bfb32996ec..9e0ced1d4c86 100644 --- a/Client/Ecosia/UI/NTP/AboutEcosia/NTPAboutEcosiaCell.swift +++ b/Client/Ecosia/UI/NTP/AboutEcosia/NTPAboutEcosiaCell.swift @@ -4,6 +4,7 @@ import Foundation import Common +import Ecosia final class NTPAboutEcosiaCell: UICollectionViewCell, ReusableCell { struct UX { diff --git a/Client/Ecosia/UI/NTP/Customization/CustomizableNTPSettingConfig.swift b/Client/Ecosia/UI/NTP/Customization/CustomizableNTPSettingConfig.swift index e23f2eebbef7..b6bffd706e80 100644 --- a/Client/Ecosia/UI/NTP/Customization/CustomizableNTPSettingConfig.swift +++ b/Client/Ecosia/UI/NTP/Customization/CustomizableNTPSettingConfig.swift @@ -4,6 +4,7 @@ import Foundation import Core +import Ecosia enum CustomizableNTPSettingConfig: CaseIterable { case topSites diff --git a/Client/Ecosia/UI/NTP/DefaultBrowser.swift b/Client/Ecosia/UI/NTP/DefaultBrowser.swift index b4a17e858d72..a79aa9d9fcb4 100644 --- a/Client/Ecosia/UI/NTP/DefaultBrowser.swift +++ b/Client/Ecosia/UI/NTP/DefaultBrowser.swift @@ -4,6 +4,7 @@ import UIKit import Common +import Ecosia @available(iOS 14, *) protocol DefaultBrowserDelegate: AnyObject { diff --git a/Client/Ecosia/UI/NTP/Library/NTPLibraryCell.swift b/Client/Ecosia/UI/NTP/Library/NTPLibraryCell.swift index 4d4f94028d40..778fc9b74ae9 100644 --- a/Client/Ecosia/UI/NTP/Library/NTPLibraryCell.swift +++ b/Client/Ecosia/UI/NTP/Library/NTPLibraryCell.swift @@ -5,6 +5,7 @@ import Shared import UIKit import Common +import Ecosia class NTPLibraryCell: UICollectionViewCell, Themeable, ReusableCell { diff --git a/Client/Ecosia/UI/NTP/News/NTPNewsCellViewModel.swift b/Client/Ecosia/UI/NTP/News/NTPNewsCellViewModel.swift index 2bb2cc30ca7b..3a8b44e0f309 100644 --- a/Client/Ecosia/UI/NTP/News/NTPNewsCellViewModel.swift +++ b/Client/Ecosia/UI/NTP/News/NTPNewsCellViewModel.swift @@ -6,6 +6,7 @@ import Foundation import Shared import Core import Common +import Ecosia protocol NTPNewsCellDelegate: AnyObject { func openSeeAllNews() diff --git a/Client/Ecosia/UI/NTP/News/NewsController.swift b/Client/Ecosia/UI/NTP/News/NewsController.swift index e5e0c2d56f54..ae1b6e5f5203 100644 --- a/Client/Ecosia/UI/NTP/News/NewsController.swift +++ b/Client/Ecosia/UI/NTP/News/NewsController.swift @@ -5,6 +5,7 @@ import Core import UIKit import Common +import Ecosia final class NewsController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, Themeable { diff --git a/Client/Ecosia/UI/NTP/NudgeCards/Newsletter/NTPNewsletterCardViewModel.swift b/Client/Ecosia/UI/NTP/NudgeCards/Newsletter/NTPNewsletterCardViewModel.swift index da92855639d5..c54935b76d21 100644 --- a/Client/Ecosia/UI/NTP/NudgeCards/Newsletter/NTPNewsletterCardViewModel.swift +++ b/Client/Ecosia/UI/NTP/NudgeCards/Newsletter/NTPNewsletterCardViewModel.swift @@ -3,6 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation +import Ecosia final class NTPNewsletterCardViewModel: NTPConfigurableNudgeCardCellViewModel { override var title: String { diff --git a/Client/Ecosia/UI/Onboarding/Welcome.swift b/Client/Ecosia/UI/Onboarding/Welcome.swift index f41c62efe577..a0f1fade39a8 100644 --- a/Client/Ecosia/UI/Onboarding/Welcome.swift +++ b/Client/Ecosia/UI/Onboarding/Welcome.swift @@ -5,6 +5,7 @@ import UIKit import Core import Common +import Ecosia protocol WelcomeDelegate: AnyObject { func welcomeDidFinish(_ welcome: Welcome) diff --git a/Client/Ecosia/UI/Onboarding/WelcomeTour.Step.swift b/Client/Ecosia/UI/Onboarding/WelcomeTour.Step.swift index 89ea65e0dbf8..a54452291be4 100644 --- a/Client/Ecosia/UI/Onboarding/WelcomeTour.Step.swift +++ b/Client/Ecosia/UI/Onboarding/WelcomeTour.Step.swift @@ -4,6 +4,7 @@ import UIKit import Core +import Ecosia extension WelcomeTour { diff --git a/Client/Ecosia/UI/Onboarding/WelcomeTour.swift b/Client/Ecosia/UI/Onboarding/WelcomeTour.swift index f9a35bb99abd..16309ce5cbb2 100644 --- a/Client/Ecosia/UI/Onboarding/WelcomeTour.swift +++ b/Client/Ecosia/UI/Onboarding/WelcomeTour.swift @@ -5,6 +5,7 @@ import UIKit import Core import Common +import Ecosia protocol WelcomeTourDelegate: AnyObject { func welcomeTourDidFinish(_ tour: WelcomeTour) diff --git a/Client/Ecosia/UI/WhatsNew/DataProvider/WhatsNewLocalDataProvider.swift b/Client/Ecosia/UI/WhatsNew/DataProvider/WhatsNewLocalDataProvider.swift index 9fa54d814b8a..481fbd1aef68 100644 --- a/Client/Ecosia/UI/WhatsNew/DataProvider/WhatsNewLocalDataProvider.swift +++ b/Client/Ecosia/UI/WhatsNew/DataProvider/WhatsNewLocalDataProvider.swift @@ -6,6 +6,7 @@ import Foundation import Shared import Core import Common +import Ecosia /// A local data provider for fetching What's New items based on app version updates. final class WhatsNewLocalDataProvider: WhatsNewDataProvider { diff --git a/Client/Frontend/Browser/MainMenuActionHelper.swift b/Client/Frontend/Browser/MainMenuActionHelper.swift index 03bd44ef9d6d..0fe3950c8523 100644 --- a/Client/Frontend/Browser/MainMenuActionHelper.swift +++ b/Client/Frontend/Browser/MainMenuActionHelper.swift @@ -13,6 +13,7 @@ import Common import Core // Ecosia: Need SafariServices to enable "open in safari" action import SafariServices +import Ecosia protocol ToolBarActionMenuDelegate: AnyObject { func updateToolbarState() diff --git a/Client/Frontend/Home/HomepageViewModel.swift b/Client/Frontend/Home/HomepageViewModel.swift index 9033ebc844d3..8982fce938fe 100644 --- a/Client/Frontend/Home/HomepageViewModel.swift +++ b/Client/Frontend/Home/HomepageViewModel.swift @@ -6,6 +6,7 @@ import Common import MozillaAppServices import Shared import Core +import Ecosia protocol HomepageViewModelDelegate: AnyObject { func reloadView() diff --git a/Client/Frontend/Home/TopSites/TopSitesViewModel.swift b/Client/Frontend/Home/TopSites/TopSitesViewModel.swift index a68bb9bcaf85..14820a21df86 100644 --- a/Client/Frontend/Home/TopSites/TopSitesViewModel.swift +++ b/Client/Frontend/Home/TopSites/TopSitesViewModel.swift @@ -8,6 +8,7 @@ import Shared import Storage // Ecosia: importing Core import Core +import Ecosia class TopSitesViewModel { struct UX { diff --git a/Client/Frontend/Library/Bookmarks/BookmarksPanel.swift b/Client/Frontend/Library/Bookmarks/BookmarksPanel.swift index b783c2cb1630..a4d98b052c54 100644 --- a/Client/Frontend/Library/Bookmarks/BookmarksPanel.swift +++ b/Client/Frontend/Library/Bookmarks/BookmarksPanel.swift @@ -8,6 +8,7 @@ import Storage import Shared import SiteImageView import Core +import Ecosia let LocalizedRootBookmarkFolderStrings = [ BookmarkRoots.MenuFolderGUID: String.BookmarksFolderTitleMenu, diff --git a/Client/Frontend/Settings/Main/DefaultBrowserSetting.swift b/Client/Frontend/Settings/Main/DefaultBrowserSetting.swift index 3f9809949946..a4bd427c9e2e 100644 --- a/Client/Frontend/Settings/Main/DefaultBrowserSetting.swift +++ b/Client/Frontend/Settings/Main/DefaultBrowserSetting.swift @@ -5,6 +5,7 @@ import Common import Foundation import Shared +import Ecosia class DefaultBrowserSetting: Setting { override var accessibilityIdentifier: String? { return "DefaultBrowserSettings" } diff --git a/Client/Frontend/Settings/SearchBar/SearchBarSettingsViewModel.swift b/Client/Frontend/Settings/SearchBar/SearchBarSettingsViewModel.swift index 7e4fef8798f4..766635e63a40 100644 --- a/Client/Frontend/Settings/SearchBar/SearchBarSettingsViewModel.swift +++ b/Client/Frontend/Settings/SearchBar/SearchBarSettingsViewModel.swift @@ -5,6 +5,7 @@ import Common import Foundation import Shared +import Ecosia enum SearchBarPosition: String, FlaggableFeatureOptions { case bottom diff --git a/Client/TabManagement/TabManagerImplementation.swift b/Client/TabManagement/TabManagerImplementation.swift index 9684c344862e..6e39c6920749 100644 --- a/Client/TabManagement/TabManagerImplementation.swift +++ b/Client/TabManagement/TabManagerImplementation.swift @@ -7,6 +7,7 @@ import TabDataStore import Storage import Common import Shared +import Ecosia // This class subclasses the legacy tab manager temporarily so we can // gradually migrate to the new system diff --git a/Client/TabManagement/TabMigrationUtility.swift b/Client/TabManagement/TabMigrationUtility.swift index 46d107b794e4..1e239d200c46 100644 --- a/Client/TabManagement/TabMigrationUtility.swift +++ b/Client/TabManagement/TabMigrationUtility.swift @@ -5,6 +5,7 @@ import Common import Shared import TabDataStore +import Ecosia protocol TabMigrationUtility { var shouldRunMigration: Bool { get } diff --git a/Client/Ecosia/Analytics/Analytics+Configuration.swift b/Ecosia/Analytics/Analytics+Configuration.swift similarity index 98% rename from Client/Ecosia/Analytics/Analytics+Configuration.swift rename to Ecosia/Analytics/Analytics+Configuration.swift index 4fa023e8ed5a..dccd31fc1f76 100644 --- a/Client/Ecosia/Analytics/Analytics+Configuration.swift +++ b/Ecosia/Analytics/Analytics+Configuration.swift @@ -82,7 +82,7 @@ extension Analytics { /// Checks if a day has passed since the last check for a specific event. /// - Parameter identifier: A unique identifier used to store and retrieve the last check date from `UserDefaults`. /// - Returns: A Boolean value indicating whether a day has passed since the last check. If no previous check exists, returns `true` and records the current date. - static func hasDayPassedSinceLastCheck(for identifier: String) -> Bool { + public static func hasDayPassedSinceLastCheck(for identifier: String) -> Bool { let now = Date() let defaults = UserDefaults.standard diff --git a/Client/Ecosia/Analytics/Analytics.Values.swift b/Ecosia/Analytics/Analytics.Values.swift similarity index 78% rename from Client/Ecosia/Analytics/Analytics.Values.swift rename to Ecosia/Analytics/Analytics.Values.swift index 6dad521b9804..477cb2725e71 100644 --- a/Client/Ecosia/Analytics/Analytics.Values.swift +++ b/Ecosia/Analytics/Analytics.Values.swift @@ -5,7 +5,7 @@ import Foundation extension Analytics { - enum Category: String { + public enum Category: String { case activity, bookmarks, @@ -24,27 +24,27 @@ extension Analytics { settings } - enum Label: String { + public enum Label: String { case analytics, market, toolbar - enum Bookmarks: String { + public enum Bookmarks: String { case importFunctionality = "import_functionality", learnMore = "learn_more", `import` } - enum DefaultBrowser: String { + public enum DefaultBrowser: String { case deeplink = "default_browser_deeplink", promo = "default_browser_promo", settings = "default_browser_settings" } - enum Menu: String { + public enum Menu: String { case bookmarks, copyLink = "copy_link", @@ -63,7 +63,7 @@ extension Analytics { zoom } - enum MenuStatus: String { + public enum MenuStatus: String { case bookmark, darkMode = "dark_mode", @@ -71,12 +71,12 @@ extension Analytics { shortcut } - enum Migration: String { + public enum Migration: String { case tabs } - enum Navigation: String { + public enum Navigation: String { case inapp, financialReports = "financial_reports", @@ -87,12 +87,12 @@ extension Analytics { terms } - enum NewsletterCardExperiment: String { + public enum NewsletterCardExperiment: String { case ntpCard = "ntp_card" } - enum NTP: String { + public enum NTP: String { case about, climateCounter = "climate_counter", @@ -104,13 +104,13 @@ extension Analytics { topSites = "top_sites" } - enum Onboarding: String { + public enum Onboarding: String { case next, skip } - enum Referral: String { + public enum Referral: String { case invite, inviteScreen = "invite_screen", @@ -120,7 +120,7 @@ extension Analytics { } } - enum Action: String { + public enum Action: String { case change, click, @@ -134,13 +134,13 @@ extension Analytics { success, view - enum Activity: String { + public enum Activity: String { case launch, resume } - enum APNConsent: String { + public enum APNConsent: String { case allow, deny, @@ -148,40 +148,40 @@ extension Analytics { view } - enum Bookmarks: String { + public enum Bookmarks: String { case `import` } - enum BrazeIAM: String { + public enum BrazeIAM: String { case click, dismiss, view } - enum NewsletterCardExperiment: String { + public enum NewsletterCardExperiment: String { case click, dismiss, view } - enum NTPCustomization: String { + public enum NTPCustomization: String { case click, disable, enable } - enum Promo: String { + public enum Promo: String { case click, close, view } - enum Referral: String { + public enum Referral: String { case claim, click, @@ -190,14 +190,14 @@ extension Analytics { view } - enum SeedCounter: String { + public enum SeedCounter: String { case level, collect, click } - enum TopSite: String { + public enum TopSite: String { case click, openNewTab = "open_new_tab", @@ -208,19 +208,19 @@ extension Analytics { } } - enum Property: String { + public enum Property: String { case enable, disable, home - enum APNConsent: String { + public enum APNConsent: String { case home, onLaunchPrompt = "on_launch_prompt" } - enum Bookmarks: String { + public enum Bookmarks: String { case `import`, export, @@ -229,7 +229,7 @@ extension Analytics { error } - enum Library: String { + public enum Library: String { case bookmarks, downloads, @@ -237,7 +237,7 @@ extension Analytics { readingList = "reading_list" } - enum OnboardingPage: String, CaseIterable { + public enum OnboardingPage: String, CaseIterable { case start, profits, @@ -246,14 +246,14 @@ extension Analytics { transparentFinances = "transparent_finances" } - enum ShareContent: String { + public enum ShareContent: String { case ntp, web, file } - enum TopSite: String { + public enum TopSite: String { case `default`, mostVisited = "most_visited", diff --git a/Client/Ecosia/Analytics/Analytics.swift b/Ecosia/Analytics/Analytics.swift similarity index 85% rename from Client/Ecosia/Analytics/Analytics.swift rename to Ecosia/Analytics/Analytics.swift index 8773b803a034..bde52e3abe84 100644 --- a/Client/Ecosia/Analytics/Analytics.swift +++ b/Ecosia/Analytics/Analytics.swift @@ -24,7 +24,7 @@ open class Analytics { Self.appResumeDailyTrackingPluginConfiguration]) } - static var shared = Analytics() + public static var shared = Analytics() private var tracker: TrackerController private let notificationCenter: AnalyticsUserNotificationCenterProtocol @@ -53,18 +53,18 @@ open class Analytics { return SelfDescribingJson(schema: abTestSchema, andDictionary: abTestContext) } - func reset() { + public func reset() { User.shared.analyticsId = .init() tracker = Self.tracker } // MARK: App events - func install() { + public func install() { track(SelfDescribing(schema: Self.installSchema, payload: ["app_v": Bundle.version as NSObject])) } - func activity(_ action: Action.Activity) { + public func activity(_ action: Action.Activity) { let event = Structured(category: Category.activity.rawValue, action: action.rawValue) .label(Analytics.Label.Navigation.inapp.rawValue) @@ -75,7 +75,7 @@ open class Analytics { } // MARK: Bookmarks - func bookmarksPerformImportExport(_ property: Property.Bookmarks) { + public func bookmarksPerformImportExport(_ property: Property.Bookmarks) { let event = Structured(category: Category.bookmarks.rawValue, action: Action.click.rawValue) .label(Label.Bookmarks.importFunctionality.rawValue) @@ -83,7 +83,7 @@ open class Analytics { track(event) } - func bookmarksEmptyLearnMoreClicked() { + public func bookmarksEmptyLearnMoreClicked() { let event = Structured(category: Category.bookmarks.rawValue, action: Action.click.rawValue) .label(Label.Bookmarks.learnMore.rawValue) @@ -91,7 +91,7 @@ open class Analytics { track(event) } - func bookmarksImportEnded(_ property: Property.Bookmarks) { + public func bookmarksImportEnded(_ property: Property.Bookmarks) { let event = Structured(category: Category.bookmarks.rawValue, action: Action.Bookmarks.import.rawValue) .label(Label.Bookmarks.import.rawValue) @@ -100,14 +100,14 @@ open class Analytics { } // MARK: Braze IAM - func brazeIAM(action: Action.BrazeIAM, messageOrButtonId: String?) { + public func brazeIAM(action: Action.BrazeIAM, messageOrButtonId: String?) { track(Structured(category: Category.brazeIAM.rawValue, action: action.rawValue) .property(messageOrButtonId)) } // MARK: Default Browser - func appOpenAsDefaultBrowser() { + public func appOpenAsDefaultBrowser() { let event = Structured(category: Category.external.rawValue, action: Action.receive.rawValue) .label(Label.DefaultBrowser.deeplink.rawValue) @@ -115,7 +115,7 @@ open class Analytics { track(event) } - func defaultBrowser(_ action: Action.Promo) { + public func defaultBrowser(_ action: Action.Promo) { let event = Structured(category: Category.browser.rawValue, action: action.rawValue) .label(Label.DefaultBrowser.promo.rawValue) @@ -124,21 +124,21 @@ open class Analytics { track(event) } - func defaultBrowserSettings() { + public func defaultBrowserSettings() { track(Structured(category: Category.browser.rawValue, action: Action.open.rawValue) .label(Label.DefaultBrowser.settings.rawValue)) } // MARK: Menu - func menuClick(_ item: Analytics.Label.Menu) { + public func menuClick(_ item: Analytics.Label.Menu) { let event = Structured(category: Category.menu.rawValue, action: Action.click.rawValue) .label(item.rawValue) track(event) } - func menuShare(_ content: Property.ShareContent) { + public func menuShare(_ content: Property.ShareContent) { let event = Structured(category: Category.menu.rawValue, action: Action.click.rawValue) .label(Label.Menu.share.rawValue) @@ -146,7 +146,7 @@ open class Analytics { track(event) } - func menuStatus(changed item: Analytics.Label.MenuStatus, to: Bool) { + public func menuStatus(changed item: Analytics.Label.MenuStatus, to: Bool) { let event = Structured(category: Category.menuStatus.rawValue, action: Action.click.rawValue) .label(item.rawValue) @@ -155,12 +155,12 @@ open class Analytics { } // MARK: Migration - func migration(_ success: Bool) { + public func migration(_ success: Bool) { track(Structured(category: Category.migration.rawValue, action: success ? Action.success.rawValue : Action.error.rawValue)) } - func migrationError(in migration: Label.Migration, message: String) { + public func migrationError(in migration: Label.Migration, message: String) { track(Structured(category: Category.migration.rawValue, action: Action.error.rawValue) .label(migration.rawValue) @@ -168,20 +168,20 @@ open class Analytics { } // MARK: Navigation - func navigation(_ action: Action, label: Label.Navigation) { + public func navigation(_ action: Action, label: Label.Navigation) { track(Structured(category: Category.navigation.rawValue, action: action.rawValue) .label(label.rawValue)) } - func navigationOpenNews(_ id: String) { + public func navigationOpenNews(_ id: String) { track(Structured(category: Category.navigation.rawValue, action: Action.open.rawValue) .label(Label.Navigation.news.rawValue) .property(id)) } - func navigationChangeMarket(_ new: String) { + public func navigationChangeMarket(_ new: String) { track(Structured(category: Category.navigation.rawValue, action: Action.change.rawValue) .label(Label.market.rawValue) @@ -189,20 +189,20 @@ open class Analytics { } // MARK: `NewsletterCardExperiment` - func newsletterCardExperiment(action: Action.NewsletterCardExperiment) { + public func newsletterCardExperiment(action: Action.NewsletterCardExperiment) { track(Structured(category: Category.newsletterExperiment.rawValue, action: action.rawValue) .label(Label.NewsletterCardExperiment.ntpCard.rawValue)) } // MARK: NTP - func ntpCustomisation(_ action: Action.NTPCustomization, label: Label.NTP) { + public func ntpCustomisation(_ action: Action.NTPCustomization, label: Label.NTP) { track(Structured(category: Category.ntp.rawValue, action: action.rawValue) .label(label.rawValue)) } - func ntpTopSite(_ action: Action.TopSite, property: Property.TopSite, position: NSNumber? = nil) { + public func ntpTopSite(_ action: Action.TopSite, property: Property.TopSite, position: NSNumber? = nil) { track(Structured(category: Category.ntp.rawValue, action: action.rawValue) .label(Label.NTP.topSites.rawValue) @@ -210,14 +210,14 @@ open class Analytics { .value(position)) } - func ntpLibraryItem(_ action: Action, property: Property.Library) { + public func ntpLibraryItem(_ action: Action, property: Property.Library) { track(Structured(category: Category.ntp.rawValue, action: action.rawValue) .label(Label.NTP.quickActions.rawValue) .property(property.rawValue)) } - func ntpSeedCounterExperiment(_ action: Action.SeedCounter, + public func ntpSeedCounterExperiment(_ action: Action.SeedCounter, value: NSNumber) { track(Structured(category: Category.ntp.rawValue, action: action.rawValue) @@ -227,7 +227,7 @@ open class Analytics { } // MARK: Onboarding - func introDisplaying(page: Property.OnboardingPage?, at index: Int) { + public func introDisplaying(page: Property.OnboardingPage?, at index: Int) { guard let page else { return } @@ -238,7 +238,7 @@ open class Analytics { track(event) } - func introClick(_ label: Label.Onboarding, page: Property.OnboardingPage?, index: Int) { + public func introClick(_ label: Label.Onboarding, page: Property.OnboardingPage?, index: Int) { guard let page else { return } @@ -259,21 +259,21 @@ open class Analytics { } // MARK: Referrals - func referral(action: Action.Referral, label: Label.Referral? = nil) { + public func referral(action: Action.Referral, label: Label.Referral? = nil) { track(Structured(category: Category.invitations.rawValue, action: action.rawValue) .label(label?.rawValue)) } // MARK: Settings - func searchbarChanged(to position: String) { + public func searchbarChanged(to position: String) { track(Structured(category: Category.settings.rawValue, action: Action.change.rawValue) .label(Label.toolbar.rawValue) .property(position)) } - func sendAnonymousUsageDataSetting(enabled: Bool) { + public func sendAnonymousUsageDataSetting(enabled: Bool) { // This is the only place where the tracker should be directly // used since we want to send this just as the user opts out _ = tracker.track(Structured(category: Category.settings.rawValue, diff --git a/Client/Ecosia/Analytics/AnalyticsNotificationSettings.swift b/Ecosia/Analytics/AnalyticsNotificationSettings.swift similarity index 100% rename from Client/Ecosia/Analytics/AnalyticsNotificationSettings.swift rename to Ecosia/Analytics/AnalyticsNotificationSettings.swift diff --git a/Ecosia/Braze/APNConsent.swift b/Ecosia/Braze/APNConsent.swift index e243cc607d9d..42545dc22612 100644 --- a/Ecosia/Braze/APNConsent.swift +++ b/Ecosia/Braze/APNConsent.swift @@ -4,13 +4,21 @@ import Foundation import Core -import Ecosia +import NotificationCenter +<<<<<<<< HEAD:Ecosia/Braze/APNConsent.swift struct APNConsent { private init() {} private static var toggleName: Unleash.Toggle.Name { .apnConsent +======== +public struct APNConsentOnLaunchExperiment { + private init() {} + + public static var toggleName: Unleash.Toggle.Name { + .apnConsentOnLaunch +>>>>>>>> e5bca0a4d ([MOB-3028] Move Analytics and dependencies to Ecosia framework):Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift } private static var isEnabled: Bool { @@ -18,7 +26,11 @@ struct APNConsent { Unleash.isEnabled(toggleName) && BrazeIntegrationExperiment.isEnabled } +<<<<<<<< HEAD:Ecosia/Braze/APNConsent.swift static func requestIfNeeded() async { +======== + public static func requestAPNConsentIfNeeded(delegate: UNUserNotificationCenterDelegate) async { +>>>>>>>> e5bca0a4d ([MOB-3028] Move Analytics and dependencies to Ecosia framework):Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift guard isEnabled, BrazeService.shared.notificationAuthorizationStatus == .notDetermined else { return } diff --git a/Ecosia/Braze/BrazeService.swift b/Ecosia/Braze/BrazeService.swift index be066fded89e..ab3ce600752c 100644 --- a/Ecosia/Braze/BrazeService.swift +++ b/Ecosia/Braze/BrazeService.swift @@ -146,15 +146,15 @@ extension BrazeService { extension BrazeService: BrazeInAppMessageUIDelegate { public func inAppMessage(_ ui: BrazeInAppMessageUI, didPresent message: Braze.InAppMessage, view: any InAppMessageView) { -// Analytics.shared.brazeIAM(action: .view, messageOrButtonId: message.id) + Analytics.shared.brazeIAM(action: .view, messageOrButtonId: message.id) } public func inAppMessage(_ ui: BrazeInAppMessageUI, didDismiss message: Braze.InAppMessage, view: any InAppMessageView) { -// Analytics.shared.brazeIAM(action: .dismiss, messageOrButtonId: message.id) + Analytics.shared.brazeIAM(action: .dismiss, messageOrButtonId: message.id) } public func inAppMessage(_ ui: BrazeInAppMessageUI, shouldProcess clickAction: Braze.InAppMessage.ClickAction, buttonId: String?, message: Braze.InAppMessage, view: any InAppMessageView) -> Bool { -// Analytics.shared.brazeIAM(action: .click, messageOrButtonId: buttonId) + Analytics.shared.brazeIAM(action: .click, messageOrButtonId: buttonId) return true } } diff --git a/Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift b/Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift new file mode 100644 index 000000000000..42545dc22612 --- /dev/null +++ b/Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift @@ -0,0 +1,45 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Foundation +import Core +import NotificationCenter + +<<<<<<<< HEAD:Ecosia/Braze/APNConsent.swift +struct APNConsent { + private init() {} + + private static var toggleName: Unleash.Toggle.Name { + .apnConsent +======== +public struct APNConsentOnLaunchExperiment { + private init() {} + + public static var toggleName: Unleash.Toggle.Name { + .apnConsentOnLaunch +>>>>>>>> e5bca0a4d ([MOB-3028] Move Analytics and dependencies to Ecosia framework):Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift + } + + private static var isEnabled: Bool { + // Depends on Braze Integration being enabled - we should make sure targets on Unleash match + Unleash.isEnabled(toggleName) && BrazeIntegrationExperiment.isEnabled + } + +<<<<<<<< HEAD:Ecosia/Braze/APNConsent.swift + static func requestIfNeeded() async { +======== + public static func requestAPNConsentIfNeeded(delegate: UNUserNotificationCenterDelegate) async { +>>>>>>>> e5bca0a4d ([MOB-3028] Move Analytics and dependencies to Ecosia framework):Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift + guard isEnabled, BrazeService.shared.notificationAuthorizationStatus == .notDetermined else { + return + } + Analytics.shared.apnConsent(.view) + do { + let granted = try await BrazeService.shared.requestAPNConsent() + Analytics.shared.apnConsent(granted ? .allow : .deny) + } catch { + Analytics.shared.apnConsent(.error) + } + } +} diff --git a/Client/Ecosia/Experiments/Unleash/BrazeIntegrationExperiment.swift b/Ecosia/Experiments/Unleash/BrazeIntegrationExperiment.swift similarity index 100% rename from Client/Ecosia/Experiments/Unleash/BrazeIntegrationExperiment.swift rename to Ecosia/Experiments/Unleash/BrazeIntegrationExperiment.swift diff --git a/Client/Ecosia/Experiments/Unleash/NewsletterCardExperiment.swift b/Ecosia/Experiments/Unleash/NewsletterCardExperiment.swift similarity index 78% rename from Client/Ecosia/Experiments/Unleash/NewsletterCardExperiment.swift rename to Ecosia/Experiments/Unleash/NewsletterCardExperiment.swift index b464d9dc263b..497f40026eaa 100644 --- a/Client/Ecosia/Experiments/Unleash/NewsletterCardExperiment.swift +++ b/Ecosia/Experiments/Unleash/NewsletterCardExperiment.swift @@ -5,19 +5,19 @@ import Foundation import Core -struct NewsletterCardExperiment { +public struct NewsletterCardExperiment { private init() {} - static var isEnabled: Bool { + public static var isEnabled: Bool { Unleash.isEnabled(.newsletterCard) } - static var shouldShowCard: Bool { + public static var shouldShowCard: Bool { isEnabled && !isDismissed } /// Send onboarding card view analytics event, but just the first time it's called. - static func trackExperimentImpression() { + public static func trackExperimentImpression() { let trackExperimentImpressionKey = "newsletterCardExperimentImpression" guard !UserDefaults.standard.bool(forKey: trackExperimentImpressionKey) else { return @@ -29,16 +29,16 @@ struct NewsletterCardExperiment { // MARK: Dismissed private static let dismissedKey = "newsletterCardExperimentDismissed" - static var isDismissed: Bool { + public static var isDismissed: Bool { UserDefaults.standard.bool(forKey: dismissedKey) } - static func setDismissed() { + public static func setDismissed() { UserDefaults.standard.set(true, forKey: dismissedKey) } /// Should only be used in Debug! - static func unsetDismissed() { + public static func unsetDismissed() { UserDefaults.standard.removeObject(forKey: dismissedKey) } } diff --git a/Client/Ecosia/Extensions/AppInfo+Ecosia.swift b/Ecosia/Extensions/AppInfo+Ecosia.swift similarity index 96% rename from Client/Ecosia/Extensions/AppInfo+Ecosia.swift rename to Ecosia/Extensions/AppInfo+Ecosia.swift index e699228c1285..d12dfe864db2 100644 --- a/Client/Ecosia/Extensions/AppInfo+Ecosia.swift +++ b/Ecosia/Extensions/AppInfo+Ecosia.swift @@ -17,7 +17,7 @@ extension AppInfo { /// Only available for iOS 14.3 and later (will return nil on earlier versions). /// Returns nil after the first time, so that no unwanted new token is generated. /// If an error is caught, it will return nil and retry next time it is fetched. - static var adServicesAttributionToken: String? { + public static var adServicesAttributionToken: String? { guard #available(iOS 14.3, *), !UserDefaults.standard.bool(forKey: hasAttributedAppleSearchDownloadKey) else { return nil diff --git a/Client/Ecosia/Helpers/AppInfoProvider/AppVersionInfoProvider.swift b/Ecosia/Helpers/AppInfoProvider/AppVersionInfoProvider.swift similarity index 86% rename from Client/Ecosia/Helpers/AppInfoProvider/AppVersionInfoProvider.swift rename to Ecosia/Helpers/AppInfoProvider/AppVersionInfoProvider.swift index cf509602a293..6158ef7f8e52 100644 --- a/Client/Ecosia/Helpers/AppInfoProvider/AppVersionInfoProvider.swift +++ b/Ecosia/Helpers/AppInfoProvider/AppVersionInfoProvider.swift @@ -4,6 +4,6 @@ import Foundation -protocol AppVersionInfoProvider { +public protocol AppVersionInfoProvider { var version: String { get } } diff --git a/Client/Ecosia/Helpers/AppInfoProvider/DefaultAppVersionInfoProvider.swift b/Ecosia/Helpers/AppInfoProvider/DefaultAppVersionInfoProvider.swift similarity index 68% rename from Client/Ecosia/Helpers/AppInfoProvider/DefaultAppVersionInfoProvider.swift rename to Ecosia/Helpers/AppInfoProvider/DefaultAppVersionInfoProvider.swift index 0fc4c91ed236..4d2942ad1f22 100644 --- a/Client/Ecosia/Helpers/AppInfoProvider/DefaultAppVersionInfoProvider.swift +++ b/Ecosia/Helpers/AppInfoProvider/DefaultAppVersionInfoProvider.swift @@ -5,9 +5,11 @@ import Shared import Common -struct DefaultAppVersionInfoProvider: AppVersionInfoProvider { +public struct DefaultAppVersionInfoProvider: AppVersionInfoProvider { - var version: String { + public init() { } + + public var version: String { return AppInfo.ecosiaAppVersion } } diff --git a/Client/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType+Extensions.swift b/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType+Extensions.swift similarity index 90% rename from Client/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType+Extensions.swift rename to Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType+Extensions.swift index 13dca5d22eda..5a3480c898d1 100644 --- a/Client/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType+Extensions.swift +++ b/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType+Extensions.swift @@ -17,7 +17,7 @@ extension EcosiaInstallType { /// /// - Warning: Ensure that `User.shared.firstTime` and `versionProvider.version` are correctly initialized before calling this function. /// - static func evaluateCurrentEcosiaInstallType(withVersionProvider versionProvider: AppVersionInfoProvider = DefaultAppVersionInfoProvider(), storeUpgradeVersion: Bool = false) { + public static func evaluateCurrentEcosiaInstallType(withVersionProvider versionProvider: AppVersionInfoProvider = DefaultAppVersionInfoProvider(), storeUpgradeVersion: Bool = false) { if User.shared.firstTime && EcosiaInstallType.get() == .unknown { diff --git a/Client/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType.swift b/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType.swift similarity index 93% rename from Client/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType.swift rename to Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType.swift index 99ae657668e7..42c8732ce7fb 100644 --- a/Client/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType.swift +++ b/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType.swift @@ -5,7 +5,7 @@ import Foundation /// Represents the type of Ecosia installation. -enum EcosiaInstallType: String { +public enum EcosiaInstallType: String { /// Represents a fresh installation of Ecosia. case fresh @@ -29,7 +29,7 @@ enum EcosiaInstallType: String { /// Retrieves the current Ecosia install type from UserDefaults. /// /// - Returns: The current Ecosia install type. If not found, returns `.unknown`. - static func get() -> EcosiaInstallType { + public static func get() -> EcosiaInstallType { guard let rawValue = UserDefaults.standard.string(forKey: Self.installTypeKey), let type = EcosiaInstallType(rawValue: rawValue) else { return unknown } @@ -47,7 +47,7 @@ enum EcosiaInstallType: String { /// Retrieves the persisted current version of Ecosia from UserDefaults. /// /// - Returns: The persisted current version. If not found, returns an empty string. - static func persistedCurrentVersion() -> String { + public static func persistedCurrentVersion() -> String { guard let currentVersion = UserDefaults.standard.string(forKey: Self.currentInstalledVersionKey) else { return "" } return currentVersion } diff --git a/Client/Ecosia/Helpers/Version/Version+Extensions.swift b/Ecosia/Helpers/Version/Version+Extensions.swift similarity index 100% rename from Client/Ecosia/Helpers/Version/Version+Extensions.swift rename to Ecosia/Helpers/Version/Version+Extensions.swift diff --git a/Client/Ecosia/Helpers/Version/Version.swift b/Ecosia/Helpers/Version/Version.swift similarity index 87% rename from Client/Ecosia/Helpers/Version/Version.swift rename to Ecosia/Helpers/Version/Version.swift index 622cde9cb142..e8469bae0bbf 100644 --- a/Client/Ecosia/Helpers/Version/Version.swift +++ b/Ecosia/Helpers/Version/Version.swift @@ -7,7 +7,7 @@ import Foundation /// Represents a semantic version of an app. /// /// A semantic version is typically represented as a series of numbers separated by dots, e.g., "1.0.0". -struct Version: CustomStringConvertible { +public struct Version: CustomStringConvertible { var major: Int var minor: Int @@ -16,7 +16,7 @@ struct Version: CustomStringConvertible { /// Initializes a new `Version` from a string representation. /// /// - Parameter versionString: A string containing the semantic version, e.g., "1.0.0". - init?(_ versionString: String) { + public init?(_ versionString: String) { let components = versionString.split(separator: ".") guard components.count == 3, let major = Int(components[0]), @@ -31,7 +31,7 @@ struct Version: CustomStringConvertible { } /// A string representation of the `Version`. - var description: String { + public var description: String { return "\(major).\(minor).\(patch)" } } @@ -45,7 +45,7 @@ extension Version: Comparable { /// - rhs: Another `Version`. /// /// - Returns: `true` if both instances represent the same version, `false` otherwise. - static func == (lhs: Version, rhs: Version) -> Bool { + public static func == (lhs: Version, rhs: Version) -> Bool { return lhs.major == rhs.major && lhs.minor == rhs.minor && lhs.patch == rhs.patch } @@ -56,7 +56,7 @@ extension Version: Comparable { /// - rhs: Another `Version`. /// /// - Returns: `true` if the instance on the left should come before the one on the right, `false` otherwise. - static func < (lhs: Version, rhs: Version) -> Bool { + public static func < (lhs: Version, rhs: Version) -> Bool { if lhs.major != rhs.major { return lhs.major < rhs.major } @@ -72,7 +72,7 @@ extension Version: Hashable { /// Adds this value to the given hasher. /// /// - Parameter hasher: The hasher to use when combining the components of this instance. - func hash(into hasher: inout Hasher) { + public func hash(into hasher: inout Hasher) { hasher.combine(major) hasher.combine(minor) hasher.combine(patch) From c4e121193c38bd8f8c6602db1fbdf2208c1a41f8 Mon Sep 17 00:00:00 2001 From: Luca Schifino Date: Fri, 15 Nov 2024 16:54:00 +0100 Subject: [PATCH 09/59] [MOB-3028] Lint fix --- Ecosia/Analytics/Analytics.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Ecosia/Analytics/Analytics.swift b/Ecosia/Analytics/Analytics.swift index bde52e3abe84..30fe0db5879e 100644 --- a/Ecosia/Analytics/Analytics.swift +++ b/Ecosia/Analytics/Analytics.swift @@ -217,8 +217,7 @@ open class Analytics { .property(property.rawValue)) } - public func ntpSeedCounterExperiment(_ action: Action.SeedCounter, - value: NSNumber) { + public func ntpSeedCounterExperiment(_ action: Action.SeedCounter, value: NSNumber) { track(Structured(category: Category.ntp.rawValue, action: action.rawValue) .label(Label.NTP.climateCounter.rawValue) From 7c1ad1c07dc485ae37f5a5de0bcf47536fa7b4de Mon Sep 17 00:00:00 2001 From: Luca Schifino Date: Wed, 20 Nov 2024 15:19:42 +0100 Subject: [PATCH 10/59] [MOB-3028] Including correct Info.plist --- Client.xcodeproj/project.pbxproj | 59 +++++++++++++++----------------- Ecosia/Info.plist | 26 ++++++++++++++ 2 files changed, 53 insertions(+), 32 deletions(-) create mode 100644 Ecosia/Info.plist diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index 2fd58071a344..2fae0c13d6bd 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -32,7 +32,7 @@ 122935742CE78D0A00EC1297 /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; 1229357C2CE78D0A00EC1297 /* Ecosia.h in Headers */ = {isa = PBXBuildFile; fileRef = 1229356C2CE78D0A00EC1297 /* Ecosia.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1229357F2CE78D0A00EC1297 /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; - 122935802CE78D0A00EC1297 /* Ecosia.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 122935802CE78D0A00EC1297 /* Ecosia.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 1229358D2CE78D5D00EC1297 /* BrazeServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126509882CDA31890011BA36 /* BrazeServiceTests.swift */; }; 1229358F2CE78EC400EC1297 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 1229358E2CE78EC400EC1297 /* Core */; }; 122935912CE78ED500EC1297 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 122935902CE78ED500EC1297 /* BrazeKit */; }; @@ -8040,6 +8040,7 @@ 122935A12CE79A8600EC1297 /* Helpers */, 1229356C2CE78D0A00EC1297 /* Ecosia.h */, 1229359D2CE792B700EC1297 /* README.md */, + 12E604442CECADDA009A7BEC /* Info.plist */, ); path = Ecosia; sourceTree = ""; @@ -8832,7 +8833,6 @@ children = ( 1285E2B62CC68BF00053506B /* APNConsentOnLaunchExperiment.swift */, 2C6188F82B7A8A22006B70D7 /* BrazeIntegrationExperiment.swift */, - 12147F322CDBA7230009D300 /* NewsletterCardExperiment.swift */, 2CFE600B2CD3AAB6001F35D2 /* OnboardingRemoveExperiment.swift */, ); path = Unleash; @@ -19824,11 +19824,10 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = ""; + DYLIB_CURRENT_VERSION = ""; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -19848,7 +19847,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - GENERATE_INFOPLIST_FILE = YES; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = Ecosia/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "$(MOZ_BUNDLE_DISPLAY_NAME)"; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_NSCameraUsageDescription = "Firefox uses your camera to scan QR codes and take photos and video."; @@ -19871,7 +19871,6 @@ "@loader_path/Frameworks", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 1.0; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; @@ -19887,7 +19886,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; + VERSIONING_SYSTEM = ""; VERSION_INFO_PREFIX = ""; }; name = Debug; @@ -19929,14 +19928,13 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 33YMRSYD2L; "DEVELOPMENT_TEAM[sdk=macosx*]" = 33YMRSYD2L; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = ""; + DYLIB_CURRENT_VERSION = ""; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; ENABLE_NS_ASSERTIONS = NO; @@ -19950,7 +19948,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - GENERATE_INFOPLIST_FILE = YES; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = Ecosia/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "$(MOZ_BUNDLE_DISPLAY_NAME)"; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_NSCameraUsageDescription = "Firefox uses your camera to scan QR codes and take photos and video."; @@ -19973,7 +19972,6 @@ "@loader_path/Frameworks", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 1.0; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; MTL_ENABLE_DEBUG_INFO = NO; @@ -19989,7 +19987,7 @@ SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; + VERSIONING_SYSTEM = ""; VERSION_INFO_PREFIX = ""; }; name = BetaDebug; @@ -20031,11 +20029,10 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = ""; + DYLIB_CURRENT_VERSION = ""; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; ENABLE_NS_ASSERTIONS = NO; @@ -20049,7 +20046,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - GENERATE_INFOPLIST_FILE = YES; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = Ecosia/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "$(MOZ_BUNDLE_DISPLAY_NAME)"; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_NSCameraUsageDescription = "Firefox uses your camera to scan QR codes and take photos and video."; @@ -20072,7 +20070,6 @@ "@loader_path/Frameworks", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 1.0; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; MTL_ENABLE_DEBUG_INFO = NO; @@ -20087,7 +20084,7 @@ SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; + VERSIONING_SYSTEM = ""; VERSION_INFO_PREFIX = ""; }; name = Release; @@ -20129,11 +20126,10 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = ""; + DYLIB_CURRENT_VERSION = ""; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -20153,7 +20149,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - GENERATE_INFOPLIST_FILE = YES; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = Ecosia/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "$(MOZ_BUNDLE_DISPLAY_NAME)"; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_NSCameraUsageDescription = "Firefox uses your camera to scan QR codes and take photos and video."; @@ -20176,7 +20173,6 @@ "@loader_path/Frameworks", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 1.0; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; @@ -20192,7 +20188,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; + VERSIONING_SYSTEM = ""; VERSION_INFO_PREFIX = ""; }; name = Development_TestFlight; @@ -20234,11 +20230,10 @@ CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; + DYLIB_COMPATIBILITY_VERSION = ""; + DYLIB_CURRENT_VERSION = ""; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -20258,7 +20253,8 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - GENERATE_INFOPLIST_FILE = YES; + GENERATE_INFOPLIST_FILE = NO; + INFOPLIST_FILE = Ecosia/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "$(MOZ_BUNDLE_DISPLAY_NAME)"; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_NSCameraUsageDescription = "Firefox uses your camera to scan QR codes and take photos and video."; @@ -20281,7 +20277,6 @@ "@loader_path/Frameworks", ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 1.0; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; @@ -20297,7 +20292,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - VERSIONING_SYSTEM = "apple-generic"; + VERSIONING_SYSTEM = ""; VERSION_INFO_PREFIX = ""; }; name = Development_AppCenter; diff --git a/Ecosia/Info.plist b/Ecosia/Info.plist new file mode 100644 index 000000000000..59d4351087bf --- /dev/null +++ b/Ecosia/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 18.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + From 35fd5df21591ab137a0a66c9aa721ca414512067 Mon Sep 17 00:00:00 2001 From: Dario Carlomagno Date: Tue, 3 Dec 2024 17:08:42 +0100 Subject: [PATCH 11/59] [MOB-3028] Build succeeded - to check install --- .tx/integration_config.yml | 6 +- Client.xcodeproj/project.pbxproj | 3006 ++++++++++++----- Client/Application/AppDelegate.swift | 1 + Client/Configuration/Ecosia.ShareTo.xcconfig | 2 +- .../Configuration/Ecosia.WidgetKit.xcconfig | 2 +- Client/Configuration/Ecosia.xcconfig | 2 +- .../Configuration/EcosiaBeta.ShareTo.xcconfig | 2 +- .../EcosiaBeta.WidgetKit.xcconfig | 2 +- Client/Configuration/EcosiaBeta.xcconfig | 2 +- .../EcosiaBetaDebug.ShareTo.xcconfig | 2 +- .../EcosiaBetaDebug.WidgetKit.xcconfig | 2 +- Client/Configuration/EcosiaBetaDebug.xcconfig | 2 +- .../EcosiaDebug.ShareTo.xcconfig | 2 +- .../EcosiaDebug.WidgetKit.xcconfig | 2 +- Client/Configuration/EcosiaDebug.xcconfig | 2 +- .../LaunchScreenViewController.swift | 2 + .../ConnectionStatusImage.swift | 2 +- Client/Ecosia/Extensions/UIImage+Ecosia.swift | 12 + Client/Ecosia/UI/EcosiaPrimaryButton.swift | 31 + Client/Ecosia/UI/Theme/EcosiaTheme.swift | 43 +- .../LegacyThemeManager/LegacyDarkTheme.swift | 2 + .../LegacyThemeManager/LegacyTheme.swift | 9 + Ecosia/Analytics/Analytics.swift | 2 +- .../AppExtensions/Ecosia.entitlements | 0 .../AppExtensions/EcosiaBeta.entitlements | 0 .../Entitlements/Ecosia.entitlements | 0 .../Entitlements/EcosiaBeta.entitlements | 0 Ecosia/Extensions/AppInfo+Ecosia.swift | 2 +- .../Extensions/DeviceInfo+Ecosia.swift | 1 + .../Ecosia => Ecosia}/Fake/FakeNimbus.swift | 0 .../Ecosia => Ecosia}/Fake/FakeSentry.swift | 0 .../Fake/FakeTelemetry.swift | 0 .../FeatureManagement/FeatureManagement.swift | 4 +- .../L10N/Scripts/Clean.swift | 0 .../L10N/Scripts/Validate.swift | 0 {Client/Ecosia => Ecosia}/L10N/String.swift | 8 +- .../L10N/de.lproj/Ecosia.strings | Bin .../L10N/de.lproj/Plurals.stringsdict | 0 .../L10N/en.lproj/Ecosia.strings | 0 .../L10N/en.lproj/Plurals.stringsdict | 0 .../L10N/es.lproj/Ecosia.strings | Bin .../L10N/es.lproj/Plurals.stringsdict | 0 .../L10N/fr.lproj/Ecosia.strings | Bin .../L10N/fr.lproj/Plurals.stringsdict | 0 .../L10N/it.lproj/Ecosia.strings | Bin .../L10N/it.lproj/Plurals.stringsdict | 0 .../L10N/nl.lproj/Ecosia.strings | Bin .../L10N/nl.lproj/Plurals.stringsdict | 0 .../LaunchScreen/EcosiaLaunchScreen.xib | 0 .../LaunchScreen/EcosiaLaunchScreenView.swift | 4 +- {Client/Ecosia => Ecosia}/MMP/MMP.swift | 8 +- .../SeedCounter.xcdatamodel/contents | 8 + {Client/Ecosia => Ecosia}/markets.json | 0 EcosiaTests/BrazeServiceTests.swift | 2 +- 54 files changed, 2188 insertions(+), 989 deletions(-) create mode 100644 Client/Ecosia/Extensions/UIImage+Ecosia.swift create mode 100644 Client/Ecosia/UI/EcosiaPrimaryButton.swift rename {Client/Ecosia => Ecosia}/Entitlements/AppExtensions/Ecosia.entitlements (100%) rename {Client/Ecosia => Ecosia}/Entitlements/AppExtensions/EcosiaBeta.entitlements (100%) rename {Client/Ecosia => Ecosia}/Entitlements/Ecosia.entitlements (100%) rename {Client/Ecosia => Ecosia}/Entitlements/EcosiaBeta.entitlements (100%) rename {Client/Ecosia => Ecosia}/Extensions/DeviceInfo+Ecosia.swift (99%) rename {Client/Ecosia => Ecosia}/Fake/FakeNimbus.swift (100%) rename {Client/Ecosia => Ecosia}/Fake/FakeSentry.swift (100%) rename {Client/Ecosia => Ecosia}/Fake/FakeTelemetry.swift (100%) rename {Client/Ecosia => Ecosia}/FeatureManagement/FeatureManagement.swift (93%) rename {Client/Ecosia => Ecosia}/L10N/Scripts/Clean.swift (100%) rename {Client/Ecosia => Ecosia}/L10N/Scripts/Validate.swift (100%) rename {Client/Ecosia => Ecosia}/L10N/String.swift (98%) rename {Client/Ecosia => Ecosia}/L10N/de.lproj/Ecosia.strings (100%) rename {Client/Ecosia => Ecosia}/L10N/de.lproj/Plurals.stringsdict (100%) rename {Client/Ecosia => Ecosia}/L10N/en.lproj/Ecosia.strings (100%) rename {Client/Ecosia => Ecosia}/L10N/en.lproj/Plurals.stringsdict (100%) rename {Client/Ecosia => Ecosia}/L10N/es.lproj/Ecosia.strings (100%) rename {Client/Ecosia => Ecosia}/L10N/es.lproj/Plurals.stringsdict (100%) rename {Client/Ecosia => Ecosia}/L10N/fr.lproj/Ecosia.strings (100%) rename {Client/Ecosia => Ecosia}/L10N/fr.lproj/Plurals.stringsdict (100%) rename {Client/Ecosia => Ecosia}/L10N/it.lproj/Ecosia.strings (100%) rename {Client/Ecosia => Ecosia}/L10N/it.lproj/Plurals.stringsdict (100%) rename {Client/Ecosia => Ecosia}/L10N/nl.lproj/Ecosia.strings (100%) rename {Client/Ecosia => Ecosia}/L10N/nl.lproj/Plurals.stringsdict (100%) rename {Client/Ecosia => Ecosia}/LaunchScreen/EcosiaLaunchScreen.xib (100%) rename {Client/Ecosia => Ecosia}/LaunchScreen/EcosiaLaunchScreenView.swift (86%) rename {Client/Ecosia => Ecosia}/MMP/MMP.swift (92%) create mode 100644 Ecosia/UI/NTP/ClimateImpactCounter/CoreData/SeedCounter.xcdatamodeld/SeedCounter.xcdatamodel/contents rename {Client/Ecosia => Ecosia}/markets.json (100%) diff --git a/.tx/integration_config.yml b/.tx/integration_config.yml index 5e7314b8836d..b8e253969c25 100644 --- a/.tx/integration_config.yml +++ b/.tx/integration_config.yml @@ -2,12 +2,12 @@ filters: - filter_type: file source_language: en - source_file: Client/Ecosia/L10N/en.lproj/Ecosia.strings + source_file: Ecosia/L10N/en.lproj/Ecosia.strings file_format: STRINGS translation_files_expression: 'Client/Ecosia/L10N/.lproj/Ecosia.strings' - filter_type: file source_language: en - source_file: Client/Ecosia/L10N/en.lproj/Plurals.stringsdict + source_file: Ecosia/L10N/en.lproj/Plurals.stringsdict file_format: STRINGSDICT - translation_files_expression: 'Client/Ecosia/L10N/.lproj/Plurals.stringsdict' + translation_files_expression: 'Client/Ecosia/L10N/.lproj/Plurals.stringsdict' \ No newline at end of file diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index 2fae0c13d6bd..3de7dbd1d3cc 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -27,8 +27,6 @@ 0BB5B30B1AC0AD1F0052877D /* LoginsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BB5B30A1AC0AD1F0052877D /* LoginsHelper.swift */; }; 0BF0DB941A8545800039F300 /* URLBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF0DB931A8545800039F300 /* URLBarView.swift */; }; 0BF1B7E31AC60DEA00A7B407 /* InsetButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BF1B7E21AC60DEA00A7B407 /* InsetButton.swift */; }; - 12147F2F2CDA3CD00009D300 /* NTPNewsletterCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F2E2CDA3CD00009D300 /* NTPNewsletterCardCell.swift */; }; - 12147F312CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F302CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift */; }; 122935742CE78D0A00EC1297 /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; 1229357C2CE78D0A00EC1297 /* Ecosia.h in Headers */ = {isa = PBXBuildFile; fileRef = 1229356C2CE78D0A00EC1297 /* Ecosia.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1229357F2CE78D0A00EC1297 /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; @@ -37,27 +35,10 @@ 1229358F2CE78EC400EC1297 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 1229358E2CE78EC400EC1297 /* Core */; }; 122935912CE78ED500EC1297 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 122935902CE78ED500EC1297 /* BrazeKit */; }; 122935932CE78ED500EC1297 /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 122935922CE78ED500EC1297 /* BrazeUI */; }; - 1229359C2CE7927900EC1297 /* BrazeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1229359B2CE7927800EC1297 /* BrazeService.swift */; }; - 1229359E2CE79A2600EC1297 /* Analytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892E2B7A8A22006B70D7 /* Analytics.swift */; }; - 1229359F2CE79A2800EC1297 /* Analytics+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892F2B7A8A22006B70D7 /* Analytics+Configuration.swift */; }; - 122935A02CE79A3100EC1297 /* Analytics.Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189302B7A8A22006B70D7 /* Analytics.Values.swift */; }; - 122935A22CE79A9400EC1297 /* EcosiaInstallType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189282B7A8A22006B70D7 /* EcosiaInstallType.swift */; }; - 122935A42CE79A9A00EC1297 /* EcosiaInstallType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189292B7A8A22006B70D7 /* EcosiaInstallType+Extensions.swift */; }; - 122935A52CE79AF400EC1297 /* DefaultAppVersionInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189252B7A8A22006B70D7 /* DefaultAppVersionInfoProvider.swift */; }; - 122935A62CE79AF800EC1297 /* AppVersionInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189262B7A8A22006B70D7 /* AppVersionInfoProvider.swift */; }; - 122935A72CE79B0400EC1297 /* Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892B2B7A8A22006B70D7 /* Version.swift */; }; - 122935A82CE79B0800EC1297 /* Version+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61892C2B7A8A22006B70D7 /* Version+Extensions.swift */; }; 122935A92CE79CC800EC1297 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; }; - 122935AB2CE79D6F00EC1297 /* AppInfo+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189092B7A8A22006B70D7 /* AppInfo+Ecosia.swift */; }; - 122935AC2CE79DA200EC1297 /* BrazeIntegrationExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188F82B7A8A22006B70D7 /* BrazeIntegrationExperiment.swift */; }; - 122935AE2CE79DA900EC1297 /* APNConsentOnLaunchExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E2B62CC68BF00053506B /* APNConsentOnLaunchExperiment.swift */; }; - 122935AF2CE79DAD00EC1297 /* OnboardingRemoveExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CFE600B2CD3AAB6001F35D2 /* OnboardingRemoveExperiment.swift */; }; - 122935B02CE79DB100EC1297 /* NewsletterCardExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 12147F322CDBA7230009D300 /* NewsletterCardExperiment.swift */; }; - 122935B32CE79E2400EC1297 /* SeedCounterNTPExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6B5B402CAAF3AA00F15323 /* SeedCounterNTPExperiment.swift */; }; 122935B52CE79EF900EC1297 /* SnowplowTracker in Frameworks */ = {isa = PBXBuildFile; productRef = 122935B42CE79EF900EC1297 /* SnowplowTracker */; }; 126509852CD925B40011BA36 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 126509842CD925B40011BA36 /* BrazeKit */; }; 126509872CD925B40011BA36 /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 126509862CD925B40011BA36 /* BrazeUI */; }; - 1285E2B52CC293CA0053506B /* AnalyticsSpyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1285E2B42CC293CA0053506B /* AnalyticsSpyTests.swift */; }; 158241282820698B00956B39 /* RustRemoteTabsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 158241272820698B00956B39 /* RustRemoteTabsTests.swift */; }; 15DE98FD27FCED4F00F1ECDB /* RustRemoteTabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15DE98FC27FCED4F00F1ECDB /* RustRemoteTabs.swift */; }; 1B3D99F1270E89D0006E1264 /* Telemetry in Frameworks */ = {isa = PBXBuildFile; productRef = 1B3D99F0270E89D0006E1264 /* Telemetry */; }; @@ -223,137 +204,23 @@ 28E91E751B443AD5009DF274 /* SyncConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28E91E741B443AD5009DF274 /* SyncConstants.swift */; }; 28ECD9BF1BA1F19900D829DA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = E6231C001B90A44F005ABB0D /* libz.tbd */; }; 2C0360DA2C1747E6006706F2 /* FxNimbus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0360D92C1747E6006706F2 /* FxNimbus.swift */; }; - 2C03A4152CB7C7CC00AB228B /* DispatchQueueHelper+BuildChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C03A4142CB7C7CC00AB228B /* DispatchQueueHelper+BuildChannel.swift */; }; 2C1298A52BF5EB16005AE4E4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 2C1298A42BF5EB16005AE4E4 /* PrivacyInfo.xcprivacy */; }; 2C1298A62BF5EB1E005AE4E4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 2C1298A42BF5EB16005AE4E4 /* PrivacyInfo.xcprivacy */; }; 2C1298A72BF5EB1F005AE4E4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 2C1298A42BF5EB16005AE4E4 /* PrivacyInfo.xcprivacy */; }; 2C1298A82BF5EE23005AE4E4 /* libStorage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FCAE21A1ABB51F800877008 /* libStorage.a */; }; 2C1298AC2BF5EE3E005AE4E4 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2C1298AB2BF5EE3E005AE4E4 /* Core */; }; 2C1298AF2BF602D3005AE4E4 /* DefaultSuggestedSites.swift in Sources */ = {isa = PBXBuildFile; fileRef = 394CF6CE1BAA493C00906917 /* DefaultSuggestedSites.swift */; }; - 2C16B7672CAF2441006118F8 /* UserDefaultsSeedProgressManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C16B7652CAF2425006118F8 /* UserDefaultsSeedProgressManagerTests.swift */; }; - 2C19DACF2C74C7BF00D2641C /* snapshot_configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = 2C19DACE2C74C7BF00D2641C /* snapshot_configuration.json */; }; 2C1F23BD2B9F405E00186F55 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2C1F23BC2B9F405E00186F55 /* Core */; }; - 2C2349A32C57E5BC007A5894 /* EcosiaPerformanceTestHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2349A22C57E5BC007A5894 /* EcosiaPerformanceTestHistory.swift */; }; - 2C26EA142C04CAD100795552 /* EcosiaTopSitesHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C26EA132C04CAD100795552 /* EcosiaTopSitesHelperTests.swift */; }; - 2C26FAA92C8752D20055760A /* LegacyThemeManager+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189012B7A8A22006B70D7 /* LegacyThemeManager+Ecosia.swift */; }; - 2C26FAAA2C8752D20055760A /* LegacyThemeManager+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189012B7A8A22006B70D7 /* LegacyThemeManager+Ecosia.swift */; }; - 2C3BD5EB2BF6193B00E25B0D /* EcosiaThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C32B7A8A22006B70D7 /* EcosiaThemeManager.swift */; }; 2C49854E206173C800893DAE /* photon-colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C49854D206173C800893DAE /* photon-colors.swift */; }; - 2C4ABD492CB58E4F00FF86F9 /* Sparkle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C4ABD482CB58E4F00FF86F9 /* Sparkle.swift */; }; - 2C4D16602C76360800E89C95 /* environment.json in Resources */ = {isa = PBXBuildFile; fileRef = 2C4D165F2C76360800E89C95 /* environment.json */; }; - 2C5A5E652CB53DB7005BFE8B /* SeedCounterConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C5A5E642CB53DB7005BFE8B /* SeedCounterConfig.swift */; }; - 2C5A5E672CB53DF9005BFE8B /* UserDefaultsSeedProgressManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C5A5E662CB53DF9005BFE8B /* UserDefaultsSeedProgressManager.swift */; }; - 2C5B81C82C75388300B81D95 /* LocaleRetriever.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C5B81C72C75388300B81D95 /* LocaleRetriever.swift */; }; - 2C6189312B7A8A22006B70D7 /* EcosiaLaunchScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188802B7A8A21006B70D7 /* EcosiaLaunchScreenView.swift */; }; - 2C6189322B7A8A22006B70D7 /* EcosiaLaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2C6188812B7A8A21006B70D7 /* EcosiaLaunchScreen.xib */; }; - 2C6189332B7A8A22006B70D7 /* MMP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188832B7A8A21006B70D7 /* MMP.swift */; }; - 2C6189342B7A8A22006B70D7 /* SemanticColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188852B7A8A21006B70D7 /* SemanticColor.swift */; }; - 2C6189352B7A8A22006B70D7 /* PageActionMenuCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188872B7A8A21006B70D7 /* PageActionMenuCell.swift */; }; - 2C6189362B7A8A22006B70D7 /* PageActionsShortcutsHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188882B7A8A21006B70D7 /* PageActionsShortcutsHeader.swift */; }; - 2C6189372B7A8A22006B70D7 /* PageActionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188892B7A8A21006B70D7 /* PageActionMenu.swift */; }; - 2C6189382B7A8A22006B70D7 /* EmptyBookmarksViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61888A2B7A8A21006B70D7 /* EmptyBookmarksViewDelegate.swift */; }; - 2C6189392B7A8A22006B70D7 /* EcosiaFindInPageBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61888B2B7A8A21006B70D7 /* EcosiaFindInPageBar.swift */; }; - 2C61893A2B7A8A22006B70D7 /* Ecosia.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C61888C2B7A8A21006B70D7 /* Ecosia.xcassets */; }; - 2C61893B2B7A8A22006B70D7 /* EmptyReadingListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61888D2B7A8A21006B70D7 /* EmptyReadingListView.swift */; }; - 2C6189412B7A8A22006B70D7 /* EmptyHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188942B7A8A21006B70D7 /* EmptyHeader.swift */; }; - 2C6189422B7A8A22006B70D7 /* WhatsNewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188962B7A8A21006B70D7 /* WhatsNewCell.swift */; }; - 2C6189432B7A8A22006B70D7 /* WhatsNewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188972B7A8A21006B70D7 /* WhatsNewViewModel.swift */; }; - 2C6189442B7A8A22006B70D7 /* WhatsNewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188982B7A8A21006B70D7 /* WhatsNewViewController.swift */; }; - 2C6189452B7A8A22006B70D7 /* WhatsNewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188992B7A8A21006B70D7 /* WhatsNewItem.swift */; }; - 2C6189462B7A8A22006B70D7 /* WhatsNewDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61889B2B7A8A21006B70D7 /* WhatsNewDataProvider.swift */; }; - 2C6189472B7A8A22006B70D7 /* WhatsNewLocalDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61889C2B7A8A21006B70D7 /* WhatsNewLocalDataProvider.swift */; }; - 2C6189482B7A8A22006B70D7 /* NTPLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61889E2B7A8A21006B70D7 /* NTPLayout.swift */; }; - 2C6189492B7A8A22006B70D7 /* DefaultBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61889F2B7A8A21006B70D7 /* DefaultBrowser.swift */; }; - 2C61894A2B7A8A22006B70D7 /* CustomizableNTPSettingConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188A12B7A8A21006B70D7 /* CustomizableNTPSettingConfig.swift */; }; - 2C61894B2B7A8A22006B70D7 /* NTPCustomizationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188A22B7A8A21006B70D7 /* NTPCustomizationCell.swift */; }; - 2C61894C2B7A8A22006B70D7 /* NTPCustomizationCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188A32B7A8A21006B70D7 /* NTPCustomizationCellViewModel.swift */; }; - 2C61894D2B7A8A22006B70D7 /* NTPLibraryShortcutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188A52B7A8A21006B70D7 /* NTPLibraryShortcutView.swift */; }; - 2C61894E2B7A8A22006B70D7 /* NTPLibraryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188A62B7A8A21006B70D7 /* NTPLibraryCell.swift */; }; - 2C61894F2B7A8A22006B70D7 /* NTPLibaryCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188A72B7A8A21006B70D7 /* NTPLibaryCellViewModel.swift */; }; - 2C6189502B7A8A22006B70D7 /* NTPTooltip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188A82B7A8A21006B70D7 /* NTPTooltip.swift */; }; - 2C6189512B7A8A22006B70D7 /* CircleButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188A92B7A8A21006B70D7 /* CircleButton.swift */; }; - 2C6189522B7A8A22006B70D7 /* NTPTooltip.Highlight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188AA2B7A8A21006B70D7 /* NTPTooltip.Highlight.swift */; }; - 2C6189552B7A8A22006B70D7 /* NewsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188AF2B7A8A22006B70D7 /* NewsController.swift */; }; - 2C6189562B7A8A22006B70D7 /* NTPNewsCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188B02B7A8A22006B70D7 /* NTPNewsCellViewModel.swift */; }; - 2C6189572B7A8A22006B70D7 /* NTPNewsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188B12B7A8A22006B70D7 /* NTPNewsCell.swift */; }; - 2C6189582B7A8A22006B70D7 /* NTPLogoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188B32B7A8A22006B70D7 /* NTPLogoCell.swift */; }; - 2C6189592B7A8A22006B70D7 /* NTPTooltipDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188B42B7A8A22006B70D7 /* NTPTooltipDelegate.swift */; }; - 2C61895A2B7A8A22006B70D7 /* ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188B62B7A8A22006B70D7 /* ProgressView.swift */; }; - 2C61895B2B7A8A22006B70D7 /* NTPImpactCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188B72B7A8A22006B70D7 /* NTPImpactCell.swift */; }; - 2C61895C2B7A8A22006B70D7 /* NTPImpactCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188B82B7A8A22006B70D7 /* NTPImpactCellViewModel.swift */; }; - 2C61895D2B7A8A22006B70D7 /* NTPImpactRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188B92B7A8A22006B70D7 /* NTPImpactRowView.swift */; }; - 2C61895E2B7A8A22006B70D7 /* NTPImpactDividerFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188BA2B7A8A22006B70D7 /* NTPImpactDividerFooter.swift */; }; - 2C61895F2B7A8A22006B70D7 /* ClimateImpactInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188BB2B7A8A22006B70D7 /* ClimateImpactInfo.swift */; }; - 2C6189602B7A8A22006B70D7 /* AboutEcosiaSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188BD2B7A8A22006B70D7 /* AboutEcosiaSection.swift */; }; - 2C6189612B7A8A22006B70D7 /* NTPAboutEcosiaCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188BE2B7A8A22006B70D7 /* NTPAboutEcosiaCellViewModel.swift */; }; - 2C6189622B7A8A22006B70D7 /* NTPAboutEcosiaCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188BF2B7A8A22006B70D7 /* NTPAboutEcosiaCell.swift */; }; - 2C6189632B7A8A22006B70D7 /* Colours.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C6188C02B7A8A22006B70D7 /* Colours.xcassets */; }; - 2C6189642B7A8A22006B70D7 /* EcosiaNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C12B7A8A22006B70D7 /* EcosiaNavigation.swift */; }; - 2C6189652B7A8A22006B70D7 /* EcosiaThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C32B7A8A22006B70D7 /* EcosiaThemeManager.swift */; }; - 2C6189662B7A8A22006B70D7 /* EcosiaThemeColourPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C42B7A8A22006B70D7 /* EcosiaThemeColourPalette.swift */; }; - 2C6189672B7A8A22006B70D7 /* EcosiaTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C52B7A8A22006B70D7 /* EcosiaTheme.swift */; }; - 2C6189682B7A8A22006B70D7 /* FilterController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C62B7A8A22006B70D7 /* FilterController.swift */; }; - 2C6189692B7A8A22006B70D7 /* MarketsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C72B7A8A22006B70D7 /* MarketsController.swift */; }; - 2C61896A2B7A8A22006B70D7 /* EmptyBookmarksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C82B7A8A22006B70D7 /* EmptyBookmarksView.swift */; }; - 2C61896B2B7A8A22006B70D7 /* WelcomeTourRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188CA2B7A8A22006B70D7 /* WelcomeTourRow.swift */; }; - 2C61896C2B7A8A22006B70D7 /* Welcome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188CB2B7A8A22006B70D7 /* Welcome.swift */; }; - 2C61896D2B7A8A22006B70D7 /* WelcomeTour.Step.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188CC2B7A8A22006B70D7 /* WelcomeTour.Step.swift */; }; - 2C61896E2B7A8A22006B70D7 /* WelcomeTourAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188CD2B7A8A22006B70D7 /* WelcomeTourAction.swift */; }; - 2C61896F2B7A8A22006B70D7 /* WelcomeTour.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188CE2B7A8A22006B70D7 /* WelcomeTour.swift */; }; - 2C6189702B7A8A22006B70D7 /* WelcomeTourTransparent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188CF2B7A8A22006B70D7 /* WelcomeTourTransparent.swift */; }; - 2C6189712B7A8A22006B70D7 /* WelcomeTourGreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188D02B7A8A22006B70D7 /* WelcomeTourGreen.swift */; }; - 2C6189722B7A8A22006B70D7 /* WelcomeNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188D12B7A8A22006B70D7 /* WelcomeNavigation.swift */; }; - 2C6189732B7A8A22006B70D7 /* WelcomeTourProfit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188D22B7A8A22006B70D7 /* WelcomeTourProfit.swift */; }; - 2C6189742B7A8A22006B70D7 /* MultiplyImpact.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188D42B7A8A22006B70D7 /* MultiplyImpact.swift */; }; - 2C6189752B7A8A22006B70D7 /* MultiplyImpactStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188D52B7A8A22006B70D7 /* MultiplyImpactStep.swift */; }; - 2C6189762B7A8A22006B70D7 /* EcosiaDebugSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188D72B7A8A22006B70D7 /* EcosiaDebugSettings.swift */; }; - 2C6189772B7A8A22006B70D7 /* EcosiaSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188D82B7A8A22006B70D7 /* EcosiaSettings.swift */; }; - 2C6189782B7A8A22006B70D7 /* NTPCustomizationSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188D92B7A8A22006B70D7 /* NTPCustomizationSettingsViewController.swift */; }; - 2C6189792B7A8A22006B70D7 /* Ecosia.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2C6188DB2B7A8A22006B70D7 /* Ecosia.strings */; }; - 2C61897A2B7A8A22006B70D7 /* Plurals.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 2C6188DD2B7A8A22006B70D7 /* Plurals.stringsdict */; }; - 2C61897D2B7A8A22006B70D7 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188E82B7A8A22006B70D7 /* String.swift */; }; - 2C61897E2B7A8A22006B70D7 /* FeatureManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188EE2B7A8A22006B70D7 /* FeatureManagement.swift */; }; - 2C61897F2B7A8A22006B70D7 /* EcosiaHomepageSectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188F12B7A8A22006B70D7 /* EcosiaHomepageSectionType.swift */; }; - 2C6189802B7A8A22006B70D7 /* EcosiaTopSiteItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188F42B7A8A22006B70D7 /* EcosiaTopSiteItemCell.swift */; }; - 2C6189842B7A8A22006B70D7 /* WebsiteConnectionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188FB2B7A8A22006B70D7 /* WebsiteConnectionStatus.swift */; }; - 2C6189862B7A8A22006B70D7 /* BrowserViewController+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189002B7A8A22006B70D7 /* BrowserViewController+Ecosia.swift */; }; - 2C6189872B7A8A22006B70D7 /* LegacyThemeManager+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189012B7A8A22006B70D7 /* LegacyThemeManager+Ecosia.swift */; }; - 2C6189882B7A8A22006B70D7 /* UIButton+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189022B7A8A22006B70D7 /* UIButton+Ecosia.swift */; }; - 2C6189892B7A8A22006B70D7 /* UIFont+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189032B7A8A22006B70D7 /* UIFont+Ecosia.swift */; }; - 2C61898A2B7A8A22006B70D7 /* ErrorPageHandler+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189042B7A8A22006B70D7 /* ErrorPageHandler+Ecosia.swift */; }; - 2C61898B2B7A8A22006B70D7 /* SnapKit+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189052B7A8A22006B70D7 /* SnapKit+Ecosia.swift */; }; - 2C61898C2B7A8A22006B70D7 /* HomepageViewController+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189062B7A8A22006B70D7 /* HomepageViewController+Ecosia.swift */; }; - 2C61898D2B7A8A22006B70D7 /* SimpleToast+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189072B7A8A22006B70D7 /* SimpleToast+Ecosia.swift */; }; - 2C61898E2B7A8A22006B70D7 /* UIView+maskedCorners.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189082B7A8A22006B70D7 /* UIView+maskedCorners.swift */; }; - 2C6189902B7A8A22006B70D7 /* NumberFormatter+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61890A2B7A8A22006B70D7 /* NumberFormatter+Ecosia.swift */; }; - 2C6189912B7A8A22006B70D7 /* URL+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61890B2B7A8A22006B70D7 /* URL+Ecosia.swift */; }; - 2C6189922B7A8A22006B70D7 /* BrowserCoordinator+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61890C2B7A8A22006B70D7 /* BrowserCoordinator+Ecosia.swift */; }; - 2C6189932B7A8A22006B70D7 /* AppSettingsTableViewController+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61890D2B7A8A22006B70D7 /* AppSettingsTableViewController+Ecosia.swift */; }; - 2C6189942B7A8A22006B70D7 /* DeviceInfo+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C61890E2B7A8A22006B70D7 /* DeviceInfo+Ecosia.swift */; }; - 2C6189952B7A8A22006B70D7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189102B7A8A22006B70D7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift */; }; - 2C6189972B7A8A22006B70D7 /* ConnectionStatusImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189122B7A8A22006B70D7 /* ConnectionStatusImage.swift */; }; - 2C6189982B7A8A22006B70D7 /* BookmarksExchange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189172B7A8A22006B70D7 /* BookmarksExchange.swift */; }; - 2C6189992B7A8A22006B70D7 /* markets.json in Resources */ = {isa = PBXBuildFile; fileRef = 2C6189182B7A8A22006B70D7 /* markets.json */; }; - 2C6189D12B7A8D3E006B70D7 /* EcosiaThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C32B7A8A22006B70D7 /* EcosiaThemeManager.swift */; }; - 2C6189D22B7A8D69006B70D7 /* EcosiaThemeColourPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C42B7A8A22006B70D7 /* EcosiaThemeColourPalette.swift */; }; - 2C6189DD2B7B7776006B70D7 /* AppInfo+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6189092B7A8A22006B70D7 /* AppInfo+Ecosia.swift */; }; 2C6189DE2B7B78ED006B70D7 /* LegacyTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9A179A20E69A7E00B12184 /* LegacyTheme.swift */; }; - 2C6189E02B7B7916006B70D7 /* EcosiaThemeColourPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C42B7A8A22006B70D7 /* EcosiaThemeColourPalette.swift */; }; 2C6189E12B7B7922006B70D7 /* LegacyTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9A179A20E69A7E00B12184 /* LegacyTheme.swift */; }; 2C6189E22B7B7929006B70D7 /* LegacyThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9A179820E69A7E00B12184 /* LegacyThemeManager.swift */; }; 2C6189E32B7B792A006B70D7 /* LegacyThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9A179820E69A7E00B12184 /* LegacyThemeManager.swift */; }; 2C6189E42B7B7946006B70D7 /* LegacyDarkTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9A179920E69A7E00B12184 /* LegacyDarkTheme.swift */; }; 2C6189E52B7B7946006B70D7 /* LegacyDarkTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9A179920E69A7E00B12184 /* LegacyDarkTheme.swift */; }; - 2C6189E62B7B7952006B70D7 /* SemanticColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188852B7A8A21006B70D7 /* SemanticColor.swift */; }; - 2C6189E72B7B7952006B70D7 /* SemanticColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188852B7A8A21006B70D7 /* SemanticColor.swift */; }; - 2C6189E92B7B7979006B70D7 /* EcosiaTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C52B7A8A22006B70D7 /* EcosiaTheme.swift */; }; - 2C6189EA2B7B7979006B70D7 /* EcosiaTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6188C52B7A8A22006B70D7 /* EcosiaTheme.swift */; }; 2C6189EB2B7B7AB4006B70D7 /* DispatchQueueHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D83821FF1FC7961D00303C12 /* DispatchQueueHelper.swift */; }; 2C6189EC2B7B7AB4006B70D7 /* DispatchQueueHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D83821FF1FC7961D00303C12 /* DispatchQueueHelper.swift */; }; 2C6189F12B7B7D5D006B70D7 /* SnowplowTracker in Frameworks */ = {isa = PBXBuildFile; productRef = 2C6189F02B7B7D5D006B70D7 /* SnowplowTracker */; }; - 2C69DA722C62175400D7F69F /* SnapshotTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C69DA712C62175400D7F69F /* SnapshotTestHelper.swift */; }; - 2C69DA752C62185A00D7F69F /* Welcome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C69DA742C62185A00D7F69F /* Welcome.swift */; }; - 2C69DA772C62243300D7F69F /* NTPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C69DA762C62243300D7F69F /* NTPTests.swift */; }; 2C69DA782C62259D00D7F69F /* MockProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 281B2BE91ADF4D90002917DC /* MockProfile.swift */; }; 2C69DA792C6225AE00D7F69F /* DependencyHelperMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A70EF18295E2E1600790249 /* DependencyHelperMock.swift */; }; 2C69DA7B2C6225C400D7F69F /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 2C69DA7A2C6225C400D7F69F /* Common */; }; @@ -363,43 +230,438 @@ 2C69DA7F2C62458300D7F69F /* RustMozillaAppServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43BE578A278BA4D900491291 /* RustMozillaAppServices.framework */; }; 2C69DA812C62459200D7F69F /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2C69DA802C62459200D7F69F /* Core */; }; 2C69DA822C62459C00D7F69F /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CB1728B2C61336D008551E2 /* libz.tbd */; }; - 2C69DA842C62B44B00D7F69F /* NTPComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C69DA832C62B44B00D7F69F /* NTPComponentTests.swift */; }; - 2C69DA922C63A92D00D7F69F /* SnapshotBaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C69DA912C63A92D00D7F69F /* SnapshotBaseTests.swift */; }; - 2C69DA942C63B0C000D7F69F /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C69DA932C63B0C000D7F69F /* String+Extension.swift */; }; - 2C6B5B3E2CAAF28000F15323 /* NTPSeedCounterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6B5B3A2CAAF27F00F15323 /* NTPSeedCounterCell.swift */; }; - 2C6B5B3F2CAAF28000F15323 /* NTPSeedCounterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6B5B3B2CAAF27F00F15323 /* NTPSeedCounterViewModel.swift */; }; 2C6C908F2C614A6C007D9B43 /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 2C6C908E2C614A6C007D9B43 /* SnapshotTesting */; }; - 2C6C90902C614A76007D9B43 /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD368492C5BC31700972871 /* OnboardingTests.swift */; }; - 2C728D7E2CBBDCDC00C7684B /* UnleashUserDefaultsSeedProgressManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C728D7D2CBBDCDC00C7684B /* UnleashUserDefaultsSeedProgressManagerTests.swift */; }; - 2C78374B2C1765DF00BBFFEB /* LoadingScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCFB3D42C0F1EA500BEDCA0 /* LoadingScreen.swift */; }; - 2C7DBABD2C4EA37200BCD03F /* AppDelegateFeatureManagementIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C7DBABB2C4EA17200BCD03F /* AppDelegateFeatureManagementIntegrationTests.swift */; }; - 2C82625A2C64BB9300E2A255 /* DeviceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C8262592C64BB9300E2A255 /* DeviceType.swift */; }; - 2C82625C2C6648D900E2A255 /* LocalizationOverrideTestingBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C82625B2C6648D900E2A255 /* LocalizationOverrideTestingBundle.swift */; }; - 2C82625E2C66661700E2A255 /* EcosiaMockThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C82625D2C66661700E2A255 /* EcosiaMockThemeManager.swift */; }; 2C872A552B8CD58200B318A0 /* ContileProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A7A93ED2810ADF2005E7E1B /* ContileProviderTests.swift */; }; - 2C872A5A2B8CD7E000B318A0 /* MockAppVersionInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C872A532B8CD47600B318A0 /* MockAppVersionInfoProvider.swift */; }; - 2C872A5B2B8CD7E000B318A0 /* AnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE294692B7FC5A5006C22B2 /* AnalyticsTests.swift */; }; - 2C872A5E2B8CD7E000B318A0 /* EcosiaInstallTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE294672B7FC5A4006C22B2 /* EcosiaInstallTypeTests.swift */; }; - 2C872A5F2B8CD7E000B318A0 /* EcosiaNTPTooltipHighlightTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE2946C2B7FC5A5006C22B2 /* EcosiaNTPTooltipHighlightTests.swift */; }; - 2C872A602B8CD7E000B318A0 /* EcosiaPageActionMenuCellTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE2946D2B7FC5A5006C22B2 /* EcosiaPageActionMenuCellTests.swift */; }; - 2C872A622B8CD7E000B318A0 /* VersionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE294702B7FC5A6006C22B2 /* VersionTests.swift */; }; - 2C872A632B8CD7E000B318A0 /* WhatsNewLocalDataProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CE2946B2B7FC5A5006C22B2 /* WhatsNewLocalDataProviderTests.swift */; }; - 2C872A642B8CD7E000B318A0 /* EcosiaHomeViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C872A562B8CD65100B318A0 /* EcosiaHomeViewModelTests.swift */; }; - 2C9258D92CEF97B100C6BB8D /* MockUNNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9258D82CEF97B100C6BB8D /* MockUNNotificationSettings.swift */; }; - 2C9258DB2CEFB26500C6BB8D /* AnalyticsNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9258DA2CEFB26500C6BB8D /* AnalyticsNotificationSettings.swift */; }; - 2C9A62C02CDE1F7600CDA7D1 /* MockWelcomeDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9A62BF2CDE1F7600CDA7D1 /* MockWelcomeDelegate.swift */; }; - 2C9A62C22CDE4A3B00CDA7D1 /* MockNewsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C9A62C12CDE4A3B00CDA7D1 /* MockNewsModel.swift */; }; - 2CA995282CA2C06A001064CC /* NTPConfigurableNudgeCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA995272CA2C06A001064CC /* NTPConfigurableNudgeCardCell.swift */; }; - 2CA9952A2CA2C0BB001064CC /* NTPConfigurableNudgeCardCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA995292CA2C0BB001064CC /* NTPConfigurableNudgeCardCellViewModel.swift */; }; 2CABD7162C11C9CC00A0750F /* MozillaAppServices in Frameworks */ = {isa = PBXBuildFile; productRef = 2CABD7152C11C9CC00A0750F /* MozillaAppServices */; }; - 2CABD7282C12EF1E00A0750F /* PrivateModeButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CABD7272C12EF1E00A0750F /* PrivateModeButtonTests.swift */; }; - 2CCBB5232CAE9826006E2E10 /* ArcProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCBB5222CAE9826006E2E10 /* ArcProgressView.swift */; }; - 2CCBB5252CAEA9DF006E2E10 /* SeedProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCBB5242CAEA9DF006E2E10 /* SeedProgressView.swift */; }; - 2CCBB5272CAEAD53006E2E10 /* SeedCounterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCBB5262CAEAD53006E2E10 /* SeedCounterView.swift */; }; - 2CCBB5352CAF06DE006E2E10 /* SeedProgressManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCBB5342CAF06DE006E2E10 /* SeedProgressManagerProtocol.swift */; }; - 2CCBB5372CAF0E8C006E2E10 /* SeedCounterHiddenSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CCBB5362CAF0E8C006E2E10 /* SeedCounterHiddenSettings.swift */; }; 2CCFB3D72C0FBEE800BEDCA0 /* TabToolbarHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D815A3A724A53F3200AAB221 /* TabToolbarHelperTests.swift */; }; - 2CD48B7F2C7F7E4100A70908 /* EcosiaOverlayModeManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD48B7E2C7F7E4100A70908 /* EcosiaOverlayModeManagerTests.swift */; }; + 2CD262A92CFDC5EB00A040A7 /* EcosiaMockThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261842CFDC5E900A040A7 /* EcosiaMockThemeManager.swift */; }; + 2CD262AA2CFDC5EB00A040A7 /* Welcome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261852CFDC5E900A040A7 /* Welcome.swift */; }; + 2CD262AB2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261872CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262AC2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261882CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262AD2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261892CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png */; }; + 2CD262AE2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618A2CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png */; }; + 2CD262AF2CFDC5EB00A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618B2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262B02CFDC5EB00A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618C2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262B12CFDC5EB00A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618D2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png */; }; + 2CD262B22CFDC5EB00A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618E2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png */; }; + 2CD262B32CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618F2CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262B42CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261902CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262B52CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261912CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png */; }; + 2CD262B62CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261922CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png */; }; + 2CD262B72CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261932CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262B82CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261942CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262B92CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261952CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png */; }; + 2CD262BA2CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261962CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png */; }; + 2CD262BB2CFDC5EB00A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261972CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262BC2CFDC5EB00A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261982CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262BD2CFDC5EB00A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261992CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png */; }; + 2CD262BE2CFDC5EB00A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619A2CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png */; }; + 2CD262BF2CFDC5EB00A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619B2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262C02CFDC5EB00A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619C2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262C12CFDC5EB00A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619D2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_en.1.png */; }; + 2CD262C22CFDC5EB00A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619E2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_es.1.png */; }; + 2CD262C32CFDC5EB00A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619F2CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262C42CFDC5EB00A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A02CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262C52CFDC5EB00A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A12CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_en.1.png */; }; + 2CD262C62CFDC5EB00A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A22CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_es.1.png */; }; + 2CD262C72CFDC5EB00A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A32CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262C82CFDC5EB00A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A42CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262C92CFDC5EB00A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A52CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_en.1.png */; }; + 2CD262CA2CFDC5EB00A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A62CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_es.1.png */; }; + 2CD262CB2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A72CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262CC2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A82CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262CD2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A92CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png */; }; + 2CD262CE2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AA2CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png */; }; + 2CD262CF2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AB2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262D02CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AC2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262D12CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AD2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png */; }; + 2CD262D22CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AE2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png */; }; + 2CD262D32CFDC5EB00A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AF2CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262D42CFDC5EB00A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B02CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262D52CFDC5EB00A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B12CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png */; }; + 2CD262D62CFDC5EB00A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B22CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png */; }; + 2CD262D72CFDC5EB00A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B32CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262D82CFDC5EB00A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B42CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262D92CFDC5EB00A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B52CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png */; }; + 2CD262DA2CFDC5EB00A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B62CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png */; }; + 2CD262DB2CFDC5EB00A040A7 /* NTPComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261B92CFDC5E900A040A7 /* NTPComponentTests.swift */; }; + 2CD262DC2CFDC5EB00A040A7 /* NTPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261BA2CFDC5E900A040A7 /* NTPTests.swift */; }; + 2CD262DD2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261BC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; + 2CD262DE2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261BD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; + 2CD262DF2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261BE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; + 2CD262E02CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261BF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; + 2CD262E12CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C02CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; + 2CD262E22CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C12CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_de.1.png */; }; + 2CD262E32CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C22CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_en.1.png */; }; + 2CD262E42CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C32CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_es.1.png */; }; + 2CD262E52CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C42CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_it.1.png */; }; + 2CD262E62CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C52CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png */; }; + 2CD262E72CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C62CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png */; }; + 2CD262E82CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C72CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png */; }; + 2CD262E92CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C82CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png */; }; + 2CD262EA2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C92CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png */; }; + 2CD262EB2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CA2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png */; }; + 2CD262EC2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CB2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png */; }; + 2CD262ED2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png */; }; + 2CD262EE2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png */; }; + 2CD262EF2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png */; }; + 2CD262F02CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png */; }; + 2CD262F12CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D02CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; + 2CD262F22CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D12CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; + 2CD262F32CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D22CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; + 2CD262F42CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D32CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; + 2CD262F52CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D42CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; + 2CD262F62CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D52CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_de.1.png */; }; + 2CD262F72CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D62CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_en.1.png */; }; + 2CD262F82CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D72CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_es.1.png */; }; + 2CD262F92CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D82CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_it.1.png */; }; + 2CD262FA2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D92CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_nl.1.png */; }; + 2CD262FB2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DA2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png */; }; + 2CD262FC2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DB2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png */; }; + 2CD262FD2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DC2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png */; }; + 2CD262FE2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DD2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png */; }; + 2CD262FF2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DE2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png */; }; + 2CD263002CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DF2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png */; }; + 2CD263012CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E02CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png */; }; + 2CD263022CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E12CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png */; }; + 2CD263032CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E22CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png */; }; + 2CD263042CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E32CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png */; }; + 2CD263052CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; + 2CD263062CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; + 2CD263072CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; + 2CD263082CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; + 2CD263092CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E82CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; + 2CD2630A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E92CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png */; }; + 2CD2630B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261EA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png */; }; + 2CD2630C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261EB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png */; }; + 2CD2630D2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261EC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png */; }; + 2CD2630E2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261ED2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png */; }; + 2CD2630F2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261EE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png */; }; + 2CD263102CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261EF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png */; }; + 2CD263112CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F02CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png */; }; + 2CD263122CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F12CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png */; }; + 2CD263132CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F22CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png */; }; + 2CD263142CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F32CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png */; }; + 2CD263152CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png */; }; + 2CD263162CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png */; }; + 2CD263172CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png */; }; + 2CD263182CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png */; }; + 2CD263192CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F82CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; + 2CD2631A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F92CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; + 2CD2631B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; + 2CD2631C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; + 2CD2631D2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; + 2CD2631E2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FD2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png */; }; + 2CD2631F2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png */; }; + 2CD263202CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png */; }; + 2CD263212CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262002CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png */; }; + 2CD263222CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262012CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png */; }; + 2CD263232CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262022CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png */; }; + 2CD263242CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262032CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png */; }; + 2CD263252CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262042CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png */; }; + 2CD263262CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262052CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png */; }; + 2CD263272CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262062CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png */; }; + 2CD263282CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262072CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png */; }; + 2CD263292CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262082CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png */; }; + 2CD2632A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262092CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png */; }; + 2CD2632B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620A2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png */; }; + 2CD2632C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620B2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png */; }; + 2CD2632D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; + 2CD2632E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; + 2CD2632F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; + 2CD263302CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; + 2CD263312CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262102CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; + 2CD263322CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262112CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png */; }; + 2CD263332CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262122CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png */; }; + 2CD263342CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262132CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png */; }; + 2CD263352CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262142CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png */; }; + 2CD263362CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262152CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png */; }; + 2CD263372CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262162CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png */; }; + 2CD263382CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262172CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png */; }; + 2CD263392CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262182CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png */; }; + 2CD2633A2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262192CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png */; }; + 2CD2633B2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png */; }; + 2CD2633C2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png */; }; + 2CD2633D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png */; }; + 2CD2633E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png */; }; + 2CD2633F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png */; }; + 2CD263402CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png */; }; + 2CD263412CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262202CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; + 2CD263422CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262212CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; + 2CD263432CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262222CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; + 2CD263442CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262232CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; + 2CD263452CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262242CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; + 2CD263462CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262252CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png */; }; + 2CD263472CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262262CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png */; }; + 2CD263482CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262272CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png */; }; + 2CD263492CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262282CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png */; }; + 2CD2634A2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262292CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png */; }; + 2CD2634B2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png */; }; + 2CD2634C2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png */; }; + 2CD2634D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png */; }; + 2CD2634E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png */; }; + 2CD2634F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png */; }; + 2CD263502CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png */; }; + 2CD263512CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262302CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png */; }; + 2CD263522CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262312CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png */; }; + 2CD263532CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262322CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png */; }; + 2CD263542CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262332CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png */; }; + 2CD263552CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262342CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; + 2CD263562CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262352CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; + 2CD263572CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262362CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; + 2CD263582CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262372CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; + 2CD263592CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262382CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; + 2CD2635A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262392CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png */; }; + 2CD2635B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png */; }; + 2CD2635C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png */; }; + 2CD2635D2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png */; }; + 2CD2635E2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png */; }; + 2CD2635F2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png */; }; + 2CD263602CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png */; }; + 2CD263612CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262402CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png */; }; + 2CD263622CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262412CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png */; }; + 2CD263632CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262422CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png */; }; + 2CD263642CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262432CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png */; }; + 2CD263652CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262442CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png */; }; + 2CD263662CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262452CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png */; }; + 2CD263672CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262462CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png */; }; + 2CD263682CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262472CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png */; }; + 2CD263692CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262482CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; + 2CD2636A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262492CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; + 2CD2636B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; + 2CD2636C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; + 2CD2636D2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; + 2CD2636E2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png */; }; + 2CD2636F2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png */; }; + 2CD263702CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png */; }; + 2CD263712CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262502CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png */; }; + 2CD263722CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262512CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png */; }; + 2CD263732CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262522CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png */; }; + 2CD263742CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262532CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png */; }; + 2CD263752CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262542CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png */; }; + 2CD263762CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262552CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png */; }; + 2CD263772CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262562CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png */; }; + 2CD263782CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262572CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png */; }; + 2CD263792CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262582CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png */; }; + 2CD2637A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262592CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png */; }; + 2CD2637B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png */; }; + 2CD2637C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png */; }; + 2CD2637D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; + 2CD2637E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; + 2CD2637F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; + 2CD263802CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; + 2CD263812CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262602CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; + 2CD263822CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262612CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png */; }; + 2CD263832CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262622CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png */; }; + 2CD263842CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262632CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png */; }; + 2CD263852CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262642CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png */; }; + 2CD263862CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262652CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png */; }; + 2CD263872CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262662CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png */; }; + 2CD263882CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262672CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png */; }; + 2CD263892CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262682CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png */; }; + 2CD2638A2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262692CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png */; }; + 2CD2638B2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png */; }; + 2CD2638C2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png */; }; + 2CD2638D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png */; }; + 2CD2638E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png */; }; + 2CD2638F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png */; }; + 2CD263902CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png */; }; + 2CD263912CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262702CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; + 2CD263922CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262712CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; + 2CD263932CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262722CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; + 2CD263942CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262732CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; + 2CD263952CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262742CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; + 2CD263962CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262752CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png */; }; + 2CD263972CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262762CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png */; }; + 2CD263982CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262772CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png */; }; + 2CD263992CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262782CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png */; }; + 2CD2639A2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262792CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png */; }; + 2CD2639B2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png */; }; + 2CD2639C2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png */; }; + 2CD2639D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png */; }; + 2CD2639E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png */; }; + 2CD2639F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png */; }; + 2CD263A02CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png */; }; + 2CD263A12CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262802CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png */; }; + 2CD263A22CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262812CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png */; }; + 2CD263A32CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262822CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png */; }; + 2CD263A42CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262832CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png */; }; + 2CD263A52CFDC5EB00A040A7 /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262862CFDC5E900A040A7 /* OnboardingTests.swift */; }; + 2CD263A62CFDC5EB00A040A7 /* DeviceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262882CFDC5E900A040A7 /* DeviceType.swift */; }; + 2CD263A72CFDC5EB00A040A7 /* EcosiaSnapshotTests.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262892CFDC5E900A040A7 /* EcosiaSnapshotTests.xctestplan */; }; + 2CD263A82CFDC5EB00A040A7 /* environment.json in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2628A2CFDC5E900A040A7 /* environment.json */; }; + 2CD263A92CFDC5EB00A040A7 /* LocaleRetriever.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628B2CFDC5E900A040A7 /* LocaleRetriever.swift */; }; + 2CD263AA2CFDC5EB00A040A7 /* LocalizationOverrideTestingBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628C2CFDC5E900A040A7 /* LocalizationOverrideTestingBundle.swift */; }; + 2CD263AB2CFDC5EB00A040A7 /* snapshot_configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2628D2CFDC5E900A040A7 /* snapshot_configuration.json */; }; + 2CD263AC2CFDC5EB00A040A7 /* SnapshotBaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628E2CFDC5E900A040A7 /* SnapshotBaseTests.swift */; }; + 2CD263AD2CFDC5EB00A040A7 /* SnapshotTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628F2CFDC5E900A040A7 /* SnapshotTestHelper.swift */; }; + 2CD263AE2CFDC5EB00A040A7 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262902CFDC5E900A040A7 /* String+Extension.swift */; }; + 2CD263AF2CFDC5EB00A040A7 /* VersionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262922CFDC5E900A040A7 /* VersionTests.swift */; }; + 2CD263B02CFDC5EB00A040A7 /* NTPComponentTests_tests.xcresult in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262932CFDC5E900A040A7 /* NTPComponentTests_tests.xcresult */; }; + 2CD263B12CFDC5EB00A040A7 /* OnboardingTests_tests.xcresult in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262942CFDC5E900A040A7 /* OnboardingTests_tests.xcresult */; }; + 2CD263B22CFDC5EB00A040A7 /* WhatsNewLocalDataProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262962CFDC5E900A040A7 /* WhatsNewLocalDataProviderTests.swift */; }; + 2CD263B32CFDC5EB00A040A7 /* AppDelegateFeatureManagementIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262972CFDC5EA00A040A7 /* AppDelegateFeatureManagementIntegrationTests.swift */; }; + 2CD263B42CFDC5EB00A040A7 /* EcosiaInstallTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262992CFDC5EA00A040A7 /* EcosiaInstallTypeTests.swift */; }; + 2CD263B52CFDC5EB00A040A7 /* EcosiaPerformanceTestHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2629A2CFDC5EA00A040A7 /* EcosiaPerformanceTestHistory.swift */; }; + 2CD263B62CFDC5EB00A040A7 /* MockAppVersionInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2629B2CFDC5EA00A040A7 /* MockAppVersionInfoProvider.swift */; }; + 2CD263B72CFDC5EB00A040A7 /* PrivateModeButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2629D2CFDC5EA00A040A7 /* PrivateModeButtonTests.swift */; }; + 2CD263B82CFDC5EB00A040A7 /* EcosiaNTPTooltipHighlightTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2629E2CFDC5EA00A040A7 /* EcosiaNTPTooltipHighlightTests.swift */; }; + 2CD263B92CFDC5EB00A040A7 /* EcosiaHomeViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2629F2CFDC5EA00A040A7 /* EcosiaHomeViewModelTests.swift */; }; + 2CD263BA2CFDC5EB00A040A7 /* UnleashUserDefaultsSeedProgressManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262A02CFDC5EA00A040A7 /* UnleashUserDefaultsSeedProgressManagerTests.swift */; }; + 2CD263BB2CFDC5EB00A040A7 /* UserDefaultsSeedProgressManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262A12CFDC5EA00A040A7 /* UserDefaultsSeedProgressManagerTests.swift */; }; + 2CD263BC2CFDC5EB00A040A7 /* EcosiaTopSitesHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262A32CFDC5EB00A040A7 /* EcosiaTopSitesHelperTests.swift */; }; + 2CD263BD2CFDC5EB00A040A7 /* EcosiaOverlayModeManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262A42CFDC5EB00A040A7 /* EcosiaOverlayModeManagerTests.swift */; }; + 2CD263BE2CFDC5EB00A040A7 /* EcosiaPageActionMenuCellTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262A52CFDC5EB00A040A7 /* EcosiaPageActionMenuCellTests.swift */; }; + 2CD263BF2CFDC5EB00A040A7 /* AnalyticsSpyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262A62CFDC5EB00A040A7 /* AnalyticsSpyTests.swift */; }; + 2CD263C02CFDC5EB00A040A7 /* AnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262A72CFDC5EB00A040A7 /* AnalyticsTests.swift */; }; + 2CD2648A2CFDC76A00A040A7 /* BrazeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263C12CFDC76800A040A7 /* BrazeService.swift */; }; + 2CD2648E2CFDC76A00A040A7 /* Ecosia.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263C92CFDC76800A040A7 /* Ecosia.strings */; }; + 2CD2648F2CFDC76A00A040A7 /* Ecosia.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263CB2CFDC76800A040A7 /* Ecosia.strings */; }; + 2CD264902CFDC76A00A040A7 /* Ecosia.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263CD2CFDC76800A040A7 /* Ecosia.strings */; }; + 2CD264912CFDC76A00A040A7 /* Ecosia.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263CF2CFDC76800A040A7 /* Ecosia.strings */; }; + 2CD264922CFDC76A00A040A7 /* Ecosia.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263D12CFDC76800A040A7 /* Ecosia.strings */; }; + 2CD264932CFDC76A00A040A7 /* Ecosia.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263D32CFDC76800A040A7 /* Ecosia.strings */; }; + 2CD264942CFDC76A00A040A7 /* Plurals.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263D52CFDC76800A040A7 /* Plurals.stringsdict */; }; + 2CD264952CFDC76A00A040A7 /* Plurals.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263D72CFDC76800A040A7 /* Plurals.stringsdict */; }; + 2CD264962CFDC76A00A040A7 /* Plurals.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263D92CFDC76800A040A7 /* Plurals.stringsdict */; }; + 2CD264972CFDC76A00A040A7 /* Plurals.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263DB2CFDC76800A040A7 /* Plurals.stringsdict */; }; + 2CD264982CFDC76A00A040A7 /* Plurals.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263DD2CFDC76800A040A7 /* Plurals.stringsdict */; }; + 2CD264992CFDC76A00A040A7 /* Plurals.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263DF2CFDC76800A040A7 /* Plurals.stringsdict */; }; + 2CD2649A2CFDC76A00A040A7 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263E02CFDC76800A040A7 /* String.swift */; }; + 2CD2649B2CFDC76A00A040A7 /* AppVersionInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263E22CFDC76800A040A7 /* AppVersionInfoProvider.swift */; }; + 2CD2649C2CFDC76A00A040A7 /* DefaultAppVersionInfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263E32CFDC76800A040A7 /* DefaultAppVersionInfoProvider.swift */; }; + 2CD2649D2CFDC76A00A040A7 /* EcosiaInstallType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263E52CFDC76800A040A7 /* EcosiaInstallType.swift */; }; + 2CD2649E2CFDC76A00A040A7 /* EcosiaInstallType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263E62CFDC76800A040A7 /* EcosiaInstallType+Extensions.swift */; }; + 2CD2649F2CFDC76A00A040A7 /* Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263E82CFDC76800A040A7 /* Version.swift */; }; + 2CD264A02CFDC76A00A040A7 /* Version+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263E92CFDC76800A040A7 /* Version+Extensions.swift */; }; + 2CD264A12CFDC76A00A040A7 /* Analytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263EC2CFDC76800A040A7 /* Analytics.swift */; }; + 2CD264A22CFDC76A00A040A7 /* Analytics.Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263ED2CFDC76800A040A7 /* Analytics.Values.swift */; }; + 2CD264A32CFDC76A00A040A7 /* Analytics+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263EE2CFDC76800A040A7 /* Analytics+Configuration.swift */; }; + 2CD264A42CFDC76A00A040A7 /* EcosiaLaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263F02CFDC76800A040A7 /* EcosiaLaunchScreen.xib */; }; + 2CD264A52CFDC76A00A040A7 /* EcosiaLaunchScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263F12CFDC76800A040A7 /* EcosiaLaunchScreenView.swift */; }; + 2CD264A92CFDC76A00A040A7 /* markets.json in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263F72CFDC76900A040A7 /* markets.json */; }; + 2CD264AC2CFDC76A00A040A7 /* FeatureManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263FE2CFDC76900A040A7 /* FeatureManagement.swift */; }; + 2CD264AD2CFDC76A00A040A7 /* MMP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD264002CFDC76900A040A7 /* MMP.swift */; }; + 2CD264FF2CFDC76A00A040A7 /* FakeNimbus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD264722CFDC76A00A040A7 /* FakeNimbus.swift */; }; + 2CD265002CFDC76A00A040A7 /* FakeSentry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD264732CFDC76A00A040A7 /* FakeSentry.swift */; }; + 2CD265012CFDC76A00A040A7 /* FakeTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD264742CFDC76A00A040A7 /* FakeTelemetry.swift */; }; + 2CD265522CFDCF0900A040A7 /* AppSettingsTableViewController+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265402CFDCF0900A040A7 /* AppSettingsTableViewController+Ecosia.swift */; }; + 2CD265532CFDCF0900A040A7 /* BrowserCoordinator+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265412CFDCF0900A040A7 /* BrowserCoordinator+Ecosia.swift */; }; + 2CD265542CFDCF0900A040A7 /* BrowserViewController+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265422CFDCF0900A040A7 /* BrowserViewController+Ecosia.swift */; }; + 2CD265562CFDCF0900A040A7 /* DispatchQueueHelper+BuildChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265442CFDCF0900A040A7 /* DispatchQueueHelper+BuildChannel.swift */; }; + 2CD265572CFDCF0900A040A7 /* ErrorPageHandler+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265452CFDCF0900A040A7 /* ErrorPageHandler+Ecosia.swift */; }; + 2CD265582CFDCF0900A040A7 /* HomepageViewController+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265462CFDCF0900A040A7 /* HomepageViewController+Ecosia.swift */; }; + 2CD265592CFDCF0900A040A7 /* LegacyThemeManager+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265472CFDCF0900A040A7 /* LegacyThemeManager+Ecosia.swift */; }; + 2CD2655A2CFDCF0900A040A7 /* NumberFormatter+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265482CFDCF0900A040A7 /* NumberFormatter+Ecosia.swift */; }; + 2CD2655B2CFDCF0900A040A7 /* SimpleToast+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265492CFDCF0900A040A7 /* SimpleToast+Ecosia.swift */; }; + 2CD2655C2CFDCF0900A040A7 /* SnapKit+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2654A2CFDCF0900A040A7 /* SnapKit+Ecosia.swift */; }; + 2CD2655D2CFDCF0900A040A7 /* UIButton+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2654B2CFDCF0900A040A7 /* UIButton+Ecosia.swift */; }; + 2CD2655E2CFDCF0900A040A7 /* UIFont+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2654C2CFDCF0900A040A7 /* UIFont+Ecosia.swift */; }; + 2CD2655F2CFDCF0900A040A7 /* UIView+maskedCorners.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2654D2CFDCF0900A040A7 /* UIView+maskedCorners.swift */; }; + 2CD265602CFDCF0900A040A7 /* URL+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2654E2CFDCF0900A040A7 /* URL+Ecosia.swift */; }; + 2CD265622CFDCF6D00A040A7 /* UIImage+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265612CFDCF6D00A040A7 /* UIImage+Ecosia.swift */; }; + 2CD265C52CFE382C00A040A7 /* MultiplyImpact.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265652CFE382C00A040A7 /* MultiplyImpact.swift */; }; + 2CD265C62CFE382C00A040A7 /* MultiplyImpactStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265662CFE382C00A040A7 /* MultiplyImpactStep.swift */; }; + 2CD265C72CFE382C00A040A7 /* AboutEcosiaSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265682CFE382C00A040A7 /* AboutEcosiaSection.swift */; }; + 2CD265C82CFE382C00A040A7 /* NTPAboutEcosiaCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265692CFE382C00A040A7 /* NTPAboutEcosiaCell.swift */; }; + 2CD265C92CFE382C00A040A7 /* NTPAboutEcosiaCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2656A2CFE382C00A040A7 /* NTPAboutEcosiaCellViewModel.swift */; }; + 2CD265CA2CFE382C00A040A7 /* SeedCounter.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2656D2CFE382C00A040A7 /* SeedCounter.xcdatamodeld */; }; + 2CD265CB2CFE382C00A040A7 /* SeedProgressManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2656F2CFE382C00A040A7 /* SeedProgressManagerProtocol.swift */; }; + 2CD265CC2CFE382C00A040A7 /* UserDefaultsSeedProgressManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265702CFE382C00A040A7 /* UserDefaultsSeedProgressManager.swift */; }; + 2CD265CD2CFE382C00A040A7 /* ArcProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265722CFE382C00A040A7 /* ArcProgressView.swift */; }; + 2CD265CE2CFE382C00A040A7 /* NTPSeedCounterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265732CFE382C00A040A7 /* NTPSeedCounterCell.swift */; }; + 2CD265CF2CFE382C00A040A7 /* NTPSeedCounterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265742CFE382C00A040A7 /* NTPSeedCounterViewModel.swift */; }; + 2CD265D02CFE382C00A040A7 /* SeedCounterConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265752CFE382C00A040A7 /* SeedCounterConfig.swift */; }; + 2CD265D12CFE382C00A040A7 /* SeedCounterHiddenSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265762CFE382C00A040A7 /* SeedCounterHiddenSettings.swift */; }; + 2CD265D22CFE382C00A040A7 /* SeedCounterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265772CFE382C00A040A7 /* SeedCounterView.swift */; }; + 2CD265D32CFE382C00A040A7 /* SeedProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265782CFE382C00A040A7 /* SeedProgressView.swift */; }; + 2CD265D42CFE382C00A040A7 /* Sparkle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265792CFE382C00A040A7 /* Sparkle.swift */; }; + 2CD265D52CFE382C00A040A7 /* CustomizableNTPSettingConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2657B2CFE382C00A040A7 /* CustomizableNTPSettingConfig.swift */; }; + 2CD265D62CFE382C00A040A7 /* NTPCustomizationCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2657C2CFE382C00A040A7 /* NTPCustomizationCell.swift */; }; + 2CD265D72CFE382C00A040A7 /* NTPCustomizationCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2657D2CFE382C00A040A7 /* NTPCustomizationCellViewModel.swift */; }; + 2CD265D82CFE382C00A040A7 /* ClimateImpactInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2657F2CFE382C00A040A7 /* ClimateImpactInfo.swift */; }; + 2CD265D92CFE382C00A040A7 /* NTPImpactCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265802CFE382C00A040A7 /* NTPImpactCell.swift */; }; + 2CD265DA2CFE382C00A040A7 /* NTPImpactCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265812CFE382C00A040A7 /* NTPImpactCellViewModel.swift */; }; + 2CD265DB2CFE382C00A040A7 /* NTPImpactDividerFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265822CFE382C00A040A7 /* NTPImpactDividerFooter.swift */; }; + 2CD265DC2CFE382C00A040A7 /* NTPImpactRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265832CFE382C00A040A7 /* NTPImpactRowView.swift */; }; + 2CD265DD2CFE382C00A040A7 /* ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265842CFE382C00A040A7 /* ProgressView.swift */; }; + 2CD265DE2CFE382C00A040A7 /* NTPLibaryCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265862CFE382C00A040A7 /* NTPLibaryCellViewModel.swift */; }; + 2CD265DF2CFE382C00A040A7 /* NTPLibraryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265872CFE382C00A040A7 /* NTPLibraryCell.swift */; }; + 2CD265E02CFE382C00A040A7 /* NTPLibraryShortcutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265882CFE382C00A040A7 /* NTPLibraryShortcutView.swift */; }; + 2CD265E12CFE382C00A040A7 /* NTPLogoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2658A2CFE382C00A040A7 /* NTPLogoCell.swift */; }; + 2CD265E22CFE382C00A040A7 /* NewsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2658C2CFE382C00A040A7 /* NewsController.swift */; }; + 2CD265E32CFE382C00A040A7 /* NTPNewsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2658D2CFE382C00A040A7 /* NTPNewsCell.swift */; }; + 2CD265E42CFE382C00A040A7 /* NTPNewsCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2658E2CFE382C00A040A7 /* NTPNewsCellViewModel.swift */; }; + 2CD265E52CFE382C00A040A7 /* NTPNewsletterCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265902CFE382C00A040A7 /* NTPNewsletterCardCell.swift */; }; + 2CD265E62CFE382C00A040A7 /* NTPNewsletterCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265912CFE382C00A040A7 /* NTPNewsletterCardViewModel.swift */; }; + 2CD265E72CFE382C00A040A7 /* NTPConfigurableNudgeCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265932CFE382C00A040A7 /* NTPConfigurableNudgeCardCell.swift */; }; + 2CD265E82CFE382C00A040A7 /* NTPConfigurableNudgeCardCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265942CFE382C00A040A7 /* NTPConfigurableNudgeCardCellViewModel.swift */; }; + 2CD265E92CFE382C00A040A7 /* CircleButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265962CFE382C00A040A7 /* CircleButton.swift */; }; + 2CD265EA2CFE382C00A040A7 /* DefaultBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265972CFE382C00A040A7 /* DefaultBrowser.swift */; }; + 2CD265EB2CFE382C00A040A7 /* NTPLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265982CFE382C00A040A7 /* NTPLayout.swift */; }; + 2CD265EC2CFE382C00A040A7 /* NTPTooltip.Highlight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265992CFE382C00A040A7 /* NTPTooltip.Highlight.swift */; }; + 2CD265ED2CFE382C00A040A7 /* NTPTooltip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2659A2CFE382C00A040A7 /* NTPTooltip.swift */; }; + 2CD265EE2CFE382C00A040A7 /* NTPTooltipDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2659B2CFE382C00A040A7 /* NTPTooltipDelegate.swift */; }; + 2CD265EF2CFE382C00A040A7 /* Welcome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2659D2CFE382C00A040A7 /* Welcome.swift */; }; + 2CD265F02CFE382C00A040A7 /* WelcomeNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2659E2CFE382C00A040A7 /* WelcomeNavigation.swift */; }; + 2CD265F12CFE382C00A040A7 /* WelcomeTour.Step.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2659F2CFE382C00A040A7 /* WelcomeTour.Step.swift */; }; + 2CD265F22CFE382C00A040A7 /* WelcomeTour.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265A02CFE382C00A040A7 /* WelcomeTour.swift */; }; + 2CD265F32CFE382C00A040A7 /* WelcomeTourAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265A12CFE382C00A040A7 /* WelcomeTourAction.swift */; }; + 2CD265F42CFE382C00A040A7 /* WelcomeTourGreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265A22CFE382C00A040A7 /* WelcomeTourGreen.swift */; }; + 2CD265F52CFE382C00A040A7 /* WelcomeTourProfit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265A32CFE382C00A040A7 /* WelcomeTourProfit.swift */; }; + 2CD265F62CFE382C00A040A7 /* WelcomeTourRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265A42CFE382C00A040A7 /* WelcomeTourRow.swift */; }; + 2CD265F72CFE382C00A040A7 /* WelcomeTourTransparent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265A52CFE382C00A040A7 /* WelcomeTourTransparent.swift */; }; + 2CD265F82CFE382C00A040A7 /* PageActionMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265A72CFE382C00A040A7 /* PageActionMenu.swift */; }; + 2CD265F92CFE382C00A040A7 /* PageActionMenuCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265A82CFE382C00A040A7 /* PageActionMenuCell.swift */; }; + 2CD265FA2CFE382C00A040A7 /* PageActionsShortcutsHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265A92CFE382C00A040A7 /* PageActionsShortcutsHeader.swift */; }; + 2CD265FB2CFE382C00A040A7 /* EcosiaTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265AB2CFE382C00A040A7 /* EcosiaTheme.swift */; }; + 2CD265FC2CFE382C00A040A7 /* EcosiaThemeColourPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265AC2CFE382C00A040A7 /* EcosiaThemeColourPalette.swift */; }; + 2CD265FD2CFE382C00A040A7 /* EcosiaThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265AD2CFE382C00A040A7 /* EcosiaThemeManager.swift */; }; + 2CD265FE2CFE382C00A040A7 /* WhatsNewDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265AF2CFE382C00A040A7 /* WhatsNewDataProvider.swift */; }; + 2CD265FF2CFE382C00A040A7 /* WhatsNewLocalDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265B02CFE382C00A040A7 /* WhatsNewLocalDataProvider.swift */; }; + 2CD266002CFE382C00A040A7 /* WhatsNewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265B22CFE382C00A040A7 /* WhatsNewCell.swift */; }; + 2CD266012CFE382C00A040A7 /* WhatsNewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265B32CFE382C00A040A7 /* WhatsNewItem.swift */; }; + 2CD266022CFE382C00A040A7 /* WhatsNewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265B42CFE382C00A040A7 /* WhatsNewViewController.swift */; }; + 2CD266032CFE382C00A040A7 /* WhatsNewViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265B52CFE382C00A040A7 /* WhatsNewViewModel.swift */; }; + 2CD266042CFE382C00A040A7 /* Colours.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CD265B72CFE382C00A040A7 /* Colours.xcassets */; }; + 2CD266052CFE382C00A040A7 /* Ecosia.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2CD265B82CFE382C00A040A7 /* Ecosia.xcassets */; }; + 2CD266062CFE382C00A040A7 /* EcosiaFindInPageBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265B92CFE382C00A040A7 /* EcosiaFindInPageBar.swift */; }; + 2CD266072CFE382C00A040A7 /* EcosiaNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265BA2CFE382C00A040A7 /* EcosiaNavigation.swift */; }; + 2CD266082CFE382C00A040A7 /* EmptyBookmarksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265BB2CFE382C00A040A7 /* EmptyBookmarksView.swift */; }; + 2CD266092CFE382C00A040A7 /* EmptyBookmarksViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265BC2CFE382C00A040A7 /* EmptyBookmarksViewDelegate.swift */; }; + 2CD2660A2CFE382C00A040A7 /* EmptyHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265BD2CFE382C00A040A7 /* EmptyHeader.swift */; }; + 2CD2660B2CFE382C00A040A7 /* EmptyReadingListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265BE2CFE382C00A040A7 /* EmptyReadingListView.swift */; }; + 2CD2660C2CFE382C00A040A7 /* FilterController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265BF2CFE382C00A040A7 /* FilterController.swift */; }; + 2CD2660D2CFE382C00A040A7 /* LoadingScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265C02CFE382C00A040A7 /* LoadingScreen.swift */; }; + 2CD2660E2CFE382C00A040A7 /* MarketsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265C12CFE382C00A040A7 /* MarketsController.swift */; }; + 2CD2660F2CFE382C00A040A7 /* SemanticColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265C22CFE382C00A040A7 /* SemanticColor.swift */; }; + 2CD2661A2CFE38AD00A040A7 /* EcosiaTopSiteItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD266102CFE38AD00A040A7 /* EcosiaTopSiteItemCell.swift */; }; + 2CD2661B2CFE38AD00A040A7 /* EcosiaHomepageSectionType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD266132CFE38AD00A040A7 /* EcosiaHomepageSectionType.swift */; }; + 2CD2661C2CFE38AD00A040A7 /* EcosiaDebugSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD266162CFE38AD00A040A7 /* EcosiaDebugSettings.swift */; }; + 2CD2661D2CFE38AD00A040A7 /* EcosiaSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD266172CFE38AD00A040A7 /* EcosiaSettings.swift */; }; + 2CD2661E2CFE38AD00A040A7 /* NTPCustomizationSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD266182CFE38AD00A040A7 /* NTPCustomizationSettingsViewController.swift */; }; + 2CD266202CFE39E300A040A7 /* EcosiaPrimaryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2661F2CFE39E300A040A7 /* EcosiaPrimaryButton.swift */; }; + 2CD266232CFE3ADA00A040A7 /* BookmarksExchange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD266212CFE3AD900A040A7 /* BookmarksExchange.swift */; }; + 2CD2662B2CFE402000A040A7 /* SeedCounterNTPExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2662A2CFE402000A040A7 /* SeedCounterNTPExperiment.swift */; }; + 2CD266322CFE403800A040A7 /* APNConsentOnLaunchExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2662C2CFE403800A040A7 /* APNConsentOnLaunchExperiment.swift */; }; + 2CD266332CFE403800A040A7 /* BrazeIntegrationExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2662D2CFE403800A040A7 /* BrazeIntegrationExperiment.swift */; }; + 2CD266342CFE403800A040A7 /* NewsletterCardExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2662E2CFE403800A040A7 /* NewsletterCardExperiment.swift */; }; + 2CD266352CFE403800A040A7 /* OnboardingRemoveExperiment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2662F2CFE403800A040A7 /* OnboardingRemoveExperiment.swift */; }; + 2CD2663C2CFE423D00A040A7 /* AppInfo+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2663B2CFE423D00A040A7 /* AppInfo+Ecosia.swift */; }; + 2CD2663E2CFF4ED000A040A7 /* DeviceInfo+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2663D2CFF4ED000A040A7 /* DeviceInfo+Ecosia.swift */; }; + 2CD2663F2CFF4FA300A040A7 /* EcosiaTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265AB2CFE382C00A040A7 /* EcosiaTheme.swift */; }; + 2CD266402CFF4FA300A040A7 /* EcosiaTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265AB2CFE382C00A040A7 /* EcosiaTheme.swift */; }; + 2CD266412CFF4FB200A040A7 /* LegacyThemeManager+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265472CFDCF0900A040A7 /* LegacyThemeManager+Ecosia.swift */; }; + 2CD266422CFF4FB200A040A7 /* LegacyThemeManager+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265472CFDCF0900A040A7 /* LegacyThemeManager+Ecosia.swift */; }; + 2CD266432CFF4FC300A040A7 /* SemanticColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265C22CFE382C00A040A7 /* SemanticColor.swift */; }; + 2CD266442CFF4FC400A040A7 /* SemanticColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265C22CFE382C00A040A7 /* SemanticColor.swift */; }; + 2CD266452CFF4FD100A040A7 /* EcosiaThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265AD2CFE382C00A040A7 /* EcosiaThemeManager.swift */; }; + 2CD266462CFF4FD200A040A7 /* EcosiaThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265AD2CFE382C00A040A7 /* EcosiaThemeManager.swift */; }; + 2CD266472CFF4FE800A040A7 /* EcosiaThemeColourPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265AC2CFE382C00A040A7 /* EcosiaThemeColourPalette.swift */; }; + 2CD266482CFF4FE800A040A7 /* EcosiaThemeColourPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265AC2CFE382C00A040A7 /* EcosiaThemeColourPalette.swift */; }; + 2CD266512CFF56CB00A040A7 /* ConnectionStatusImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2664E2CFF56CB00A040A7 /* ConnectionStatusImage.swift */; }; + 2CD266522CFF56CB00A040A7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2664F2CFF56CB00A040A7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift */; }; + 2CD266552CFF56EA00A040A7 /* WebsiteConnectionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD266532CFF56EA00A040A7 /* WebsiteConnectionStatus.swift */; }; 2CE294472B7CDD56006C22B2 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE294462B7CDD56006C22B2 /* Core */; }; 2CE294492B7CDD78006C22B2 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE294482B7CDD78006C22B2 /* Core */; }; 2CE2E24D2B9B1FCB00973C16 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE2E24C2B9B1FCB00973C16 /* Core */; }; @@ -2052,21 +2314,16 @@ 10CD44F0A402C84BB31E5474 /* gu-IN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "gu-IN"; path = "gu-IN.lproj/Intro.strings"; sourceTree = ""; }; 11F747589EB8A55A47647C93 /* bn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bn; path = bn.lproj/ClearPrivateData.strings; sourceTree = ""; }; 120F42119EB30F217AB9493E /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/FindInPage.strings; sourceTree = ""; }; - 12147F2E2CDA3CD00009D300 /* NTPNewsletterCardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NTPNewsletterCardCell.swift; sourceTree = ""; }; - 12147F302CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NTPNewsletterCardViewModel.swift; sourceTree = ""; }; - 12147F322CDBA7230009D300 /* NewsletterCardExperiment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsletterCardExperiment.swift; sourceTree = ""; }; 1229356A2CE78D0A00EC1297 /* Ecosia.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Ecosia.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1229356C2CE78D0A00EC1297 /* Ecosia.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Ecosia.h; sourceTree = ""; }; 122935732CE78D0A00EC1297 /* EcosiaTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = EcosiaTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 1229359B2CE7927800EC1297 /* BrazeService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrazeService.swift; sourceTree = ""; }; 1229359D2CE792B700EC1297 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 123045959E0F295753B4B4DB /* lo */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lo; path = lo.lproj/Today.strings; sourceTree = ""; }; 126509882CDA31890011BA36 /* BrazeServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrazeServiceTests.swift; sourceTree = ""; }; 12674A038346A46589A0AC0B /* el */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = el; path = "el.lproj/Default Browser.strings"; sourceTree = ""; }; 126A40A4A5AFDFD655B0FDF4 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/ClearHistoryConfirm.strings; sourceTree = ""; }; 126F44CCB14373DC7813DE1F /* hr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hr; path = hr.lproj/ClearPrivateDataConfirm.strings; sourceTree = ""; }; - 1285E2B42CC293CA0053506B /* AnalyticsSpyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsSpyTests.swift; sourceTree = ""; }; - 1285E2B62CC68BF00053506B /* APNConsent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APNConsent.swift; sourceTree = ""; }; + 12E604442CECADDA009A7BEC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 12EA4881BFBE296298150D4A /* bn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bn; path = bn.lproj/LoginManager.strings; sourceTree = ""; }; 12F949169C30744CCC749588 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/HistoryPanel.strings; sourceTree = ""; }; 1323403C8071FC19BB79C191 /* su */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = su; path = su.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -2396,15 +2653,8 @@ 2BAA411FAF1D49B9990A7720 /* sat-Olck */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "sat-Olck"; path = "sat-Olck.lproj/Shared.strings"; sourceTree = ""; }; 2BAB4A40A318F5A577488909 /* mr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = mr; path = mr.lproj/InfoPlist.strings; sourceTree = ""; }; 2C0360D92C1747E6006706F2 /* FxNimbus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FxNimbus.swift; sourceTree = ""; }; - 2C03A4142CB7C7CC00AB228B /* DispatchQueueHelper+BuildChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DispatchQueueHelper+BuildChannel.swift"; sourceTree = ""; }; - 2C08319B2B89127200BD7134 /* Ecosia.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Ecosia.entitlements; sourceTree = ""; }; - 2C08319C2B89127200BD7134 /* EcosiaBeta.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = EcosiaBeta.entitlements; sourceTree = ""; }; 2C1298A42BF5EB16005AE4E4 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; - 2C16B7652CAF2425006118F8 /* UserDefaultsSeedProgressManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsSeedProgressManagerTests.swift; sourceTree = ""; }; - 2C19DACE2C74C7BF00D2641C /* snapshot_configuration.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = snapshot_configuration.json; sourceTree = ""; }; - 2C2349A22C57E5BC007A5894 /* EcosiaPerformanceTestHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EcosiaPerformanceTestHistory.swift; sourceTree = ""; }; 2C26401D9CCB8C2671EA2431 /* ta */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ta; path = ta.lproj/3DTouchActions.strings; sourceTree = ""; }; - 2C26EA132C04CAD100795552 /* EcosiaTopSitesHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EcosiaTopSitesHelperTests.swift; sourceTree = ""; }; 2C2A5EF31E68469500F02659 /* PrivateBrowsingTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateBrowsingTest.swift; sourceTree = ""; }; 2C2A91281FA2410D002E36BD /* HistoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryTests.swift; sourceTree = ""; }; 2C31A7A81E8BFB2200DAC646 /* ReadingListTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadingListTests.swift; sourceTree = ""; }; @@ -2414,161 +2664,14 @@ 2C473BCF209778900008C853 /* DownloadsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadsTests.swift; sourceTree = ""; }; 2C49854D206173C800893DAE /* photon-colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "photon-colors.swift"; sourceTree = ""; }; 2C4A07DB20246EAD0083E320 /* DragAndDropTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DragAndDropTests.swift; sourceTree = ""; }; - 2C4ABD482CB58E4F00FF86F9 /* Sparkle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sparkle.swift; sourceTree = ""; }; 2C4B6BF220349EB800A009C2 /* OnboardingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTests.swift; sourceTree = ""; }; - 2C4D165F2C76360800E89C95 /* environment.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = environment.json; sourceTree = ""; }; - 2C5A5E642CB53DB7005BFE8B /* SeedCounterConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedCounterConfig.swift; sourceTree = ""; }; - 2C5A5E662CB53DF9005BFE8B /* UserDefaultsSeedProgressManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsSeedProgressManager.swift; sourceTree = ""; }; - 2C5B81C72C75388300B81D95 /* LocaleRetriever.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocaleRetriever.swift; sourceTree = ""; }; 2C6045859589979C43AF09E0 /* jv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = jv; path = jv.lproj/ClearPrivateDataConfirm.strings; sourceTree = ""; }; - 2C6188802B7A8A21006B70D7 /* EcosiaLaunchScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaLaunchScreenView.swift; sourceTree = ""; }; - 2C6188812B7A8A21006B70D7 /* EcosiaLaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EcosiaLaunchScreen.xib; sourceTree = ""; }; - 2C6188832B7A8A21006B70D7 /* MMP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MMP.swift; sourceTree = ""; }; - 2C6188852B7A8A21006B70D7 /* SemanticColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemanticColor.swift; sourceTree = ""; }; - 2C6188872B7A8A21006B70D7 /* PageActionMenuCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageActionMenuCell.swift; sourceTree = ""; }; - 2C6188882B7A8A21006B70D7 /* PageActionsShortcutsHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageActionsShortcutsHeader.swift; sourceTree = ""; }; - 2C6188892B7A8A21006B70D7 /* PageActionMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageActionMenu.swift; sourceTree = ""; }; - 2C61888A2B7A8A21006B70D7 /* EmptyBookmarksViewDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyBookmarksViewDelegate.swift; sourceTree = ""; }; - 2C61888B2B7A8A21006B70D7 /* EcosiaFindInPageBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaFindInPageBar.swift; sourceTree = ""; }; - 2C61888C2B7A8A21006B70D7 /* Ecosia.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Ecosia.xcassets; sourceTree = ""; }; - 2C61888D2B7A8A21006B70D7 /* EmptyReadingListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyReadingListView.swift; sourceTree = ""; }; - 2C6188942B7A8A21006B70D7 /* EmptyHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyHeader.swift; sourceTree = ""; }; - 2C6188962B7A8A21006B70D7 /* WhatsNewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewCell.swift; sourceTree = ""; }; - 2C6188972B7A8A21006B70D7 /* WhatsNewViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewViewModel.swift; sourceTree = ""; }; - 2C6188982B7A8A21006B70D7 /* WhatsNewViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewViewController.swift; sourceTree = ""; }; - 2C6188992B7A8A21006B70D7 /* WhatsNewItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewItem.swift; sourceTree = ""; }; - 2C61889B2B7A8A21006B70D7 /* WhatsNewDataProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewDataProvider.swift; sourceTree = ""; }; - 2C61889C2B7A8A21006B70D7 /* WhatsNewLocalDataProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewLocalDataProvider.swift; sourceTree = ""; }; - 2C61889E2B7A8A21006B70D7 /* NTPLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPLayout.swift; sourceTree = ""; }; - 2C61889F2B7A8A21006B70D7 /* DefaultBrowser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultBrowser.swift; sourceTree = ""; }; - 2C6188A12B7A8A21006B70D7 /* CustomizableNTPSettingConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomizableNTPSettingConfig.swift; sourceTree = ""; }; - 2C6188A22B7A8A21006B70D7 /* NTPCustomizationCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPCustomizationCell.swift; sourceTree = ""; }; - 2C6188A32B7A8A21006B70D7 /* NTPCustomizationCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPCustomizationCellViewModel.swift; sourceTree = ""; }; - 2C6188A52B7A8A21006B70D7 /* NTPLibraryShortcutView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPLibraryShortcutView.swift; sourceTree = ""; }; - 2C6188A62B7A8A21006B70D7 /* NTPLibraryCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPLibraryCell.swift; sourceTree = ""; }; - 2C6188A72B7A8A21006B70D7 /* NTPLibaryCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPLibaryCellViewModel.swift; sourceTree = ""; }; - 2C6188A82B7A8A21006B70D7 /* NTPTooltip.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPTooltip.swift; sourceTree = ""; }; - 2C6188A92B7A8A21006B70D7 /* CircleButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircleButton.swift; sourceTree = ""; }; - 2C6188AA2B7A8A21006B70D7 /* NTPTooltip.Highlight.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPTooltip.Highlight.swift; sourceTree = ""; }; - 2C6188AF2B7A8A22006B70D7 /* NewsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsController.swift; sourceTree = ""; }; - 2C6188B02B7A8A22006B70D7 /* NTPNewsCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPNewsCellViewModel.swift; sourceTree = ""; }; - 2C6188B12B7A8A22006B70D7 /* NTPNewsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPNewsCell.swift; sourceTree = ""; }; - 2C6188B32B7A8A22006B70D7 /* NTPLogoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPLogoCell.swift; sourceTree = ""; }; - 2C6188B42B7A8A22006B70D7 /* NTPTooltipDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPTooltipDelegate.swift; sourceTree = ""; }; - 2C6188B62B7A8A22006B70D7 /* ProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressView.swift; sourceTree = ""; }; - 2C6188B72B7A8A22006B70D7 /* NTPImpactCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPImpactCell.swift; sourceTree = ""; }; - 2C6188B82B7A8A22006B70D7 /* NTPImpactCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPImpactCellViewModel.swift; sourceTree = ""; }; - 2C6188B92B7A8A22006B70D7 /* NTPImpactRowView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPImpactRowView.swift; sourceTree = ""; }; - 2C6188BA2B7A8A22006B70D7 /* NTPImpactDividerFooter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPImpactDividerFooter.swift; sourceTree = ""; }; - 2C6188BB2B7A8A22006B70D7 /* ClimateImpactInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClimateImpactInfo.swift; sourceTree = ""; }; - 2C6188BD2B7A8A22006B70D7 /* AboutEcosiaSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutEcosiaSection.swift; sourceTree = ""; }; - 2C6188BE2B7A8A22006B70D7 /* NTPAboutEcosiaCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPAboutEcosiaCellViewModel.swift; sourceTree = ""; }; - 2C6188BF2B7A8A22006B70D7 /* NTPAboutEcosiaCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPAboutEcosiaCell.swift; sourceTree = ""; }; - 2C6188C02B7A8A22006B70D7 /* Colours.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colours.xcassets; sourceTree = ""; }; - 2C6188C12B7A8A22006B70D7 /* EcosiaNavigation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaNavigation.swift; sourceTree = ""; }; - 2C6188C32B7A8A22006B70D7 /* EcosiaThemeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaThemeManager.swift; sourceTree = ""; }; - 2C6188C42B7A8A22006B70D7 /* EcosiaThemeColourPalette.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaThemeColourPalette.swift; sourceTree = ""; }; - 2C6188C52B7A8A22006B70D7 /* EcosiaTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaTheme.swift; sourceTree = ""; }; - 2C6188C62B7A8A22006B70D7 /* FilterController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterController.swift; sourceTree = ""; }; - 2C6188C72B7A8A22006B70D7 /* MarketsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketsController.swift; sourceTree = ""; }; - 2C6188C82B7A8A22006B70D7 /* EmptyBookmarksView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyBookmarksView.swift; sourceTree = ""; }; - 2C6188CA2B7A8A22006B70D7 /* WelcomeTourRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTourRow.swift; sourceTree = ""; }; - 2C6188CB2B7A8A22006B70D7 /* Welcome.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Welcome.swift; sourceTree = ""; }; - 2C6188CC2B7A8A22006B70D7 /* WelcomeTour.Step.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTour.Step.swift; sourceTree = ""; }; - 2C6188CD2B7A8A22006B70D7 /* WelcomeTourAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTourAction.swift; sourceTree = ""; }; - 2C6188CE2B7A8A22006B70D7 /* WelcomeTour.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTour.swift; sourceTree = ""; }; - 2C6188CF2B7A8A22006B70D7 /* WelcomeTourTransparent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTourTransparent.swift; sourceTree = ""; }; - 2C6188D02B7A8A22006B70D7 /* WelcomeTourGreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTourGreen.swift; sourceTree = ""; }; - 2C6188D12B7A8A22006B70D7 /* WelcomeNavigation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeNavigation.swift; sourceTree = ""; }; - 2C6188D22B7A8A22006B70D7 /* WelcomeTourProfit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTourProfit.swift; sourceTree = ""; }; - 2C6188D42B7A8A22006B70D7 /* MultiplyImpact.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiplyImpact.swift; sourceTree = ""; }; - 2C6188D52B7A8A22006B70D7 /* MultiplyImpactStep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiplyImpactStep.swift; sourceTree = ""; }; - 2C6188D72B7A8A22006B70D7 /* EcosiaDebugSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaDebugSettings.swift; sourceTree = ""; }; - 2C6188D82B7A8A22006B70D7 /* EcosiaSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaSettings.swift; sourceTree = ""; }; - 2C6188D92B7A8A22006B70D7 /* NTPCustomizationSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPCustomizationSettingsViewController.swift; sourceTree = ""; }; - 2C6188DC2B7A8A22006B70D7 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Ecosia.strings; sourceTree = ""; }; - 2C6188DE2B7A8A22006B70D7 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = de; path = de.lproj/Plurals.stringsdict; sourceTree = ""; }; - 2C6188DF2B7A8A22006B70D7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Ecosia.strings; sourceTree = ""; }; - 2C6188E02B7A8A22006B70D7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Plurals.stringsdict; sourceTree = ""; }; - 2C6188E12B7A8A22006B70D7 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Ecosia.strings; sourceTree = ""; }; - 2C6188E22B7A8A22006B70D7 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = es; path = es.lproj/Plurals.stringsdict; sourceTree = ""; }; - 2C6188E32B7A8A22006B70D7 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Ecosia.strings; sourceTree = ""; }; - 2C6188E42B7A8A22006B70D7 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = it; path = it.lproj/Plurals.stringsdict; sourceTree = ""; }; - 2C6188E62B7A8A22006B70D7 /* Clean.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Clean.swift; sourceTree = ""; }; - 2C6188E72B7A8A22006B70D7 /* Validate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Validate.swift; sourceTree = ""; }; - 2C6188E82B7A8A22006B70D7 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; - 2C6188E92B7A8A22006B70D7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Ecosia.strings; sourceTree = ""; }; - 2C6188EA2B7A8A22006B70D7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Plurals.stringsdict; sourceTree = ""; }; - 2C6188EB2B7A8A22006B70D7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Ecosia.strings; sourceTree = ""; }; - 2C6188EC2B7A8A22006B70D7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nl; path = nl.lproj/Plurals.stringsdict; sourceTree = ""; }; - 2C6188EE2B7A8A22006B70D7 /* FeatureManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureManagement.swift; sourceTree = ""; }; - 2C6188F12B7A8A22006B70D7 /* EcosiaHomepageSectionType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaHomepageSectionType.swift; sourceTree = ""; }; - 2C6188F42B7A8A22006B70D7 /* EcosiaTopSiteItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaTopSiteItemCell.swift; sourceTree = ""; }; - 2C6188F82B7A8A22006B70D7 /* BrazeIntegrationExperiment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrazeIntegrationExperiment.swift; sourceTree = ""; }; - 2C6188FB2B7A8A22006B70D7 /* WebsiteConnectionStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebsiteConnectionStatus.swift; sourceTree = ""; }; - 2C6189002B7A8A22006B70D7 /* BrowserViewController+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+Ecosia.swift"; sourceTree = ""; }; - 2C6189012B7A8A22006B70D7 /* LegacyThemeManager+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LegacyThemeManager+Ecosia.swift"; sourceTree = ""; }; - 2C6189022B7A8A22006B70D7 /* UIButton+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIButton+Ecosia.swift"; sourceTree = ""; }; - 2C6189032B7A8A22006B70D7 /* UIFont+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIFont+Ecosia.swift"; sourceTree = ""; }; - 2C6189042B7A8A22006B70D7 /* ErrorPageHandler+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ErrorPageHandler+Ecosia.swift"; sourceTree = ""; }; - 2C6189052B7A8A22006B70D7 /* SnapKit+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SnapKit+Ecosia.swift"; sourceTree = ""; }; - 2C6189062B7A8A22006B70D7 /* HomepageViewController+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HomepageViewController+Ecosia.swift"; sourceTree = ""; }; - 2C6189072B7A8A22006B70D7 /* SimpleToast+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SimpleToast+Ecosia.swift"; sourceTree = ""; }; - 2C6189082B7A8A22006B70D7 /* UIView+maskedCorners.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+maskedCorners.swift"; sourceTree = ""; }; - 2C6189092B7A8A22006B70D7 /* AppInfo+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AppInfo+Ecosia.swift"; sourceTree = ""; }; - 2C61890A2B7A8A22006B70D7 /* NumberFormatter+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NumberFormatter+Ecosia.swift"; sourceTree = ""; }; - 2C61890B2B7A8A22006B70D7 /* URL+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URL+Ecosia.swift"; sourceTree = ""; }; - 2C61890C2B7A8A22006B70D7 /* BrowserCoordinator+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BrowserCoordinator+Ecosia.swift"; sourceTree = ""; }; - 2C61890D2B7A8A22006B70D7 /* AppSettingsTableViewController+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AppSettingsTableViewController+Ecosia.swift"; sourceTree = ""; }; - 2C61890E2B7A8A22006B70D7 /* DeviceInfo+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DeviceInfo+Ecosia.swift"; sourceTree = ""; }; - 2C6189102B7A8A22006B70D7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConnectionStatusImage+WebsiteConnectionTypeStatus.swift"; sourceTree = ""; }; - 2C6189122B7A8A22006B70D7 /* ConnectionStatusImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionStatusImage.swift; sourceTree = ""; }; - 2C6189142B7A8A22006B70D7 /* EcosiaBeta.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = EcosiaBeta.entitlements; sourceTree = ""; }; - 2C6189152B7A8A22006B70D7 /* Ecosia.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Ecosia.entitlements; sourceTree = ""; }; - 2C6189172B7A8A22006B70D7 /* BookmarksExchange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksExchange.swift; sourceTree = ""; }; - 2C6189182B7A8A22006B70D7 /* markets.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = markets.json; sourceTree = ""; }; - 2C61891A2B7A8A22006B70D7 /* FakeTelemetry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FakeTelemetry.swift; sourceTree = ""; }; - 2C61891B2B7A8A22006B70D7 /* FakeNimbus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FakeNimbus.swift; sourceTree = ""; }; - 2C61891C2B7A8A22006B70D7 /* FakeSentry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FakeSentry.swift; sourceTree = ""; }; - 2C6189252B7A8A22006B70D7 /* DefaultAppVersionInfoProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultAppVersionInfoProvider.swift; sourceTree = ""; }; - 2C6189262B7A8A22006B70D7 /* AppVersionInfoProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppVersionInfoProvider.swift; sourceTree = ""; }; - 2C6189282B7A8A22006B70D7 /* EcosiaInstallType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaInstallType.swift; sourceTree = ""; }; - 2C6189292B7A8A22006B70D7 /* EcosiaInstallType+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "EcosiaInstallType+Extensions.swift"; sourceTree = ""; }; - 2C61892B2B7A8A22006B70D7 /* Version.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Version.swift; sourceTree = ""; }; - 2C61892C2B7A8A22006B70D7 /* Version+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Version+Extensions.swift"; sourceTree = ""; }; - 2C61892E2B7A8A22006B70D7 /* Analytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Analytics.swift; sourceTree = ""; }; - 2C61892F2B7A8A22006B70D7 /* Analytics+Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Analytics+Configuration.swift"; sourceTree = ""; }; - 2C6189302B7A8A22006B70D7 /* Analytics.Values.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Analytics.Values.swift; sourceTree = ""; }; - 2C69DA712C62175400D7F69F /* SnapshotTestHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotTestHelper.swift; sourceTree = ""; }; - 2C69DA742C62185A00D7F69F /* Welcome.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Welcome.swift; sourceTree = ""; }; - 2C69DA762C62243300D7F69F /* NTPTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NTPTests.swift; sourceTree = ""; }; - 2C69DA832C62B44B00D7F69F /* NTPComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NTPComponentTests.swift; sourceTree = ""; }; - 2C69DA912C63A92D00D7F69F /* SnapshotBaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotBaseTests.swift; sourceTree = ""; }; - 2C69DA932C63B0C000D7F69F /* String+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = ""; }; - 2C6B5B3A2CAAF27F00F15323 /* NTPSeedCounterCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPSeedCounterCell.swift; sourceTree = ""; }; - 2C6B5B3B2CAAF27F00F15323 /* NTPSeedCounterViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPSeedCounterViewModel.swift; sourceTree = ""; }; - 2C6B5B402CAAF3AA00F15323 /* SeedCounterNTPExperiment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedCounterNTPExperiment.swift; sourceTree = ""; }; 2C6C90822C614A16007D9B43 /* EcosiaSnapshotTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = EcosiaSnapshotTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 2C6E44099EACF7BE5438CEB6 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Today.strings; sourceTree = ""; }; - 2C728D7D2CBBDCDC00C7684B /* UnleashUserDefaultsSeedProgressManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnleashUserDefaultsSeedProgressManagerTests.swift; sourceTree = ""; }; - 2C7DBABB2C4EA17200BCD03F /* AppDelegateFeatureManagementIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegateFeatureManagementIntegrationTests.swift; sourceTree = ""; }; - 2C8262572C64424300E2A255 /* EcosiaSnapshotTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = EcosiaSnapshotTests.xctestplan; sourceTree = ""; }; - 2C8262592C64BB9300E2A255 /* DeviceType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceType.swift; sourceTree = ""; }; - 2C82625B2C6648D900E2A255 /* LocalizationOverrideTestingBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationOverrideTestingBundle.swift; sourceTree = ""; }; - 2C82625D2C66661700E2A255 /* EcosiaMockThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EcosiaMockThemeManager.swift; sourceTree = ""; }; - 2C872A532B8CD47600B318A0 /* MockAppVersionInfoProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAppVersionInfoProvider.swift; sourceTree = ""; }; - 2C872A562B8CD65100B318A0 /* EcosiaHomeViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EcosiaHomeViewModelTests.swift; sourceTree = ""; }; 2C8C07761E7800EA00DC1237 /* FindInPageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FindInPageTests.swift; sourceTree = ""; }; 2C9144B0B15218D8A0FCD538 /* es-AR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-AR"; path = "es-AR.lproj/ClearPrivateData.strings"; sourceTree = ""; }; - 2C9258D82CEF97B100C6BB8D /* MockUNNotificationSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUNNotificationSettings.swift; sourceTree = ""; }; - 2C9258DA2CEFB26500C6BB8D /* AnalyticsNotificationSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsNotificationSettings.swift; sourceTree = ""; }; 2C97EC701E72C80E0092EC18 /* TopTabsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopTabsTest.swift; sourceTree = ""; }; - 2C9A62BF2CDE1F7600CDA7D1 /* MockWelcomeDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockWelcomeDelegate.swift; sourceTree = ""; }; - 2C9A62C12CDE4A3B00CDA7D1 /* MockNewsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockNewsModel.swift; sourceTree = ""; }; 2CA16FDD1E5F089100332277 /* SearchTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchTest.swift; sourceTree = ""; }; - 2CA995272CA2C06A001064CC /* NTPConfigurableNudgeCardCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NTPConfigurableNudgeCardCell.swift; sourceTree = ""; }; - 2CA995292CA2C0BB001064CC /* NTPConfigurableNudgeCardCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NTPConfigurableNudgeCardCellViewModel.swift; sourceTree = ""; }; - 2CABD7272C12EF1E00A0750F /* PrivateModeButtonTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateModeButtonTests.swift; sourceTree = ""; }; 2CAE4511992E91A32AB7D7C7 /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = th; path = th.lproj/Today.strings; sourceTree = ""; }; 2CB1728B2C61336D008551E2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; 2CB1A6591FDEA8B60084E96D /* NewTabSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabSettings.swift; sourceTree = ""; }; @@ -2595,22 +2698,432 @@ 2CBCAB0E2B88EEE40080AD68 /* EcosiaDebug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = EcosiaDebug.xcconfig; sourceTree = ""; }; 2CC1B3EF1E9B861400814EEC /* DomainAutocompleteTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainAutocompleteTests.swift; sourceTree = ""; }; 2CCB296620A99C9500121DD8 /* LoginsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginsTests.swift; sourceTree = ""; }; - 2CCBB5222CAE9826006E2E10 /* ArcProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArcProgressView.swift; sourceTree = ""; }; - 2CCBB5242CAEA9DF006E2E10 /* SeedProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedProgressView.swift; sourceTree = ""; }; - 2CCBB5262CAEAD53006E2E10 /* SeedCounterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedCounterView.swift; sourceTree = ""; }; - 2CCBB5342CAF06DE006E2E10 /* SeedProgressManagerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedProgressManagerProtocol.swift; sourceTree = ""; }; - 2CCBB5362CAF0E8C006E2E10 /* SeedCounterHiddenSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeedCounterHiddenSettings.swift; sourceTree = ""; }; 2CCF17522105E4FD00705AE5 /* DisplaySettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplaySettingsTests.swift; sourceTree = ""; }; - 2CCFB3D42C0F1EA500BEDCA0 /* LoadingScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingScreen.swift; sourceTree = ""; }; - 2CD368492C5BC31700972871 /* OnboardingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTests.swift; sourceTree = ""; }; - 2CD48B7E2C7F7E4100A70908 /* EcosiaOverlayModeManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EcosiaOverlayModeManagerTests.swift; sourceTree = ""; }; + 2CD261842CFDC5E900A040A7 /* EcosiaMockThemeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaMockThemeManager.swift; sourceTree = ""; }; + 2CD261852CFDC5E900A040A7 /* Welcome.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Welcome.swift; sourceTree = ""; }; + 2CD261872CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261882CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261892CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD2618A2CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD2618B2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD2618C2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD2618D2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD2618E2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD2618F2CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261902CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261912CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261922CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261932CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261942CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261952CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261962CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261972CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261982CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261992CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD2619A2CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD2619B2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD2619C2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD2619D2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLibraryCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD2619E2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLibraryCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD2619F2CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLogoCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261A02CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLogoCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261A12CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLogoCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261A22CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLogoCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261A32CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPNewsCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261A42CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPNewsCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261A52CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPNewsCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261A62CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPNewsCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261A72CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261A82CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261A92CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261AA2CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261AB2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261AC2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261AD2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261AE2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261AF2CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261B02CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261B12CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261B22CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261B32CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261B42CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261B52CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261B62CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261B92CFDC5E900A040A7 /* NTPComponentTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPComponentTests.swift; sourceTree = ""; }; + 2CD261BA2CFDC5E900A040A7 /* NTPTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPTests.swift; sourceTree = ""; }; + 2CD261BC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; + 2CD261BD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; + 2CD261BE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; + 2CD261BF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; + 2CD261C02CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; + 2CD261C12CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; + 2CD261C22CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261C32CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261C42CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; + 2CD261C52CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; + 2CD261C62CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; + 2CD261C72CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; + 2CD261C82CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; + 2CD261C92CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; + 2CD261CA2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; + 2CD261CB2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; + 2CD261CC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; + 2CD261CD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; + 2CD261CE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; + 2CD261CF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; + 2CD261D02CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; + 2CD261D12CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; + 2CD261D22CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; + 2CD261D32CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; + 2CD261D42CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; + 2CD261D52CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; + 2CD261D62CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261D72CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261D82CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; + 2CD261D92CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; + 2CD261DA2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; + 2CD261DB2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; + 2CD261DC2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; + 2CD261DD2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; + 2CD261DE2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; + 2CD261DF2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; + 2CD261E02CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; + 2CD261E12CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; + 2CD261E22CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; + 2CD261E32CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; + 2CD261E42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; + 2CD261E52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; + 2CD261E62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; + 2CD261E72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; + 2CD261E82CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; + 2CD261E92CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; + 2CD261EA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261EB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD261EC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; + 2CD261ED2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; + 2CD261EE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; + 2CD261EF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; + 2CD261F02CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; + 2CD261F12CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; + 2CD261F22CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; + 2CD261F32CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; + 2CD261F42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; + 2CD261F52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; + 2CD261F62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; + 2CD261F72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; + 2CD261F82CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; + 2CD261F92CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; + 2CD261FA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; + 2CD261FB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; + 2CD261FC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; + 2CD261FD2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; + 2CD261FE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD261FF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD262002CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; + 2CD262012CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; + 2CD262022CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; + 2CD262032CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; + 2CD262042CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; + 2CD262052CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; + 2CD262062CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; + 2CD262072CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; + 2CD262082CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; + 2CD262092CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; + 2CD2620A2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; + 2CD2620B2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; + 2CD2620C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; + 2CD2620D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; + 2CD2620E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; + 2CD2620F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; + 2CD262102CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; + 2CD262112CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; + 2CD262122CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD262132CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD262142CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; + 2CD262152CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; + 2CD262162CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; + 2CD262172CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; + 2CD262182CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; + 2CD262192CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; + 2CD2621A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; + 2CD2621B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; + 2CD2621C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; + 2CD2621D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; + 2CD2621E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; + 2CD2621F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; + 2CD262202CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; + 2CD262212CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; + 2CD262222CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; + 2CD262232CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; + 2CD262242CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; + 2CD262252CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; + 2CD262262CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD262272CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD262282CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; + 2CD262292CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; + 2CD2622A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; + 2CD2622B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; + 2CD2622C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; + 2CD2622D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; + 2CD2622E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; + 2CD2622F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; + 2CD262302CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; + 2CD262312CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; + 2CD262322CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; + 2CD262332CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; + 2CD262342CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; + 2CD262352CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; + 2CD262362CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; + 2CD262372CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; + 2CD262382CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; + 2CD262392CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; + 2CD2623A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD2623B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD2623C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; + 2CD2623D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; + 2CD2623E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; + 2CD2623F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; + 2CD262402CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; + 2CD262412CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; + 2CD262422CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; + 2CD262432CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; + 2CD262442CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; + 2CD262452CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; + 2CD262462CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; + 2CD262472CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; + 2CD262482CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; + 2CD262492CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; + 2CD2624A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; + 2CD2624B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; + 2CD2624C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; + 2CD2624D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; + 2CD2624E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD2624F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD262502CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; + 2CD262512CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; + 2CD262522CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; + 2CD262532CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; + 2CD262542CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; + 2CD262552CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; + 2CD262562CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; + 2CD262572CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; + 2CD262582CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; + 2CD262592CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; + 2CD2625A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; + 2CD2625B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; + 2CD2625C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; + 2CD2625D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; + 2CD2625E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; + 2CD2625F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; + 2CD262602CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; + 2CD262612CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; + 2CD262622CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD262632CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD262642CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; + 2CD262652CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; + 2CD262662CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; + 2CD262672CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; + 2CD262682CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; + 2CD262692CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; + 2CD2626A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; + 2CD2626B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; + 2CD2626C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; + 2CD2626D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; + 2CD2626E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; + 2CD2626F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; + 2CD262702CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; + 2CD262712CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; + 2CD262722CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; + 2CD262732CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; + 2CD262742CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; + 2CD262752CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; + 2CD262762CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; + 2CD262772CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; + 2CD262782CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; + 2CD262792CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; + 2CD2627A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; + 2CD2627B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; + 2CD2627C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; + 2CD2627D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; + 2CD2627E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; + 2CD2627F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; + 2CD262802CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; + 2CD262812CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; + 2CD262822CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; + 2CD262832CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; + 2CD262862CFDC5E900A040A7 /* OnboardingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingTests.swift; sourceTree = ""; }; + 2CD262882CFDC5E900A040A7 /* DeviceType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceType.swift; sourceTree = ""; }; + 2CD262892CFDC5E900A040A7 /* EcosiaSnapshotTests.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = EcosiaSnapshotTests.xctestplan; sourceTree = ""; }; + 2CD2628A2CFDC5E900A040A7 /* environment.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = environment.json; sourceTree = ""; }; + 2CD2628B2CFDC5E900A040A7 /* LocaleRetriever.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocaleRetriever.swift; sourceTree = ""; }; + 2CD2628C2CFDC5E900A040A7 /* LocalizationOverrideTestingBundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizationOverrideTestingBundle.swift; sourceTree = ""; }; + 2CD2628D2CFDC5E900A040A7 /* snapshot_configuration.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = snapshot_configuration.json; sourceTree = ""; }; + 2CD2628E2CFDC5E900A040A7 /* SnapshotBaseTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotBaseTests.swift; sourceTree = ""; }; + 2CD2628F2CFDC5E900A040A7 /* SnapshotTestHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotTestHelper.swift; sourceTree = ""; }; + 2CD262902CFDC5E900A040A7 /* String+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = ""; }; + 2CD262922CFDC5E900A040A7 /* VersionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionTests.swift; sourceTree = ""; }; + 2CD262932CFDC5E900A040A7 /* NTPComponentTests_tests.xcresult */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = NTPComponentTests_tests.xcresult; sourceTree = ""; }; + 2CD262942CFDC5E900A040A7 /* OnboardingTests_tests.xcresult */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = OnboardingTests_tests.xcresult; sourceTree = ""; }; + 2CD262962CFDC5E900A040A7 /* WhatsNewLocalDataProviderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewLocalDataProviderTests.swift; sourceTree = ""; }; + 2CD262972CFDC5EA00A040A7 /* AppDelegateFeatureManagementIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegateFeatureManagementIntegrationTests.swift; sourceTree = ""; }; + 2CD262992CFDC5EA00A040A7 /* EcosiaInstallTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaInstallTypeTests.swift; sourceTree = ""; }; + 2CD2629A2CFDC5EA00A040A7 /* EcosiaPerformanceTestHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaPerformanceTestHistory.swift; sourceTree = ""; }; + 2CD2629B2CFDC5EA00A040A7 /* MockAppVersionInfoProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockAppVersionInfoProvider.swift; sourceTree = ""; }; + 2CD2629D2CFDC5EA00A040A7 /* PrivateModeButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateModeButtonTests.swift; sourceTree = ""; }; + 2CD2629E2CFDC5EA00A040A7 /* EcosiaNTPTooltipHighlightTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaNTPTooltipHighlightTests.swift; sourceTree = ""; }; + 2CD2629F2CFDC5EA00A040A7 /* EcosiaHomeViewModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaHomeViewModelTests.swift; sourceTree = ""; }; + 2CD262A02CFDC5EA00A040A7 /* UnleashUserDefaultsSeedProgressManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnleashUserDefaultsSeedProgressManagerTests.swift; sourceTree = ""; }; + 2CD262A12CFDC5EA00A040A7 /* UserDefaultsSeedProgressManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsSeedProgressManagerTests.swift; sourceTree = ""; }; + 2CD262A32CFDC5EB00A040A7 /* EcosiaTopSitesHelperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaTopSitesHelperTests.swift; sourceTree = ""; }; + 2CD262A42CFDC5EB00A040A7 /* EcosiaOverlayModeManagerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaOverlayModeManagerTests.swift; sourceTree = ""; }; + 2CD262A52CFDC5EB00A040A7 /* EcosiaPageActionMenuCellTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaPageActionMenuCellTests.swift; sourceTree = ""; }; + 2CD262A62CFDC5EB00A040A7 /* AnalyticsSpyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnalyticsSpyTests.swift; sourceTree = ""; }; + 2CD262A72CFDC5EB00A040A7 /* AnalyticsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnalyticsTests.swift; sourceTree = ""; }; + 2CD263C12CFDC76800A040A7 /* BrazeService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrazeService.swift; sourceTree = ""; }; + 2CD263C52CFDC76800A040A7 /* Clean.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Clean.swift; sourceTree = ""; }; + 2CD263C62CFDC76800A040A7 /* Validate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Validate.swift; sourceTree = ""; }; + 2CD263C82CFDC76800A040A7 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Ecosia.strings; sourceTree = ""; }; + 2CD263CA2CFDC76800A040A7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Ecosia.strings; sourceTree = ""; }; + 2CD263CC2CFDC76800A040A7 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Ecosia.strings; sourceTree = ""; }; + 2CD263CE2CFDC76800A040A7 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Ecosia.strings; sourceTree = ""; }; + 2CD263D02CFDC76800A040A7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Ecosia.strings; sourceTree = ""; }; + 2CD263D22CFDC76800A040A7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Ecosia.strings; sourceTree = ""; }; + 2CD263D42CFDC76800A040A7 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = de; path = de.lproj/Plurals.stringsdict; sourceTree = ""; }; + 2CD263D62CFDC76800A040A7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Plurals.stringsdict; sourceTree = ""; }; + 2CD263D82CFDC76800A040A7 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = es; path = es.lproj/Plurals.stringsdict; sourceTree = ""; }; + 2CD263DA2CFDC76800A040A7 /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = it; path = it.lproj/Plurals.stringsdict; sourceTree = ""; }; + 2CD263DC2CFDC76800A040A7 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = fr; path = fr.lproj/Plurals.stringsdict; sourceTree = ""; }; + 2CD263DE2CFDC76800A040A7 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = nl; path = nl.lproj/Plurals.stringsdict; sourceTree = ""; }; + 2CD263E02CFDC76800A040A7 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; + 2CD263E22CFDC76800A040A7 /* AppVersionInfoProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppVersionInfoProvider.swift; sourceTree = ""; }; + 2CD263E32CFDC76800A040A7 /* DefaultAppVersionInfoProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultAppVersionInfoProvider.swift; sourceTree = ""; }; + 2CD263E52CFDC76800A040A7 /* EcosiaInstallType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaInstallType.swift; sourceTree = ""; }; + 2CD263E62CFDC76800A040A7 /* EcosiaInstallType+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "EcosiaInstallType+Extensions.swift"; sourceTree = ""; }; + 2CD263E82CFDC76800A040A7 /* Version.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Version.swift; sourceTree = ""; }; + 2CD263E92CFDC76800A040A7 /* Version+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Version+Extensions.swift"; sourceTree = ""; }; + 2CD263EC2CFDC76800A040A7 /* Analytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Analytics.swift; sourceTree = ""; }; + 2CD263ED2CFDC76800A040A7 /* Analytics.Values.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Analytics.Values.swift; sourceTree = ""; }; + 2CD263EE2CFDC76800A040A7 /* Analytics+Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Analytics+Configuration.swift"; sourceTree = ""; }; + 2CD263F02CFDC76800A040A7 /* EcosiaLaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EcosiaLaunchScreen.xib; sourceTree = ""; }; + 2CD263F12CFDC76800A040A7 /* EcosiaLaunchScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaLaunchScreenView.swift; sourceTree = ""; }; + 2CD263F72CFDC76900A040A7 /* markets.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = markets.json; sourceTree = ""; }; + 2CD263FE2CFDC76900A040A7 /* FeatureManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureManagement.swift; sourceTree = ""; }; + 2CD264002CFDC76900A040A7 /* MMP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MMP.swift; sourceTree = ""; }; + 2CD264022CFDC76900A040A7 /* Ecosia.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Ecosia.entitlements; sourceTree = ""; }; + 2CD264032CFDC76900A040A7 /* EcosiaBeta.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = EcosiaBeta.entitlements; sourceTree = ""; }; + 2CD264052CFDC76900A040A7 /* Ecosia.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Ecosia.entitlements; sourceTree = ""; }; + 2CD264062CFDC76900A040A7 /* EcosiaBeta.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = EcosiaBeta.entitlements; sourceTree = ""; }; + 2CD264722CFDC76A00A040A7 /* FakeNimbus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FakeNimbus.swift; sourceTree = ""; }; + 2CD264732CFDC76A00A040A7 /* FakeSentry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FakeSentry.swift; sourceTree = ""; }; + 2CD264742CFDC76A00A040A7 /* FakeTelemetry.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FakeTelemetry.swift; sourceTree = ""; }; + 2CD265402CFDCF0900A040A7 /* AppSettingsTableViewController+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AppSettingsTableViewController+Ecosia.swift"; sourceTree = ""; }; + 2CD265412CFDCF0900A040A7 /* BrowserCoordinator+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BrowserCoordinator+Ecosia.swift"; sourceTree = ""; }; + 2CD265422CFDCF0900A040A7 /* BrowserViewController+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+Ecosia.swift"; sourceTree = ""; }; + 2CD265442CFDCF0900A040A7 /* DispatchQueueHelper+BuildChannel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DispatchQueueHelper+BuildChannel.swift"; sourceTree = ""; }; + 2CD265452CFDCF0900A040A7 /* ErrorPageHandler+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ErrorPageHandler+Ecosia.swift"; sourceTree = ""; }; + 2CD265462CFDCF0900A040A7 /* HomepageViewController+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HomepageViewController+Ecosia.swift"; sourceTree = ""; }; + 2CD265472CFDCF0900A040A7 /* LegacyThemeManager+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "LegacyThemeManager+Ecosia.swift"; sourceTree = ""; }; + 2CD265482CFDCF0900A040A7 /* NumberFormatter+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NumberFormatter+Ecosia.swift"; sourceTree = ""; }; + 2CD265492CFDCF0900A040A7 /* SimpleToast+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SimpleToast+Ecosia.swift"; sourceTree = ""; }; + 2CD2654A2CFDCF0900A040A7 /* SnapKit+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SnapKit+Ecosia.swift"; sourceTree = ""; }; + 2CD2654B2CFDCF0900A040A7 /* UIButton+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIButton+Ecosia.swift"; sourceTree = ""; }; + 2CD2654C2CFDCF0900A040A7 /* UIFont+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIFont+Ecosia.swift"; sourceTree = ""; }; + 2CD2654D2CFDCF0900A040A7 /* UIView+maskedCorners.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+maskedCorners.swift"; sourceTree = ""; }; + 2CD2654E2CFDCF0900A040A7 /* URL+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URL+Ecosia.swift"; sourceTree = ""; }; + 2CD265612CFDCF6D00A040A7 /* UIImage+Ecosia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Ecosia.swift"; sourceTree = ""; }; + 2CD265652CFE382C00A040A7 /* MultiplyImpact.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiplyImpact.swift; sourceTree = ""; }; + 2CD265662CFE382C00A040A7 /* MultiplyImpactStep.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiplyImpactStep.swift; sourceTree = ""; }; + 2CD265682CFE382C00A040A7 /* AboutEcosiaSection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AboutEcosiaSection.swift; sourceTree = ""; }; + 2CD265692CFE382C00A040A7 /* NTPAboutEcosiaCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPAboutEcosiaCell.swift; sourceTree = ""; }; + 2CD2656A2CFE382C00A040A7 /* NTPAboutEcosiaCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPAboutEcosiaCellViewModel.swift; sourceTree = ""; }; + 2CD2656F2CFE382C00A040A7 /* SeedProgressManagerProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeedProgressManagerProtocol.swift; sourceTree = ""; }; + 2CD265702CFE382C00A040A7 /* UserDefaultsSeedProgressManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaultsSeedProgressManager.swift; sourceTree = ""; }; + 2CD265722CFE382C00A040A7 /* ArcProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArcProgressView.swift; sourceTree = ""; }; + 2CD265732CFE382C00A040A7 /* NTPSeedCounterCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPSeedCounterCell.swift; sourceTree = ""; }; + 2CD265742CFE382C00A040A7 /* NTPSeedCounterViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPSeedCounterViewModel.swift; sourceTree = ""; }; + 2CD265752CFE382C00A040A7 /* SeedCounterConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeedCounterConfig.swift; sourceTree = ""; }; + 2CD265762CFE382C00A040A7 /* SeedCounterHiddenSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeedCounterHiddenSettings.swift; sourceTree = ""; }; + 2CD265772CFE382C00A040A7 /* SeedCounterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeedCounterView.swift; sourceTree = ""; }; + 2CD265782CFE382C00A040A7 /* SeedProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeedProgressView.swift; sourceTree = ""; }; + 2CD265792CFE382C00A040A7 /* Sparkle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sparkle.swift; sourceTree = ""; }; + 2CD2657B2CFE382C00A040A7 /* CustomizableNTPSettingConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomizableNTPSettingConfig.swift; sourceTree = ""; }; + 2CD2657C2CFE382C00A040A7 /* NTPCustomizationCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPCustomizationCell.swift; sourceTree = ""; }; + 2CD2657D2CFE382C00A040A7 /* NTPCustomizationCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPCustomizationCellViewModel.swift; sourceTree = ""; }; + 2CD2657F2CFE382C00A040A7 /* ClimateImpactInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClimateImpactInfo.swift; sourceTree = ""; }; + 2CD265802CFE382C00A040A7 /* NTPImpactCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPImpactCell.swift; sourceTree = ""; }; + 2CD265812CFE382C00A040A7 /* NTPImpactCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPImpactCellViewModel.swift; sourceTree = ""; }; + 2CD265822CFE382C00A040A7 /* NTPImpactDividerFooter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPImpactDividerFooter.swift; sourceTree = ""; }; + 2CD265832CFE382C00A040A7 /* NTPImpactRowView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPImpactRowView.swift; sourceTree = ""; }; + 2CD265842CFE382C00A040A7 /* ProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressView.swift; sourceTree = ""; }; + 2CD265862CFE382C00A040A7 /* NTPLibaryCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPLibaryCellViewModel.swift; sourceTree = ""; }; + 2CD265872CFE382C00A040A7 /* NTPLibraryCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPLibraryCell.swift; sourceTree = ""; }; + 2CD265882CFE382C00A040A7 /* NTPLibraryShortcutView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPLibraryShortcutView.swift; sourceTree = ""; }; + 2CD2658A2CFE382C00A040A7 /* NTPLogoCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPLogoCell.swift; sourceTree = ""; }; + 2CD2658C2CFE382C00A040A7 /* NewsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsController.swift; sourceTree = ""; }; + 2CD2658D2CFE382C00A040A7 /* NTPNewsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPNewsCell.swift; sourceTree = ""; }; + 2CD2658E2CFE382C00A040A7 /* NTPNewsCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPNewsCellViewModel.swift; sourceTree = ""; }; + 2CD265902CFE382C00A040A7 /* NTPNewsletterCardCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPNewsletterCardCell.swift; sourceTree = ""; }; + 2CD265912CFE382C00A040A7 /* NTPNewsletterCardViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPNewsletterCardViewModel.swift; sourceTree = ""; }; + 2CD265932CFE382C00A040A7 /* NTPConfigurableNudgeCardCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPConfigurableNudgeCardCell.swift; sourceTree = ""; }; + 2CD265942CFE382C00A040A7 /* NTPConfigurableNudgeCardCellViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPConfigurableNudgeCardCellViewModel.swift; sourceTree = ""; }; + 2CD265962CFE382C00A040A7 /* CircleButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircleButton.swift; sourceTree = ""; }; + 2CD265972CFE382C00A040A7 /* DefaultBrowser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultBrowser.swift; sourceTree = ""; }; + 2CD265982CFE382C00A040A7 /* NTPLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPLayout.swift; sourceTree = ""; }; + 2CD265992CFE382C00A040A7 /* NTPTooltip.Highlight.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPTooltip.Highlight.swift; sourceTree = ""; }; + 2CD2659A2CFE382C00A040A7 /* NTPTooltip.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPTooltip.swift; sourceTree = ""; }; + 2CD2659B2CFE382C00A040A7 /* NTPTooltipDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPTooltipDelegate.swift; sourceTree = ""; }; + 2CD2659D2CFE382C00A040A7 /* Welcome.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Welcome.swift; sourceTree = ""; }; + 2CD2659E2CFE382C00A040A7 /* WelcomeNavigation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeNavigation.swift; sourceTree = ""; }; + 2CD2659F2CFE382C00A040A7 /* WelcomeTour.Step.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTour.Step.swift; sourceTree = ""; }; + 2CD265A02CFE382C00A040A7 /* WelcomeTour.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTour.swift; sourceTree = ""; }; + 2CD265A12CFE382C00A040A7 /* WelcomeTourAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTourAction.swift; sourceTree = ""; }; + 2CD265A22CFE382C00A040A7 /* WelcomeTourGreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTourGreen.swift; sourceTree = ""; }; + 2CD265A32CFE382C00A040A7 /* WelcomeTourProfit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTourProfit.swift; sourceTree = ""; }; + 2CD265A42CFE382C00A040A7 /* WelcomeTourRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTourRow.swift; sourceTree = ""; }; + 2CD265A52CFE382C00A040A7 /* WelcomeTourTransparent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeTourTransparent.swift; sourceTree = ""; }; + 2CD265A72CFE382C00A040A7 /* PageActionMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageActionMenu.swift; sourceTree = ""; }; + 2CD265A82CFE382C00A040A7 /* PageActionMenuCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageActionMenuCell.swift; sourceTree = ""; }; + 2CD265A92CFE382C00A040A7 /* PageActionsShortcutsHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageActionsShortcutsHeader.swift; sourceTree = ""; }; + 2CD265AB2CFE382C00A040A7 /* EcosiaTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaTheme.swift; sourceTree = ""; }; + 2CD265AC2CFE382C00A040A7 /* EcosiaThemeColourPalette.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaThemeColourPalette.swift; sourceTree = ""; }; + 2CD265AD2CFE382C00A040A7 /* EcosiaThemeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaThemeManager.swift; sourceTree = ""; }; + 2CD265AF2CFE382C00A040A7 /* WhatsNewDataProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewDataProvider.swift; sourceTree = ""; }; + 2CD265B02CFE382C00A040A7 /* WhatsNewLocalDataProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewLocalDataProvider.swift; sourceTree = ""; }; + 2CD265B22CFE382C00A040A7 /* WhatsNewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewCell.swift; sourceTree = ""; }; + 2CD265B32CFE382C00A040A7 /* WhatsNewItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewItem.swift; sourceTree = ""; }; + 2CD265B42CFE382C00A040A7 /* WhatsNewViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewViewController.swift; sourceTree = ""; }; + 2CD265B52CFE382C00A040A7 /* WhatsNewViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewViewModel.swift; sourceTree = ""; }; + 2CD265B72CFE382C00A040A7 /* Colours.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colours.xcassets; sourceTree = ""; }; + 2CD265B82CFE382C00A040A7 /* Ecosia.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Ecosia.xcassets; sourceTree = ""; }; + 2CD265B92CFE382C00A040A7 /* EcosiaFindInPageBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaFindInPageBar.swift; sourceTree = ""; }; + 2CD265BA2CFE382C00A040A7 /* EcosiaNavigation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaNavigation.swift; sourceTree = ""; }; + 2CD265BB2CFE382C00A040A7 /* EmptyBookmarksView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyBookmarksView.swift; sourceTree = ""; }; + 2CD265BC2CFE382C00A040A7 /* EmptyBookmarksViewDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyBookmarksViewDelegate.swift; sourceTree = ""; }; + 2CD265BD2CFE382C00A040A7 /* EmptyHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyHeader.swift; sourceTree = ""; }; + 2CD265BE2CFE382C00A040A7 /* EmptyReadingListView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyReadingListView.swift; sourceTree = ""; }; + 2CD265BF2CFE382C00A040A7 /* FilterController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterController.swift; sourceTree = ""; }; + 2CD265C02CFE382C00A040A7 /* LoadingScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingScreen.swift; sourceTree = ""; }; + 2CD265C12CFE382C00A040A7 /* MarketsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketsController.swift; sourceTree = ""; }; + 2CD265C22CFE382C00A040A7 /* SemanticColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemanticColor.swift; sourceTree = ""; }; + 2CD265C42CFE382C00A040A7 /* SeedCounter.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SeedCounter.xcdatamodel; sourceTree = ""; }; + 2CD266102CFE38AD00A040A7 /* EcosiaTopSiteItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaTopSiteItemCell.swift; sourceTree = ""; }; + 2CD266132CFE38AD00A040A7 /* EcosiaHomepageSectionType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaHomepageSectionType.swift; sourceTree = ""; }; + 2CD266162CFE38AD00A040A7 /* EcosiaDebugSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaDebugSettings.swift; sourceTree = ""; }; + 2CD266172CFE38AD00A040A7 /* EcosiaSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaSettings.swift; sourceTree = ""; }; + 2CD266182CFE38AD00A040A7 /* NTPCustomizationSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPCustomizationSettingsViewController.swift; sourceTree = ""; }; + 2CD2661F2CFE39E300A040A7 /* EcosiaPrimaryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EcosiaPrimaryButton.swift; sourceTree = ""; }; + 2CD266212CFE3AD900A040A7 /* BookmarksExchange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksExchange.swift; sourceTree = ""; }; + 2CD2662A2CFE402000A040A7 /* SeedCounterNTPExperiment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SeedCounterNTPExperiment.swift; sourceTree = ""; }; + 2CD2662C2CFE403800A040A7 /* APNConsentOnLaunchExperiment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APNConsentOnLaunchExperiment.swift; sourceTree = ""; }; + 2CD2662D2CFE403800A040A7 /* BrazeIntegrationExperiment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrazeIntegrationExperiment.swift; sourceTree = ""; }; + 2CD2662E2CFE403800A040A7 /* NewsletterCardExperiment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsletterCardExperiment.swift; sourceTree = ""; }; + 2CD2662F2CFE403800A040A7 /* OnboardingRemoveExperiment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingRemoveExperiment.swift; sourceTree = ""; }; + 2CD2663B2CFE423D00A040A7 /* AppInfo+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AppInfo+Ecosia.swift"; sourceTree = ""; }; + 2CD2663D2CFF4ED000A040A7 /* DeviceInfo+Ecosia.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DeviceInfo+Ecosia.swift"; sourceTree = ""; }; + 2CD2664E2CFF56CB00A040A7 /* ConnectionStatusImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionStatusImage.swift; sourceTree = ""; }; + 2CD2664F2CFF56CB00A040A7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConnectionStatusImage+WebsiteConnectionTypeStatus.swift"; sourceTree = ""; }; + 2CD266532CFF56EA00A040A7 /* WebsiteConnectionStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebsiteConnectionStatus.swift; sourceTree = ""; }; 2CE294442B7CDD05006C22B2 /* CoreAudioTypes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudioTypes.framework; path = System/Library/Frameworks/CoreAudioTypes.framework; sourceTree = SDKROOT; }; - 2CE294672B7FC5A4006C22B2 /* EcosiaInstallTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaInstallTypeTests.swift; sourceTree = ""; }; - 2CE294692B7FC5A5006C22B2 /* AnalyticsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnalyticsTests.swift; sourceTree = ""; }; - 2CE2946B2B7FC5A5006C22B2 /* WhatsNewLocalDataProviderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewLocalDataProviderTests.swift; sourceTree = ""; }; - 2CE2946C2B7FC5A5006C22B2 /* EcosiaNTPTooltipHighlightTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaNTPTooltipHighlightTests.swift; sourceTree = ""; }; - 2CE2946D2B7FC5A5006C22B2 /* EcosiaPageActionMenuCellTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaPageActionMenuCellTests.swift; sourceTree = ""; }; - 2CE294702B7FC5A6006C22B2 /* VersionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionTests.swift; sourceTree = ""; }; 2CEA6F781E93E3A600D4100E /* SearchSettingsUITest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchSettingsUITest.swift; sourceTree = ""; }; 2CEB48402BE0EE2600498471 /* Production.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Production.xcconfig; sourceTree = ""; }; 2CEDADA120207EC400223A89 /* SyncFAUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncFAUITests.swift; sourceTree = ""; }; @@ -8021,23 +8534,22 @@ path = SearchQuickLinksMedium; sourceTree = ""; }; - 12147F2D2CDA3CB40009D300 /* Newsletter */ = { - isa = PBXGroup; - children = ( - 12147F2E2CDA3CD00009D300 /* NTPNewsletterCardCell.swift */, - 12147F302CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift */, - ); - path = Newsletter; - sourceTree = ""; - }; 1229356B2CE78D0A00EC1297 /* Ecosia */ = { isa = PBXGroup; children = ( - 2C61892D2B7A8A22006B70D7 /* Analytics */, - 122935962CE7913100EC1297 /* Braze */, - 2C6188F52B7A8A22006B70D7 /* Experiments */, - 122935AA2CE79D4E00EC1297 /* Extensions */, - 122935A12CE79A8600EC1297 /* Helpers */, + 2CD2663A2CFE421C00A040A7 /* Extensions */, + 2CD266312CFE403800A040A7 /* Experiments */, + 2CD263EF2CFDC76800A040A7 /* Analytics */, + 2CD264082CFDC76900A040A7 /* Auth */, + 2CD263C22CFDC76800A040A7 /* Braze */, + 2CD264072CFDC76900A040A7 /* Entitlements */, + 2CD264752CFDC76A00A040A7 /* Fake */, + 2CD263FF2CFDC76900A040A7 /* FeatureManagement */, + 2CD263EB2CFDC76800A040A7 /* Helpers */, + 2CD263E12CFDC76800A040A7 /* L10N */, + 2CD263F22CFDC76800A040A7 /* LaunchScreen */, + 2CD263F72CFDC76900A040A7 /* markets.json */, + 2CD264012CFDC76900A040A7 /* MMP */, 1229356C2CE78D0A00EC1297 /* Ecosia.h */, 1229359D2CE792B700EC1297 /* README.md */, 12E604442CECADDA009A7BEC /* Info.plist */, @@ -8048,62 +8560,27 @@ 122935792CE78D0A00EC1297 /* EcosiaTests */ = { isa = PBXGroup; children = ( + 2CD262A82CFDC5EB00A040A7 /* Analytics */, + 2CD262A22CFDC5EA00A040A7 /* ClimateImpactCounter */, + 2CD262982CFDC5EA00A040A7 /* IntegrationTests */, + 2CD2629C2CFDC5EA00A040A7 /* Mocks */, + 2CD262952CFDC5E900A040A7 /* Results */, + 2CD262912CFDC5E900A040A7 /* SnapshotTests */, + 2CD2629F2CFDC5EA00A040A7 /* EcosiaHomeViewModelTests.swift */, + 2CD262992CFDC5EA00A040A7 /* EcosiaInstallTypeTests.swift */, + 2CD2629E2CFDC5EA00A040A7 /* EcosiaNTPTooltipHighlightTests.swift */, + 2CD262A42CFDC5EB00A040A7 /* EcosiaOverlayModeManagerTests.swift */, + 2CD262A52CFDC5EB00A040A7 /* EcosiaPageActionMenuCellTests.swift */, + 2CD2629A2CFDC5EA00A040A7 /* EcosiaPerformanceTestHistory.swift */, + 2CD262A32CFDC5EB00A040A7 /* EcosiaTopSitesHelperTests.swift */, + 2CD2629D2CFDC5EA00A040A7 /* PrivateModeButtonTests.swift */, + 2CD262922CFDC5E900A040A7 /* VersionTests.swift */, + 2CD262962CFDC5E900A040A7 /* WhatsNewLocalDataProviderTests.swift */, 126509882CDA31890011BA36 /* BrazeServiceTests.swift */, ); path = EcosiaTests; sourceTree = ""; }; - 122935962CE7913100EC1297 /* Braze */ = { - isa = PBXGroup; - children = ( - 1229359B2CE7927800EC1297 /* BrazeService.swift */, - ); - path = Braze; - sourceTree = ""; - }; - 122935A12CE79A8600EC1297 /* Helpers */ = { - isa = PBXGroup; - children = ( - 2C6189242B7A8A22006B70D7 /* AppInfoProvider */, - 2C6189272B7A8A22006B70D7 /* EcosiaInstallType */, - 2C61892A2B7A8A22006B70D7 /* Version */, - ); - path = Helpers; - sourceTree = ""; - }; - 122935AA2CE79D4E00EC1297 /* Extensions */ = { - isa = PBXGroup; - children = ( - 2C6189092B7A8A22006B70D7 /* AppInfo+Ecosia.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 122935B12CE79DFB00EC1297 /* Experiments */ = { - isa = PBXGroup; - children = ( - 122935B22CE79E0D00EC1297 /* Unleash */, - ); - path = Experiments; - sourceTree = ""; - }; - 122935B22CE79E0D00EC1297 /* Unleash */ = { - isa = PBXGroup; - children = ( - 2C6B5B402CAAF3AA00F15323 /* SeedCounterNTPExperiment.swift */, - ); - path = Unleash; - sourceTree = ""; - }; - 1285E2B32CC293A20053506B /* Analytics */ = { - isa = PBXGroup; - children = ( - 2CE294692B7FC5A5006C22B2 /* AnalyticsTests.swift */, - 1285E2B42CC293CA0053506B /* AnalyticsSpyTests.swift */, - ); - path = Analytics; - sourceTree = ""; - }; 1D7B78952ADF324E0011E9F2 /* Event Queue */ = { isa = PBXGroup; children = ( @@ -8510,593 +8987,938 @@ path = Extensions; sourceTree = ""; }; - 2C08319A2B89124000BD7134 /* AppExtensions */ = { + 2CABD71A2C11E07300A0750F /* PersistedGenerated */ = { isa = PBXGroup; children = ( - 2C08319B2B89127200BD7134 /* Ecosia.entitlements */, - 2C08319C2B89127200BD7134 /* EcosiaBeta.entitlements */, + 2C0360D92C1747E6006706F2 /* FxNimbus.swift */, ); - path = AppExtensions; + path = PersistedGenerated; + sourceTree = ""; + }; + 2CBCAAFA2B88EEE40080AD68 /* Configuration */ = { + isa = PBXGroup; + children = ( + 2CBCAB0C2B88EEE40080AD68 /* Ecosia.xcconfig */, + 2CBCAAFB2B88EEE40080AD68 /* Ecosia.WidgetKit.xcconfig */, + 2CBCAAFD2B88EEE40080AD68 /* Ecosia.ShareTo.xcconfig */, + 2CBCAB0E2B88EEE40080AD68 /* EcosiaDebug.xcconfig */, + 2CBCAB0D2B88EEE40080AD68 /* EcosiaDebug.WidgetKit.xcconfig */, + 2CBCAB072B88EEE40080AD68 /* EcosiaDebug.ShareTo.xcconfig */, + 2CBCAB0B2B88EEE40080AD68 /* EcosiaBeta.xcconfig */, + 2CBCAB042B88EEE40080AD68 /* EcosiaBeta.WidgetKit.xcconfig */, + 2CBCAAFC2B88EEE40080AD68 /* EcosiaBeta.ShareTo.xcconfig */, + 2CBCAAFE2B88EEE40080AD68 /* EcosiaBetaDebug.xcconfig */, + 2CBCAB092B88EEE40080AD68 /* EcosiaBetaDebug.ShareTo.xcconfig */, + 2CBCAB022B88EEE40080AD68 /* EcosiaBetaDebug.WidgetKit.xcconfig */, + 2CBCAB002B88EEE40080AD68 /* Common.xcconfig */, + 2CBCAB032B88EEE40080AD68 /* Debug.xcconfig */, + 2CBCAB082B88EEE40080AD68 /* Staging.xcconfig */, + 2CBCAB062B88EEE40080AD68 /* Release.xcconfig */, + 2CEB48402BE0EE2600498471 /* Production.xcconfig */, + 2CBCAB0A2B88EEE40080AD68 /* Fennec.enterprise.xcconfig */, + 2CBCAAFF2B88EEE40080AD68 /* Firefox.xcconfig */, + 2CBCAB052B88EEE40080AD68 /* FirefoxBeta.xcconfig */, + 2CBCAB012B88EEE40080AD68 /* Fennec.xcconfig */, + ); + path = Configuration; + sourceTree = ""; + }; + 2CD261862CFDC5E900A040A7 /* Mocks */ = { + isa = PBXGroup; + children = ( + 2CD261842CFDC5E900A040A7 /* EcosiaMockThemeManager.swift */, + 2CD261852CFDC5E900A040A7 /* Welcome.swift */, + ); + path = Mocks; sourceTree = ""; }; - 2C16B7642CAF2417006118F8 /* ClimateImpactCounter */ = { + 2CD261B72CFDC5E900A040A7 /* NTPComponentTests */ = { + isa = PBXGroup; + children = ( + 2CD261872CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png */, + 2CD261882CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png */, + 2CD261892CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png */, + 2CD2618A2CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png */, + 2CD2618B2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png */, + 2CD2618C2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png */, + 2CD2618D2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png */, + 2CD2618E2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png */, + 2CD2618F2CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png */, + 2CD261902CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png */, + 2CD261912CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png */, + 2CD261922CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png */, + 2CD261932CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png */, + 2CD261942CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png */, + 2CD261952CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png */, + 2CD261962CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png */, + 2CD261972CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png */, + 2CD261982CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png */, + 2CD261992CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png */, + 2CD2619A2CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png */, + 2CD2619B2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png */, + 2CD2619C2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png */, + 2CD2619D2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_en.1.png */, + 2CD2619E2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_es.1.png */, + 2CD2619F2CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_en.1.png */, + 2CD261A02CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_es.1.png */, + 2CD261A12CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_en.1.png */, + 2CD261A22CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_es.1.png */, + 2CD261A32CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_en.1.png */, + 2CD261A42CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_es.1.png */, + 2CD261A52CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_en.1.png */, + 2CD261A62CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_es.1.png */, + 2CD261A72CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png */, + 2CD261A82CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png */, + 2CD261A92CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png */, + 2CD261AA2CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png */, + 2CD261AB2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png */, + 2CD261AC2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png */, + 2CD261AD2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png */, + 2CD261AE2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png */, + 2CD261AF2CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png */, + 2CD261B02CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png */, + 2CD261B12CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png */, + 2CD261B22CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png */, + 2CD261B32CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png */, + 2CD261B42CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png */, + 2CD261B52CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png */, + 2CD261B62CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png */, + ); + path = NTPComponentTests; + sourceTree = ""; + }; + 2CD261B82CFDC5E900A040A7 /* __Snapshots__ */ = { + isa = PBXGroup; + children = ( + 2CD261B72CFDC5E900A040A7 /* NTPComponentTests */, + ); + path = __Snapshots__; + sourceTree = ""; + }; + 2CD261BB2CFDC5E900A040A7 /* NTP */ = { + isa = PBXGroup; + children = ( + 2CD261B82CFDC5E900A040A7 /* __Snapshots__ */, + 2CD261B92CFDC5E900A040A7 /* NTPComponentTests.swift */, + 2CD261BA2CFDC5E900A040A7 /* NTPTests.swift */, + ); + path = NTP; + sourceTree = ""; + }; + 2CD262842CFDC5E900A040A7 /* OnboardingTests */ = { + isa = PBXGroup; + children = ( + 2CD261BC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, + 2CD261BD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, + 2CD261BE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, + 2CD261BF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, + 2CD261C02CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, + 2CD261C12CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_de.1.png */, + 2CD261C22CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_en.1.png */, + 2CD261C32CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_es.1.png */, + 2CD261C42CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_it.1.png */, + 2CD261C52CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png */, + 2CD261C62CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png */, + 2CD261C72CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png */, + 2CD261C82CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png */, + 2CD261C92CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png */, + 2CD261CA2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png */, + 2CD261CB2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png */, + 2CD261CC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png */, + 2CD261CD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png */, + 2CD261CE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png */, + 2CD261CF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png */, + 2CD261D02CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, + 2CD261D12CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, + 2CD261D22CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, + 2CD261D32CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, + 2CD261D42CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, + 2CD261D52CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_de.1.png */, + 2CD261D62CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_en.1.png */, + 2CD261D72CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_es.1.png */, + 2CD261D82CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_it.1.png */, + 2CD261D92CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_nl.1.png */, + 2CD261DA2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png */, + 2CD261DB2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png */, + 2CD261DC2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png */, + 2CD261DD2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png */, + 2CD261DE2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png */, + 2CD261DF2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png */, + 2CD261E02CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png */, + 2CD261E12CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png */, + 2CD261E22CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png */, + 2CD261E32CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png */, + 2CD261E42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, + 2CD261E52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, + 2CD261E62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, + 2CD261E72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, + 2CD261E82CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, + 2CD261E92CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png */, + 2CD261EA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png */, + 2CD261EB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png */, + 2CD261EC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png */, + 2CD261ED2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png */, + 2CD261EE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png */, + 2CD261EF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png */, + 2CD261F02CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png */, + 2CD261F12CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png */, + 2CD261F22CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png */, + 2CD261F32CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png */, + 2CD261F42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png */, + 2CD261F52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png */, + 2CD261F62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png */, + 2CD261F72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png */, + 2CD261F82CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, + 2CD261F92CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, + 2CD261FA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, + 2CD261FB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, + 2CD261FC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, + 2CD261FD2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png */, + 2CD261FE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png */, + 2CD261FF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png */, + 2CD262002CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png */, + 2CD262012CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png */, + 2CD262022CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png */, + 2CD262032CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png */, + 2CD262042CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png */, + 2CD262052CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png */, + 2CD262062CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png */, + 2CD262072CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png */, + 2CD262082CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png */, + 2CD262092CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png */, + 2CD2620A2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png */, + 2CD2620B2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png */, + 2CD2620C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, + 2CD2620D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, + 2CD2620E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, + 2CD2620F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, + 2CD262102CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, + 2CD262112CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png */, + 2CD262122CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png */, + 2CD262132CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png */, + 2CD262142CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png */, + 2CD262152CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png */, + 2CD262162CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png */, + 2CD262172CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png */, + 2CD262182CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png */, + 2CD262192CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png */, + 2CD2621A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png */, + 2CD2621B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png */, + 2CD2621C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png */, + 2CD2621D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png */, + 2CD2621E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png */, + 2CD2621F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png */, + 2CD262202CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, + 2CD262212CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, + 2CD262222CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, + 2CD262232CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, + 2CD262242CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, + 2CD262252CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png */, + 2CD262262CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png */, + 2CD262272CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png */, + 2CD262282CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png */, + 2CD262292CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png */, + 2CD2622A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png */, + 2CD2622B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png */, + 2CD2622C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png */, + 2CD2622D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png */, + 2CD2622E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png */, + 2CD2622F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png */, + 2CD262302CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png */, + 2CD262312CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png */, + 2CD262322CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png */, + 2CD262332CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png */, + 2CD262342CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, + 2CD262352CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, + 2CD262362CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, + 2CD262372CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, + 2CD262382CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, + 2CD262392CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png */, + 2CD2623A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png */, + 2CD2623B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png */, + 2CD2623C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png */, + 2CD2623D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png */, + 2CD2623E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png */, + 2CD2623F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png */, + 2CD262402CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png */, + 2CD262412CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png */, + 2CD262422CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png */, + 2CD262432CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png */, + 2CD262442CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png */, + 2CD262452CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png */, + 2CD262462CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png */, + 2CD262472CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png */, + 2CD262482CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, + 2CD262492CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, + 2CD2624A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, + 2CD2624B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, + 2CD2624C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, + 2CD2624D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png */, + 2CD2624E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png */, + 2CD2624F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png */, + 2CD262502CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png */, + 2CD262512CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png */, + 2CD262522CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png */, + 2CD262532CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png */, + 2CD262542CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png */, + 2CD262552CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png */, + 2CD262562CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png */, + 2CD262572CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png */, + 2CD262582CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png */, + 2CD262592CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png */, + 2CD2625A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png */, + 2CD2625B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png */, + 2CD2625C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, + 2CD2625D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, + 2CD2625E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, + 2CD2625F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, + 2CD262602CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, + 2CD262612CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png */, + 2CD262622CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png */, + 2CD262632CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png */, + 2CD262642CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png */, + 2CD262652CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png */, + 2CD262662CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png */, + 2CD262672CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png */, + 2CD262682CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png */, + 2CD262692CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png */, + 2CD2626A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png */, + 2CD2626B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png */, + 2CD2626C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png */, + 2CD2626D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png */, + 2CD2626E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png */, + 2CD2626F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png */, + 2CD262702CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, + 2CD262712CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, + 2CD262722CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, + 2CD262732CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, + 2CD262742CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, + 2CD262752CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png */, + 2CD262762CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png */, + 2CD262772CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png */, + 2CD262782CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png */, + 2CD262792CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png */, + 2CD2627A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png */, + 2CD2627B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png */, + 2CD2627C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png */, + 2CD2627D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png */, + 2CD2627E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png */, + 2CD2627F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png */, + 2CD262802CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png */, + 2CD262812CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png */, + 2CD262822CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png */, + 2CD262832CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png */, + ); + path = OnboardingTests; + sourceTree = ""; + }; + 2CD262852CFDC5E900A040A7 /* __Snapshots__ */ = { + isa = PBXGroup; + children = ( + 2CD262842CFDC5E900A040A7 /* OnboardingTests */, + ); + path = __Snapshots__; + sourceTree = ""; + }; + 2CD262872CFDC5E900A040A7 /* Onboarding */ = { + isa = PBXGroup; + children = ( + 2CD262852CFDC5E900A040A7 /* __Snapshots__ */, + 2CD262862CFDC5E900A040A7 /* OnboardingTests.swift */, + ); + path = Onboarding; + sourceTree = ""; + }; + 2CD262912CFDC5E900A040A7 /* SnapshotTests */ = { + isa = PBXGroup; + children = ( + 2CD261862CFDC5E900A040A7 /* Mocks */, + 2CD261BB2CFDC5E900A040A7 /* NTP */, + 2CD262872CFDC5E900A040A7 /* Onboarding */, + 2CD262882CFDC5E900A040A7 /* DeviceType.swift */, + 2CD262892CFDC5E900A040A7 /* EcosiaSnapshotTests.xctestplan */, + 2CD2628A2CFDC5E900A040A7 /* environment.json */, + 2CD2628B2CFDC5E900A040A7 /* LocaleRetriever.swift */, + 2CD2628C2CFDC5E900A040A7 /* LocalizationOverrideTestingBundle.swift */, + 2CD2628D2CFDC5E900A040A7 /* snapshot_configuration.json */, + 2CD2628E2CFDC5E900A040A7 /* SnapshotBaseTests.swift */, + 2CD2628F2CFDC5E900A040A7 /* SnapshotTestHelper.swift */, + 2CD262902CFDC5E900A040A7 /* String+Extension.swift */, + ); + path = SnapshotTests; + sourceTree = ""; + }; + 2CD262952CFDC5E900A040A7 /* Results */ = { + isa = PBXGroup; + children = ( + 2CD262932CFDC5E900A040A7 /* NTPComponentTests_tests.xcresult */, + 2CD262942CFDC5E900A040A7 /* OnboardingTests_tests.xcresult */, + ); + path = Results; + sourceTree = ""; + }; + 2CD262982CFDC5EA00A040A7 /* IntegrationTests */ = { + isa = PBXGroup; + children = ( + 2CD262972CFDC5EA00A040A7 /* AppDelegateFeatureManagementIntegrationTests.swift */, + ); + path = IntegrationTests; + sourceTree = ""; + }; + 2CD2629C2CFDC5EA00A040A7 /* Mocks */ = { + isa = PBXGroup; + children = ( + 2CD2629B2CFDC5EA00A040A7 /* MockAppVersionInfoProvider.swift */, + ); + path = Mocks; + sourceTree = ""; + }; + 2CD262A22CFDC5EA00A040A7 /* ClimateImpactCounter */ = { isa = PBXGroup; children = ( - 2C16B7652CAF2425006118F8 /* UserDefaultsSeedProgressManagerTests.swift */, - 2C728D7D2CBBDCDC00C7684B /* UnleashUserDefaultsSeedProgressManagerTests.swift */, + 2CD262A02CFDC5EA00A040A7 /* UnleashUserDefaultsSeedProgressManagerTests.swift */, + 2CD262A12CFDC5EA00A040A7 /* UserDefaultsSeedProgressManagerTests.swift */, ); path = ClimateImpactCounter; sourceTree = ""; }; - 2C5A5E682CB53E05005BFE8B /* SeedProgressManager */ = { + 2CD262A82CFDC5EB00A040A7 /* Analytics */ = { isa = PBXGroup; children = ( - 2CCBB5342CAF06DE006E2E10 /* SeedProgressManagerProtocol.swift */, - 2C5A5E662CB53DF9005BFE8B /* UserDefaultsSeedProgressManager.swift */, + 2CD262A62CFDC5EB00A040A7 /* AnalyticsSpyTests.swift */, + 2CD262A72CFDC5EB00A040A7 /* AnalyticsTests.swift */, ); - path = SeedProgressManager; + path = Analytics; sourceTree = ""; }; - 2C61887E2B7A8A21006B70D7 /* Ecosia */ = { + 2CD263C22CFDC76800A040A7 /* Braze */ = { isa = PBXGroup; children = ( - 2C61887F2B7A8A21006B70D7 /* LaunchScreen */, - 2C6188822B7A8A21006B70D7 /* MMP */, - 2C6188842B7A8A21006B70D7 /* UI */, - 2C6188D62B7A8A22006B70D7 /* Settings */, - 2C6188DA2B7A8A22006B70D7 /* L10N */, - 2C6188ED2B7A8A22006B70D7 /* FeatureManagement */, - 2C6188EF2B7A8A22006B70D7 /* Frontend */, - 2C6188FA2B7A8A22006B70D7 /* Network */, - 2C6188FC2B7A8A22006B70D7 /* BrowserKitExtensions */, - 122935B12CE79DFB00EC1297 /* Experiments */, - 2C6188FF2B7A8A22006B70D7 /* Extensions */, - 2C6189132B7A8A22006B70D7 /* Entitlements */, - 2C6189162B7A8A22006B70D7 /* Bookmarks */, - 2C6189182B7A8A22006B70D7 /* markets.json */, - 2C6189192B7A8A22006B70D7 /* Fake */, + 2CD263C12CFDC76800A040A7 /* BrazeService.swift */, ); - path = Ecosia; + path = Braze; sourceTree = ""; }; - 2C61887F2B7A8A21006B70D7 /* LaunchScreen */ = { + 2CD263C72CFDC76800A040A7 /* Scripts */ = { isa = PBXGroup; children = ( - 2C6188802B7A8A21006B70D7 /* EcosiaLaunchScreenView.swift */, - 2C6188812B7A8A21006B70D7 /* EcosiaLaunchScreen.xib */, + 2CD263C52CFDC76800A040A7 /* Clean.swift */, + 2CD263C62CFDC76800A040A7 /* Validate.swift */, ); - path = LaunchScreen; + path = Scripts; sourceTree = ""; }; - 2C6188822B7A8A21006B70D7 /* MMP */ = { + 2CD263E12CFDC76800A040A7 /* L10N */ = { isa = PBXGroup; children = ( - 2C6188832B7A8A21006B70D7 /* MMP.swift */, + 2CD263C72CFDC76800A040A7 /* Scripts */, + 2CD263C92CFDC76800A040A7 /* Ecosia.strings */, + 2CD263CB2CFDC76800A040A7 /* Ecosia.strings */, + 2CD263CD2CFDC76800A040A7 /* Ecosia.strings */, + 2CD263CF2CFDC76800A040A7 /* Ecosia.strings */, + 2CD263D12CFDC76800A040A7 /* Ecosia.strings */, + 2CD263D32CFDC76800A040A7 /* Ecosia.strings */, + 2CD263D52CFDC76800A040A7 /* Plurals.stringsdict */, + 2CD263D72CFDC76800A040A7 /* Plurals.stringsdict */, + 2CD263D92CFDC76800A040A7 /* Plurals.stringsdict */, + 2CD263DB2CFDC76800A040A7 /* Plurals.stringsdict */, + 2CD263DD2CFDC76800A040A7 /* Plurals.stringsdict */, + 2CD263DF2CFDC76800A040A7 /* Plurals.stringsdict */, + 2CD263E02CFDC76800A040A7 /* String.swift */, ); - path = MMP; + path = L10N; sourceTree = ""; }; - 2C6188842B7A8A21006B70D7 /* UI */ = { - isa = PBXGroup; - children = ( - 2CCFB3D42C0F1EA500BEDCA0 /* LoadingScreen.swift */, - 2C6188852B7A8A21006B70D7 /* SemanticColor.swift */, - 2C6188862B7A8A21006B70D7 /* PageAction */, - 2C61888A2B7A8A21006B70D7 /* EmptyBookmarksViewDelegate.swift */, - 2C61888B2B7A8A21006B70D7 /* EcosiaFindInPageBar.swift */, - 2C61888C2B7A8A21006B70D7 /* Ecosia.xcassets */, - 2C61888D2B7A8A21006B70D7 /* EmptyReadingListView.swift */, - 2C6188942B7A8A21006B70D7 /* EmptyHeader.swift */, - 2C6188952B7A8A21006B70D7 /* WhatsNew */, - 2C61889D2B7A8A21006B70D7 /* NTP */, - 2C6188C02B7A8A22006B70D7 /* Colours.xcassets */, - 2C6188C12B7A8A22006B70D7 /* EcosiaNavigation.swift */, - 2C6188C22B7A8A22006B70D7 /* Theme */, - 2C6188C62B7A8A22006B70D7 /* FilterController.swift */, - 2C6188C72B7A8A22006B70D7 /* MarketsController.swift */, - 2C6188C82B7A8A22006B70D7 /* EmptyBookmarksView.swift */, - 2C6188C92B7A8A22006B70D7 /* Onboarding */, - 2C6188D32B7A8A22006B70D7 /* MultiplyImpact */, + 2CD263E42CFDC76800A040A7 /* AppInfoProvider */ = { + isa = PBXGroup; + children = ( + 2CD263E22CFDC76800A040A7 /* AppVersionInfoProvider.swift */, + 2CD263E32CFDC76800A040A7 /* DefaultAppVersionInfoProvider.swift */, ); - path = UI; + path = AppInfoProvider; sourceTree = ""; }; - 2C6188862B7A8A21006B70D7 /* PageAction */ = { + 2CD263E72CFDC76800A040A7 /* EcosiaInstallType */ = { isa = PBXGroup; children = ( - 2C6188872B7A8A21006B70D7 /* PageActionMenuCell.swift */, - 2C6188882B7A8A21006B70D7 /* PageActionsShortcutsHeader.swift */, - 2C6188892B7A8A21006B70D7 /* PageActionMenu.swift */, + 2CD263E52CFDC76800A040A7 /* EcosiaInstallType.swift */, + 2CD263E62CFDC76800A040A7 /* EcosiaInstallType+Extensions.swift */, ); - path = PageAction; + path = EcosiaInstallType; sourceTree = ""; }; - 2C6188952B7A8A21006B70D7 /* WhatsNew */ = { + 2CD263EA2CFDC76800A040A7 /* Version */ = { isa = PBXGroup; children = ( - 2C6188962B7A8A21006B70D7 /* WhatsNewCell.swift */, - 2C6188972B7A8A21006B70D7 /* WhatsNewViewModel.swift */, - 2C6188982B7A8A21006B70D7 /* WhatsNewViewController.swift */, - 2C6188992B7A8A21006B70D7 /* WhatsNewItem.swift */, - 2C61889A2B7A8A21006B70D7 /* DataProvider */, + 2CD263E82CFDC76800A040A7 /* Version.swift */, + 2CD263E92CFDC76800A040A7 /* Version+Extensions.swift */, ); - path = WhatsNew; + path = Version; sourceTree = ""; }; - 2C61889A2B7A8A21006B70D7 /* DataProvider */ = { + 2CD263EB2CFDC76800A040A7 /* Helpers */ = { isa = PBXGroup; children = ( - 2C61889B2B7A8A21006B70D7 /* WhatsNewDataProvider.swift */, - 2C61889C2B7A8A21006B70D7 /* WhatsNewLocalDataProvider.swift */, + 2CD263E42CFDC76800A040A7 /* AppInfoProvider */, + 2CD263E72CFDC76800A040A7 /* EcosiaInstallType */, + 2CD263EA2CFDC76800A040A7 /* Version */, ); - path = DataProvider; + path = Helpers; sourceTree = ""; }; - 2C61889D2B7A8A21006B70D7 /* NTP */ = { + 2CD263EF2CFDC76800A040A7 /* Analytics */ = { isa = PBXGroup; children = ( - 2C6B5B3C2CAAF27F00F15323 /* ClimateImpactCounter */, - 2CA995262CA2C053001064CC /* NudgeCards */, - 2C61889E2B7A8A21006B70D7 /* NTPLayout.swift */, - 2C61889F2B7A8A21006B70D7 /* DefaultBrowser.swift */, - 2C6188A02B7A8A21006B70D7 /* Customization */, - 2C6188A42B7A8A21006B70D7 /* Library */, - 2C6188A82B7A8A21006B70D7 /* NTPTooltip.swift */, - 2C6188A92B7A8A21006B70D7 /* CircleButton.swift */, - 2C6188AA2B7A8A21006B70D7 /* NTPTooltip.Highlight.swift */, - 2C6188AE2B7A8A22006B70D7 /* News */, - 2C6188B22B7A8A22006B70D7 /* Logo */, - 2C6188B42B7A8A22006B70D7 /* NTPTooltipDelegate.swift */, - 2C6188B52B7A8A22006B70D7 /* Impact */, - 2C6188BC2B7A8A22006B70D7 /* AboutEcosia */, + 2CD263EC2CFDC76800A040A7 /* Analytics.swift */, + 2CD263ED2CFDC76800A040A7 /* Analytics.Values.swift */, + 2CD263EE2CFDC76800A040A7 /* Analytics+Configuration.swift */, ); - path = NTP; + path = Analytics; sourceTree = ""; }; - 2C6188A02B7A8A21006B70D7 /* Customization */ = { + 2CD263F22CFDC76800A040A7 /* LaunchScreen */ = { isa = PBXGroup; children = ( - 2C6188A12B7A8A21006B70D7 /* CustomizableNTPSettingConfig.swift */, - 2C6188A22B7A8A21006B70D7 /* NTPCustomizationCell.swift */, - 2C6188A32B7A8A21006B70D7 /* NTPCustomizationCellViewModel.swift */, + 2CD263F02CFDC76800A040A7 /* EcosiaLaunchScreen.xib */, + 2CD263F12CFDC76800A040A7 /* EcosiaLaunchScreenView.swift */, ); - path = Customization; + path = LaunchScreen; sourceTree = ""; }; - 2C6188A42B7A8A21006B70D7 /* Library */ = { + 2CD263FF2CFDC76900A040A7 /* FeatureManagement */ = { isa = PBXGroup; children = ( - 2C6188A52B7A8A21006B70D7 /* NTPLibraryShortcutView.swift */, - 2C6188A62B7A8A21006B70D7 /* NTPLibraryCell.swift */, - 2C6188A72B7A8A21006B70D7 /* NTPLibaryCellViewModel.swift */, + 2CD263FE2CFDC76900A040A7 /* FeatureManagement.swift */, ); - path = Library; + path = FeatureManagement; sourceTree = ""; }; - 2C6188AE2B7A8A22006B70D7 /* News */ = { + 2CD264012CFDC76900A040A7 /* MMP */ = { isa = PBXGroup; children = ( - 2C6188AF2B7A8A22006B70D7 /* NewsController.swift */, - 2C6188B02B7A8A22006B70D7 /* NTPNewsCellViewModel.swift */, - 2C6188B12B7A8A22006B70D7 /* NTPNewsCell.swift */, + 2CD264002CFDC76900A040A7 /* MMP.swift */, ); - path = News; + path = MMP; sourceTree = ""; }; - 2C6188B22B7A8A22006B70D7 /* Logo */ = { + 2CD264042CFDC76900A040A7 /* AppExtensions */ = { isa = PBXGroup; children = ( - 2C6188B32B7A8A22006B70D7 /* NTPLogoCell.swift */, + 2CD264022CFDC76900A040A7 /* Ecosia.entitlements */, + 2CD264032CFDC76900A040A7 /* EcosiaBeta.entitlements */, ); - path = Logo; + path = AppExtensions; sourceTree = ""; }; - 2C6188B52B7A8A22006B70D7 /* Impact */ = { + 2CD264072CFDC76900A040A7 /* Entitlements */ = { isa = PBXGroup; children = ( - 2C6188B62B7A8A22006B70D7 /* ProgressView.swift */, - 2C6188B72B7A8A22006B70D7 /* NTPImpactCell.swift */, - 2C6188B82B7A8A22006B70D7 /* NTPImpactCellViewModel.swift */, - 2C6188B92B7A8A22006B70D7 /* NTPImpactRowView.swift */, - 2C6188BA2B7A8A22006B70D7 /* NTPImpactDividerFooter.swift */, - 2C6188BB2B7A8A22006B70D7 /* ClimateImpactInfo.swift */, + 2CD264042CFDC76900A040A7 /* AppExtensions */, + 2CD264052CFDC76900A040A7 /* Ecosia.entitlements */, + 2CD264062CFDC76900A040A7 /* EcosiaBeta.entitlements */, ); - path = Impact; + path = Entitlements; sourceTree = ""; }; - 2C6188BC2B7A8A22006B70D7 /* AboutEcosia */ = { + 2CD264082CFDC76900A040A7 /* Auth */ = { isa = PBXGroup; children = ( - 2C6188BD2B7A8A22006B70D7 /* AboutEcosiaSection.swift */, - 2C6188BE2B7A8A22006B70D7 /* NTPAboutEcosiaCellViewModel.swift */, - 2C6188BF2B7A8A22006B70D7 /* NTPAboutEcosiaCell.swift */, ); - path = AboutEcosia; + path = Auth; sourceTree = ""; }; - 2C6188C22B7A8A22006B70D7 /* Theme */ = { + 2CD264752CFDC76A00A040A7 /* Fake */ = { isa = PBXGroup; children = ( - 2C6188C32B7A8A22006B70D7 /* EcosiaThemeManager.swift */, - 2C6188C42B7A8A22006B70D7 /* EcosiaThemeColourPalette.swift */, - 2C6188C52B7A8A22006B70D7 /* EcosiaTheme.swift */, + 2CD264722CFDC76A00A040A7 /* FakeNimbus.swift */, + 2CD264732CFDC76A00A040A7 /* FakeSentry.swift */, + 2CD264742CFDC76A00A040A7 /* FakeTelemetry.swift */, ); - path = Theme; + path = Fake; sourceTree = ""; }; - 2C6188C92B7A8A22006B70D7 /* Onboarding */ = { + 2CD265162CFDCB8A00A040A7 /* Ecosia */ = { isa = PBXGroup; children = ( - 2C6188CA2B7A8A22006B70D7 /* WelcomeTourRow.swift */, - 2C6188CB2B7A8A22006B70D7 /* Welcome.swift */, - 2C6188CC2B7A8A22006B70D7 /* WelcomeTour.Step.swift */, - 2C6188CD2B7A8A22006B70D7 /* WelcomeTourAction.swift */, - 2C6188CE2B7A8A22006B70D7 /* WelcomeTour.swift */, - 2C6188CF2B7A8A22006B70D7 /* WelcomeTourTransparent.swift */, - 2C6188D02B7A8A22006B70D7 /* WelcomeTourGreen.swift */, - 2C6188D12B7A8A22006B70D7 /* WelcomeNavigation.swift */, - 2C6188D22B7A8A22006B70D7 /* WelcomeTourProfit.swift */, + 2CD266542CFF56EA00A040A7 /* Network */, + 2CD266242CFE3E8500A040A7 /* Experiments */, + 2CD266222CFE3AD900A040A7 /* Bookmarks */, + 2CD266152CFE38AD00A040A7 /* Frontend */, + 2CD266192CFE38AD00A040A7 /* Settings */, + 2CD265C32CFE382C00A040A7 /* UI */, + 2CD2654F2CFDCF0900A040A7 /* Extensions */, ); - path = Onboarding; + path = Ecosia; sourceTree = ""; }; - 2C6188D32B7A8A22006B70D7 /* MultiplyImpact */ = { + 2CD2654F2CFDCF0900A040A7 /* Extensions */ = { isa = PBXGroup; children = ( - 2C6188D42B7A8A22006B70D7 /* MultiplyImpact.swift */, - 2C6188D52B7A8A22006B70D7 /* MultiplyImpactStep.swift */, + 2CD266502CFF56CB00A040A7 /* Toolbar+URLBar */, + 2CD265402CFDCF0900A040A7 /* AppSettingsTableViewController+Ecosia.swift */, + 2CD265412CFDCF0900A040A7 /* BrowserCoordinator+Ecosia.swift */, + 2CD265422CFDCF0900A040A7 /* BrowserViewController+Ecosia.swift */, + 2CD265442CFDCF0900A040A7 /* DispatchQueueHelper+BuildChannel.swift */, + 2CD265452CFDCF0900A040A7 /* ErrorPageHandler+Ecosia.swift */, + 2CD265462CFDCF0900A040A7 /* HomepageViewController+Ecosia.swift */, + 2CD265472CFDCF0900A040A7 /* LegacyThemeManager+Ecosia.swift */, + 2CD265482CFDCF0900A040A7 /* NumberFormatter+Ecosia.swift */, + 2CD265492CFDCF0900A040A7 /* SimpleToast+Ecosia.swift */, + 2CD2654A2CFDCF0900A040A7 /* SnapKit+Ecosia.swift */, + 2CD2654B2CFDCF0900A040A7 /* UIButton+Ecosia.swift */, + 2CD2654C2CFDCF0900A040A7 /* UIFont+Ecosia.swift */, + 2CD2654D2CFDCF0900A040A7 /* UIView+maskedCorners.swift */, + 2CD2654E2CFDCF0900A040A7 /* URL+Ecosia.swift */, + 2CD265612CFDCF6D00A040A7 /* UIImage+Ecosia.swift */, ); - path = MultiplyImpact; + path = Extensions; sourceTree = ""; }; - 2C6188D62B7A8A22006B70D7 /* Settings */ = { + 2CD265672CFE382C00A040A7 /* MultiplyImpact */ = { isa = PBXGroup; children = ( - 2C6188D72B7A8A22006B70D7 /* EcosiaDebugSettings.swift */, - 2C6188D82B7A8A22006B70D7 /* EcosiaSettings.swift */, - 2C6188D92B7A8A22006B70D7 /* NTPCustomizationSettingsViewController.swift */, + 2CD265652CFE382C00A040A7 /* MultiplyImpact.swift */, + 2CD265662CFE382C00A040A7 /* MultiplyImpactStep.swift */, ); - path = Settings; + path = MultiplyImpact; sourceTree = ""; }; - 2C6188DA2B7A8A22006B70D7 /* L10N */ = { + 2CD2656B2CFE382C00A040A7 /* AboutEcosia */ = { isa = PBXGroup; children = ( - 2C6188DB2B7A8A22006B70D7 /* Ecosia.strings */, - 2C6188DD2B7A8A22006B70D7 /* Plurals.stringsdict */, - 2C6188E52B7A8A22006B70D7 /* Scripts */, - 2C6188E82B7A8A22006B70D7 /* String.swift */, + 2CD265682CFE382C00A040A7 /* AboutEcosiaSection.swift */, + 2CD265692CFE382C00A040A7 /* NTPAboutEcosiaCell.swift */, + 2CD2656A2CFE382C00A040A7 /* NTPAboutEcosiaCellViewModel.swift */, ); - path = L10N; + path = AboutEcosia; sourceTree = ""; }; - 2C6188E52B7A8A22006B70D7 /* Scripts */ = { + 2CD2656C2CFE382C00A040A7 /* Account */ = { isa = PBXGroup; children = ( - 2C6188E62B7A8A22006B70D7 /* Clean.swift */, - 2C6188E72B7A8A22006B70D7 /* Validate.swift */, ); - path = Scripts; + path = Account; sourceTree = ""; }; - 2C6188ED2B7A8A22006B70D7 /* FeatureManagement */ = { + 2CD2656E2CFE382C00A040A7 /* CoreData */ = { isa = PBXGroup; children = ( - 2C6188EE2B7A8A22006B70D7 /* FeatureManagement.swift */, + 2CD2656D2CFE382C00A040A7 /* SeedCounter.xcdatamodeld */, ); - path = FeatureManagement; + path = CoreData; sourceTree = ""; }; - 2C6188EF2B7A8A22006B70D7 /* Frontend */ = { + 2CD265712CFE382C00A040A7 /* SeedProgressManager */ = { isa = PBXGroup; children = ( - 2C6188F02B7A8A22006B70D7 /* Home */, + 2CD2656F2CFE382C00A040A7 /* SeedProgressManagerProtocol.swift */, + 2CD265702CFE382C00A040A7 /* UserDefaultsSeedProgressManager.swift */, ); - path = Frontend; + path = SeedProgressManager; sourceTree = ""; }; - 2C6188F02B7A8A22006B70D7 /* Home */ = { + 2CD2657A2CFE382C00A040A7 /* ClimateImpactCounter */ = { isa = PBXGroup; children = ( - 2C6188F12B7A8A22006B70D7 /* EcosiaHomepageSectionType.swift */, - 2C6188F22B7A8A22006B70D7 /* TopSites */, + 2CD2656E2CFE382C00A040A7 /* CoreData */, + 2CD265712CFE382C00A040A7 /* SeedProgressManager */, + 2CD265722CFE382C00A040A7 /* ArcProgressView.swift */, + 2CD265732CFE382C00A040A7 /* NTPSeedCounterCell.swift */, + 2CD265742CFE382C00A040A7 /* NTPSeedCounterViewModel.swift */, + 2CD265752CFE382C00A040A7 /* SeedCounterConfig.swift */, + 2CD265762CFE382C00A040A7 /* SeedCounterHiddenSettings.swift */, + 2CD265772CFE382C00A040A7 /* SeedCounterView.swift */, + 2CD265782CFE382C00A040A7 /* SeedProgressView.swift */, + 2CD265792CFE382C00A040A7 /* Sparkle.swift */, ); - path = Home; + path = ClimateImpactCounter; sourceTree = ""; }; - 2C6188F22B7A8A22006B70D7 /* TopSites */ = { + 2CD2657E2CFE382C00A040A7 /* Customization */ = { isa = PBXGroup; children = ( - 2C6188F32B7A8A22006B70D7 /* Cell */, + 2CD2657B2CFE382C00A040A7 /* CustomizableNTPSettingConfig.swift */, + 2CD2657C2CFE382C00A040A7 /* NTPCustomizationCell.swift */, + 2CD2657D2CFE382C00A040A7 /* NTPCustomizationCellViewModel.swift */, ); - path = TopSites; + path = Customization; sourceTree = ""; }; - 2C6188F32B7A8A22006B70D7 /* Cell */ = { + 2CD265852CFE382C00A040A7 /* Impact */ = { isa = PBXGroup; children = ( - 2C6188F42B7A8A22006B70D7 /* EcosiaTopSiteItemCell.swift */, + 2CD2657F2CFE382C00A040A7 /* ClimateImpactInfo.swift */, + 2CD265802CFE382C00A040A7 /* NTPImpactCell.swift */, + 2CD265812CFE382C00A040A7 /* NTPImpactCellViewModel.swift */, + 2CD265822CFE382C00A040A7 /* NTPImpactDividerFooter.swift */, + 2CD265832CFE382C00A040A7 /* NTPImpactRowView.swift */, + 2CD265842CFE382C00A040A7 /* ProgressView.swift */, ); - path = Cell; + path = Impact; sourceTree = ""; }; - 2C6188F52B7A8A22006B70D7 /* Experiments */ = { + 2CD265892CFE382C00A040A7 /* Library */ = { isa = PBXGroup; children = ( - 2C6188F62B7A8A22006B70D7 /* Unleash */, + 2CD265862CFE382C00A040A7 /* NTPLibaryCellViewModel.swift */, + 2CD265872CFE382C00A040A7 /* NTPLibraryCell.swift */, + 2CD265882CFE382C00A040A7 /* NTPLibraryShortcutView.swift */, ); - path = Experiments; + path = Library; sourceTree = ""; }; - 2C6188F62B7A8A22006B70D7 /* Unleash */ = { + 2CD2658B2CFE382C00A040A7 /* Logo */ = { isa = PBXGroup; children = ( - 1285E2B62CC68BF00053506B /* APNConsentOnLaunchExperiment.swift */, - 2C6188F82B7A8A22006B70D7 /* BrazeIntegrationExperiment.swift */, - 2CFE600B2CD3AAB6001F35D2 /* OnboardingRemoveExperiment.swift */, + 2CD2658A2CFE382C00A040A7 /* NTPLogoCell.swift */, ); - path = Unleash; + path = Logo; sourceTree = ""; }; - 2C6188FA2B7A8A22006B70D7 /* Network */ = { + 2CD2658F2CFE382C00A040A7 /* News */ = { isa = PBXGroup; children = ( - 2C6188FB2B7A8A22006B70D7 /* WebsiteConnectionStatus.swift */, + 2CD2658C2CFE382C00A040A7 /* NewsController.swift */, + 2CD2658D2CFE382C00A040A7 /* NTPNewsCell.swift */, + 2CD2658E2CFE382C00A040A7 /* NTPNewsCellViewModel.swift */, ); - path = Network; + path = News; sourceTree = ""; }; - 2C6188FC2B7A8A22006B70D7 /* BrowserKitExtensions */ = { + 2CD265922CFE382C00A040A7 /* Newsletter */ = { isa = PBXGroup; children = ( + 2CD265902CFE382C00A040A7 /* NTPNewsletterCardCell.swift */, + 2CD265912CFE382C00A040A7 /* NTPNewsletterCardViewModel.swift */, ); - path = BrowserKitExtensions; + path = Newsletter; sourceTree = ""; }; - 2C6188FF2B7A8A22006B70D7 /* Extensions */ = { + 2CD265952CFE382C00A040A7 /* NudgeCards */ = { isa = PBXGroup; children = ( - 2C6189002B7A8A22006B70D7 /* BrowserViewController+Ecosia.swift */, - 2C6189012B7A8A22006B70D7 /* LegacyThemeManager+Ecosia.swift */, - 2C6189022B7A8A22006B70D7 /* UIButton+Ecosia.swift */, - 2C6189032B7A8A22006B70D7 /* UIFont+Ecosia.swift */, - 2C6189042B7A8A22006B70D7 /* ErrorPageHandler+Ecosia.swift */, - 2C6189052B7A8A22006B70D7 /* SnapKit+Ecosia.swift */, - 2C6189062B7A8A22006B70D7 /* HomepageViewController+Ecosia.swift */, - 2C6189072B7A8A22006B70D7 /* SimpleToast+Ecosia.swift */, - 2C6189082B7A8A22006B70D7 /* UIView+maskedCorners.swift */, - 2C61890A2B7A8A22006B70D7 /* NumberFormatter+Ecosia.swift */, - 2C61890B2B7A8A22006B70D7 /* URL+Ecosia.swift */, - 2C61890C2B7A8A22006B70D7 /* BrowserCoordinator+Ecosia.swift */, - 2C61890D2B7A8A22006B70D7 /* AppSettingsTableViewController+Ecosia.swift */, - 2C61890E2B7A8A22006B70D7 /* DeviceInfo+Ecosia.swift */, - 2C61890F2B7A8A22006B70D7 /* Toolbar+URLBar */, - 2C03A4142CB7C7CC00AB228B /* DispatchQueueHelper+BuildChannel.swift */, + 2CD265922CFE382C00A040A7 /* Newsletter */, + 2CD265932CFE382C00A040A7 /* NTPConfigurableNudgeCardCell.swift */, + 2CD265942CFE382C00A040A7 /* NTPConfigurableNudgeCardCellViewModel.swift */, ); - path = Extensions; + path = NudgeCards; sourceTree = ""; }; - 2C61890F2B7A8A22006B70D7 /* Toolbar+URLBar */ = { + 2CD2659C2CFE382C00A040A7 /* NTP */ = { isa = PBXGroup; children = ( - 2C6189102B7A8A22006B70D7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift */, - 2C6189122B7A8A22006B70D7 /* ConnectionStatusImage.swift */, + 2CD2656B2CFE382C00A040A7 /* AboutEcosia */, + 2CD2656C2CFE382C00A040A7 /* Account */, + 2CD2657A2CFE382C00A040A7 /* ClimateImpactCounter */, + 2CD2657E2CFE382C00A040A7 /* Customization */, + 2CD265852CFE382C00A040A7 /* Impact */, + 2CD265892CFE382C00A040A7 /* Library */, + 2CD2658B2CFE382C00A040A7 /* Logo */, + 2CD2658F2CFE382C00A040A7 /* News */, + 2CD265952CFE382C00A040A7 /* NudgeCards */, + 2CD265962CFE382C00A040A7 /* CircleButton.swift */, + 2CD265972CFE382C00A040A7 /* DefaultBrowser.swift */, + 2CD265982CFE382C00A040A7 /* NTPLayout.swift */, + 2CD265992CFE382C00A040A7 /* NTPTooltip.Highlight.swift */, + 2CD2659A2CFE382C00A040A7 /* NTPTooltip.swift */, + 2CD2659B2CFE382C00A040A7 /* NTPTooltipDelegate.swift */, ); - path = "Toolbar+URLBar"; + path = NTP; sourceTree = ""; }; - 2C6189132B7A8A22006B70D7 /* Entitlements */ = { + 2CD265A62CFE382C00A040A7 /* Onboarding */ = { isa = PBXGroup; children = ( - 2C08319A2B89124000BD7134 /* AppExtensions */, - 2C6189142B7A8A22006B70D7 /* EcosiaBeta.entitlements */, - 2C6189152B7A8A22006B70D7 /* Ecosia.entitlements */, + 2CD2659D2CFE382C00A040A7 /* Welcome.swift */, + 2CD2659E2CFE382C00A040A7 /* WelcomeNavigation.swift */, + 2CD2659F2CFE382C00A040A7 /* WelcomeTour.Step.swift */, + 2CD265A02CFE382C00A040A7 /* WelcomeTour.swift */, + 2CD265A12CFE382C00A040A7 /* WelcomeTourAction.swift */, + 2CD265A22CFE382C00A040A7 /* WelcomeTourGreen.swift */, + 2CD265A32CFE382C00A040A7 /* WelcomeTourProfit.swift */, + 2CD265A42CFE382C00A040A7 /* WelcomeTourRow.swift */, + 2CD265A52CFE382C00A040A7 /* WelcomeTourTransparent.swift */, ); - path = Entitlements; + path = Onboarding; sourceTree = ""; }; - 2C6189162B7A8A22006B70D7 /* Bookmarks */ = { + 2CD265AA2CFE382C00A040A7 /* PageAction */ = { isa = PBXGroup; children = ( - 2C6189172B7A8A22006B70D7 /* BookmarksExchange.swift */, + 2CD265A72CFE382C00A040A7 /* PageActionMenu.swift */, + 2CD265A82CFE382C00A040A7 /* PageActionMenuCell.swift */, + 2CD265A92CFE382C00A040A7 /* PageActionsShortcutsHeader.swift */, ); - path = Bookmarks; + path = PageAction; sourceTree = ""; }; - 2C6189192B7A8A22006B70D7 /* Fake */ = { + 2CD265AE2CFE382C00A040A7 /* Theme */ = { isa = PBXGroup; children = ( - 2C61891A2B7A8A22006B70D7 /* FakeTelemetry.swift */, - 2C61891B2B7A8A22006B70D7 /* FakeNimbus.swift */, - 2C61891C2B7A8A22006B70D7 /* FakeSentry.swift */, + 2CD265AB2CFE382C00A040A7 /* EcosiaTheme.swift */, + 2CD265AC2CFE382C00A040A7 /* EcosiaThemeColourPalette.swift */, + 2CD265AD2CFE382C00A040A7 /* EcosiaThemeManager.swift */, ); - path = Fake; + path = Theme; sourceTree = ""; }; - 2C6189242B7A8A22006B70D7 /* AppInfoProvider */ = { + 2CD265B12CFE382C00A040A7 /* DataProvider */ = { isa = PBXGroup; children = ( - 2C6189252B7A8A22006B70D7 /* DefaultAppVersionInfoProvider.swift */, - 2C6189262B7A8A22006B70D7 /* AppVersionInfoProvider.swift */, + 2CD265AF2CFE382C00A040A7 /* WhatsNewDataProvider.swift */, + 2CD265B02CFE382C00A040A7 /* WhatsNewLocalDataProvider.swift */, ); - path = AppInfoProvider; + path = DataProvider; sourceTree = ""; }; - 2C6189272B7A8A22006B70D7 /* EcosiaInstallType */ = { + 2CD265B62CFE382C00A040A7 /* WhatsNew */ = { isa = PBXGroup; children = ( - 2C6189282B7A8A22006B70D7 /* EcosiaInstallType.swift */, - 2C6189292B7A8A22006B70D7 /* EcosiaInstallType+Extensions.swift */, + 2CD265B12CFE382C00A040A7 /* DataProvider */, + 2CD265B22CFE382C00A040A7 /* WhatsNewCell.swift */, + 2CD265B32CFE382C00A040A7 /* WhatsNewItem.swift */, + 2CD265B42CFE382C00A040A7 /* WhatsNewViewController.swift */, + 2CD265B52CFE382C00A040A7 /* WhatsNewViewModel.swift */, ); - path = EcosiaInstallType; + path = WhatsNew; sourceTree = ""; }; - 2C61892A2B7A8A22006B70D7 /* Version */ = { + 2CD265C32CFE382C00A040A7 /* UI */ = { + isa = PBXGroup; + children = ( + 2CD265672CFE382C00A040A7 /* MultiplyImpact */, + 2CD2659C2CFE382C00A040A7 /* NTP */, + 2CD265A62CFE382C00A040A7 /* Onboarding */, + 2CD265AA2CFE382C00A040A7 /* PageAction */, + 2CD265AE2CFE382C00A040A7 /* Theme */, + 2CD265B62CFE382C00A040A7 /* WhatsNew */, + 2CD265B72CFE382C00A040A7 /* Colours.xcassets */, + 2CD265B82CFE382C00A040A7 /* Ecosia.xcassets */, + 2CD265B92CFE382C00A040A7 /* EcosiaFindInPageBar.swift */, + 2CD265BA2CFE382C00A040A7 /* EcosiaNavigation.swift */, + 2CD265BB2CFE382C00A040A7 /* EmptyBookmarksView.swift */, + 2CD265BC2CFE382C00A040A7 /* EmptyBookmarksViewDelegate.swift */, + 2CD265BD2CFE382C00A040A7 /* EmptyHeader.swift */, + 2CD265BE2CFE382C00A040A7 /* EmptyReadingListView.swift */, + 2CD265BF2CFE382C00A040A7 /* FilterController.swift */, + 2CD265C02CFE382C00A040A7 /* LoadingScreen.swift */, + 2CD265C12CFE382C00A040A7 /* MarketsController.swift */, + 2CD265C22CFE382C00A040A7 /* SemanticColor.swift */, + 2CD2661F2CFE39E300A040A7 /* EcosiaPrimaryButton.swift */, + ); + path = UI; + sourceTree = ""; + }; + 2CD266112CFE38AD00A040A7 /* Cell */ = { isa = PBXGroup; children = ( - 2C61892B2B7A8A22006B70D7 /* Version.swift */, - 2C61892C2B7A8A22006B70D7 /* Version+Extensions.swift */, + 2CD266102CFE38AD00A040A7 /* EcosiaTopSiteItemCell.swift */, ); - path = Version; + path = Cell; sourceTree = ""; }; - 2C61892D2B7A8A22006B70D7 /* Analytics */ = { + 2CD266122CFE38AD00A040A7 /* TopSites */ = { isa = PBXGroup; children = ( - 2C61892E2B7A8A22006B70D7 /* Analytics.swift */, - 2C61892F2B7A8A22006B70D7 /* Analytics+Configuration.swift */, - 2C6189302B7A8A22006B70D7 /* Analytics.Values.swift */, - 2C9258DA2CEFB26500C6BB8D /* AnalyticsNotificationSettings.swift */, + 2CD266112CFE38AD00A040A7 /* Cell */, ); - path = Analytics; + path = TopSites; sourceTree = ""; }; - 2C69DA732C62185000D7F69F /* Mocks */ = { + 2CD266142CFE38AD00A040A7 /* Home */ = { isa = PBXGroup; children = ( - 2C69DA742C62185A00D7F69F /* Welcome.swift */, - 2C82625D2C66661700E2A255 /* EcosiaMockThemeManager.swift */, + 2CD266122CFE38AD00A040A7 /* TopSites */, + 2CD266132CFE38AD00A040A7 /* EcosiaHomepageSectionType.swift */, ); - path = Mocks; + path = Home; sourceTree = ""; }; - 2C69DA872C63A53C00D7F69F /* NTP */ = { + 2CD266152CFE38AD00A040A7 /* Frontend */ = { isa = PBXGroup; children = ( - 2C69DA762C62243300D7F69F /* NTPTests.swift */, - 2C69DA832C62B44B00D7F69F /* NTPComponentTests.swift */, + 2CD266142CFE38AD00A040A7 /* Home */, ); - path = NTP; + path = Frontend; sourceTree = ""; }; - 2C69DA882C63A54100D7F69F /* Onboarding */ = { + 2CD266192CFE38AD00A040A7 /* Settings */ = { isa = PBXGroup; children = ( - 2CD368492C5BC31700972871 /* OnboardingTests.swift */, + 2CD266162CFE38AD00A040A7 /* EcosiaDebugSettings.swift */, + 2CD266172CFE38AD00A040A7 /* EcosiaSettings.swift */, + 2CD266182CFE38AD00A040A7 /* NTPCustomizationSettingsViewController.swift */, ); - path = Onboarding; + path = Settings; sourceTree = ""; }; - 2C6B5B3C2CAAF27F00F15323 /* ClimateImpactCounter */ = { + 2CD266222CFE3AD900A040A7 /* Bookmarks */ = { isa = PBXGroup; children = ( - 2C4ABD482CB58E4F00FF86F9 /* Sparkle.swift */, - 2C6B5B3A2CAAF27F00F15323 /* NTPSeedCounterCell.swift */, - 2C6B5B3B2CAAF27F00F15323 /* NTPSeedCounterViewModel.swift */, - 2CCBB5222CAE9826006E2E10 /* ArcProgressView.swift */, - 2CCBB5242CAEA9DF006E2E10 /* SeedProgressView.swift */, - 2CCBB5262CAEAD53006E2E10 /* SeedCounterView.swift */, - 2CCBB5362CAF0E8C006E2E10 /* SeedCounterHiddenSettings.swift */, - 2C5A5E682CB53E05005BFE8B /* SeedProgressManager */, - 2C5A5E642CB53DB7005BFE8B /* SeedCounterConfig.swift */, + 2CD266212CFE3AD900A040A7 /* BookmarksExchange.swift */, ); - path = ClimateImpactCounter; + path = Bookmarks; sourceTree = ""; }; - 2C7DBABA2C4EA14C00BCD03F /* IntegrationTests */ = { + 2CD266242CFE3E8500A040A7 /* Experiments */ = { isa = PBXGroup; children = ( - 2C7DBABB2C4EA17200BCD03F /* AppDelegateFeatureManagementIntegrationTests.swift */, + 2CD266252CFE3E8D00A040A7 /* Unleash */, ); - path = IntegrationTests; + path = Experiments; sourceTree = ""; }; - 2C872A522B8CD45F00B318A0 /* Mocks */ = { + 2CD266252CFE3E8D00A040A7 /* Unleash */ = { isa = PBXGroup; children = ( - 2C872A532B8CD47600B318A0 /* MockAppVersionInfoProvider.swift */, - 2C9A62BF2CDE1F7600CDA7D1 /* MockWelcomeDelegate.swift */, - 2C9A62C12CDE4A3B00CDA7D1 /* MockNewsModel.swift */, - 2C9258D82CEF97B100C6BB8D /* MockUNNotificationSettings.swift */, + 2CD2662A2CFE402000A040A7 /* SeedCounterNTPExperiment.swift */, ); - path = Mocks; + path = Unleash; sourceTree = ""; }; - 2CA995262CA2C053001064CC /* NudgeCards */ = { + 2CD266302CFE403800A040A7 /* Unleash */ = { isa = PBXGroup; children = ( - 12147F2D2CDA3CB40009D300 /* Newsletter */, - 2CA995272CA2C06A001064CC /* NTPConfigurableNudgeCardCell.swift */, - 2CA995292CA2C0BB001064CC /* NTPConfigurableNudgeCardCellViewModel.swift */, + 2CD2662C2CFE403800A040A7 /* APNConsentOnLaunchExperiment.swift */, + 2CD2662D2CFE403800A040A7 /* BrazeIntegrationExperiment.swift */, + 2CD2662E2CFE403800A040A7 /* NewsletterCardExperiment.swift */, + 2CD2662F2CFE403800A040A7 /* OnboardingRemoveExperiment.swift */, ); - path = NudgeCards; + path = Unleash; sourceTree = ""; }; - 2CABD71A2C11E07300A0750F /* PersistedGenerated */ = { + 2CD266312CFE403800A040A7 /* Experiments */ = { isa = PBXGroup; children = ( - 2C0360D92C1747E6006706F2 /* FxNimbus.swift */, + 2CD266302CFE403800A040A7 /* Unleash */, ); - path = PersistedGenerated; + path = Experiments; sourceTree = ""; }; - 2CBCAAFA2B88EEE40080AD68 /* Configuration */ = { + 2CD2663A2CFE421C00A040A7 /* Extensions */ = { isa = PBXGroup; children = ( - 2CBCAB0C2B88EEE40080AD68 /* Ecosia.xcconfig */, - 2CBCAAFB2B88EEE40080AD68 /* Ecosia.WidgetKit.xcconfig */, - 2CBCAAFD2B88EEE40080AD68 /* Ecosia.ShareTo.xcconfig */, - 2CBCAB0E2B88EEE40080AD68 /* EcosiaDebug.xcconfig */, - 2CBCAB0D2B88EEE40080AD68 /* EcosiaDebug.WidgetKit.xcconfig */, - 2CBCAB072B88EEE40080AD68 /* EcosiaDebug.ShareTo.xcconfig */, - 2CBCAB0B2B88EEE40080AD68 /* EcosiaBeta.xcconfig */, - 2CBCAB042B88EEE40080AD68 /* EcosiaBeta.WidgetKit.xcconfig */, - 2CBCAAFC2B88EEE40080AD68 /* EcosiaBeta.ShareTo.xcconfig */, - 2CBCAAFE2B88EEE40080AD68 /* EcosiaBetaDebug.xcconfig */, - 2CBCAB092B88EEE40080AD68 /* EcosiaBetaDebug.ShareTo.xcconfig */, - 2CBCAB022B88EEE40080AD68 /* EcosiaBetaDebug.WidgetKit.xcconfig */, - 2CBCAB002B88EEE40080AD68 /* Common.xcconfig */, - 2CBCAB032B88EEE40080AD68 /* Debug.xcconfig */, - 2CBCAB082B88EEE40080AD68 /* Staging.xcconfig */, - 2CBCAB062B88EEE40080AD68 /* Release.xcconfig */, - 2CEB48402BE0EE2600498471 /* Production.xcconfig */, - 2CBCAB0A2B88EEE40080AD68 /* Fennec.enterprise.xcconfig */, - 2CBCAAFF2B88EEE40080AD68 /* Firefox.xcconfig */, - 2CBCAB052B88EEE40080AD68 /* FirefoxBeta.xcconfig */, - 2CBCAB012B88EEE40080AD68 /* Fennec.xcconfig */, + 2CD2663D2CFF4ED000A040A7 /* DeviceInfo+Ecosia.swift */, + 2CD2663B2CFE423D00A040A7 /* AppInfo+Ecosia.swift */, ); - path = Configuration; + path = Extensions; sourceTree = ""; }; - 2CD3683F2C5BA30A00972871 /* SnapshotTests */ = { + 2CD266502CFF56CB00A040A7 /* Toolbar+URLBar */ = { isa = PBXGroup; children = ( - 2C8262572C64424300E2A255 /* EcosiaSnapshotTests.xctestplan */, - 2C69DA882C63A54100D7F69F /* Onboarding */, - 2C69DA872C63A53C00D7F69F /* NTP */, - 2C69DA732C62185000D7F69F /* Mocks */, - 2C69DA712C62175400D7F69F /* SnapshotTestHelper.swift */, - 2C69DA912C63A92D00D7F69F /* SnapshotBaseTests.swift */, - 2C69DA932C63B0C000D7F69F /* String+Extension.swift */, - 2C8262592C64BB9300E2A255 /* DeviceType.swift */, - 2C82625B2C6648D900E2A255 /* LocalizationOverrideTestingBundle.swift */, - 2C5B81C72C75388300B81D95 /* LocaleRetriever.swift */, - 2C19DACE2C74C7BF00D2641C /* snapshot_configuration.json */, - 2C4D165F2C76360800E89C95 /* environment.json */, + 2CD2664E2CFF56CB00A040A7 /* ConnectionStatusImage.swift */, + 2CD2664F2CFF56CB00A040A7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift */, ); - path = SnapshotTests; + path = "Toolbar+URLBar"; sourceTree = ""; }; - 2CE2945C2B7FC51E006C22B2 /* EcosiaTests */ = { + 2CD266542CFF56EA00A040A7 /* Network */ = { isa = PBXGroup; children = ( - 1285E2B32CC293A20053506B /* Analytics */, - 2C16B7642CAF2417006118F8 /* ClimateImpactCounter */, - 2CD3683F2C5BA30A00972871 /* SnapshotTests */, - 2C7DBABA2C4EA14C00BCD03F /* IntegrationTests */, - 2C872A522B8CD45F00B318A0 /* Mocks */, - 2CE294672B7FC5A4006C22B2 /* EcosiaInstallTypeTests.swift */, - 2CE2946C2B7FC5A5006C22B2 /* EcosiaNTPTooltipHighlightTests.swift */, - 2CE2946D2B7FC5A5006C22B2 /* EcosiaPageActionMenuCellTests.swift */, - 2CE294702B7FC5A6006C22B2 /* VersionTests.swift */, - 2CE2946B2B7FC5A5006C22B2 /* WhatsNewLocalDataProviderTests.swift */, - 2C872A562B8CD65100B318A0 /* EcosiaHomeViewModelTests.swift */, - 2C26EA132C04CAD100795552 /* EcosiaTopSitesHelperTests.swift */, - 2CABD7272C12EF1E00A0750F /* PrivateModeButtonTests.swift */, - 2C2349A22C57E5BC007A5894 /* EcosiaPerformanceTestHistory.swift */, - 2CD48B7E2C7F7E4100A70908 /* EcosiaOverlayModeManagerTests.swift */, + 2CD266532CFF56EA00A040A7 /* WebsiteConnectionStatus.swift */, ); - path = EcosiaTests; + path = Network; sourceTree = ""; }; 2F44FC551A9E83E200FD20CC /* Settings */ = { @@ -12077,7 +12899,6 @@ children = ( 7B3632E71C29879300D12AF9 /* Snapshot */, D4AFA84B2AFA4FC6000BFEAA /* firefox-ios-tests */, - 2CE2945C2B7FC51E006C22B2 /* EcosiaTests */, 962C6C39297054A700354BE8 /* Package.swift */, 962C6C3F2971F5D400354BE8 /* Dangerfile.swift */, 962C6C3B297054EC00354BE8 /* Sources */, @@ -12133,9 +12954,9 @@ F84B21C01A090F8100AAB793 /* Client */ = { isa = PBXGroup; children = ( + 2CD265162CFDCB8A00A040A7 /* Ecosia */, 2CABD71A2C11E07300A0750F /* PersistedGenerated */, 2CBCAAFA2B88EEE40080AD68 /* Configuration */, - 2C61887E2B7A8A21006B70D7 /* Ecosia */, 8AD984F12AF1554F00B9FDA4 /* ContentBlocker */, 216A0D6F2A40D0E4008077BA /* Redux */, 8A93F85C29D36D9F004159D9 /* Coordinators */, @@ -13185,6 +14006,20 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2CD264972CFDC76A00A040A7 /* Plurals.stringsdict in Resources */, + 2CD264A42CFDC76A00A040A7 /* EcosiaLaunchScreen.xib in Resources */, + 2CD264982CFDC76A00A040A7 /* Plurals.stringsdict in Resources */, + 2CD264992CFDC76A00A040A7 /* Plurals.stringsdict in Resources */, + 2CD264922CFDC76A00A040A7 /* Ecosia.strings in Resources */, + 2CD2648F2CFDC76A00A040A7 /* Ecosia.strings in Resources */, + 2CD264952CFDC76A00A040A7 /* Plurals.stringsdict in Resources */, + 2CD264A92CFDC76A00A040A7 /* markets.json in Resources */, + 2CD264902CFDC76A00A040A7 /* Ecosia.strings in Resources */, + 2CD264912CFDC76A00A040A7 /* Ecosia.strings in Resources */, + 2CD264932CFDC76A00A040A7 /* Ecosia.strings in Resources */, + 2CD264942CFDC76A00A040A7 /* Plurals.stringsdict in Resources */, + 2CD2648E2CFDC76A00A040A7 /* Ecosia.strings in Resources */, + 2CD264962CFDC76A00A040A7 /* Plurals.stringsdict in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -13192,6 +14027,259 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2CD263702CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD263342CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD262CC2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD262F42CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, + 2CD262FD2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png in Resources */, + 2CD2635B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD263452CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, + 2CD2634F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png in Resources */, + 2CD2631A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, + 2CD262EF2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, + 2CD2639F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png in Resources */, + 2CD2635C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD2639A2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png in Resources */, + 2CD2632F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, + 2CD2632E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, + 2CD262C22CFDC5EB00A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD263122CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png in Resources */, + 2CD263112CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png in Resources */, + 2CD262FF2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png in Resources */, + 2CD263002CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png in Resources */, + 2CD263B12CFDC5EB00A040A7 /* OnboardingTests_tests.xcresult in Resources */, + 2CD262D32CFDC5EB00A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD2633E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */, + 2CD263612CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png in Resources */, + 2CD2631D2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, + 2CD263A42CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */, + 2CD262C62CFDC5EB00A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD262C52CFDC5EB00A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD263352CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png in Resources */, + 2CD262E62CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png in Resources */, + 2CD2638F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, + 2CD263742CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png in Resources */, + 2CD2633F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, + 2CD2639B2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png in Resources */, + 2CD263662CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */, + 2CD262B42CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD262E32CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD2632B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png in Resources */, + 2CD263622CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png in Resources */, + 2CD263542CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */, + 2CD262C82CFDC5EB00A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD263162CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */, + 2CD263012CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png in Resources */, + 2CD262CF2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD2638A2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png in Resources */, + 2CD263442CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, + 2CD2630D2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png in Resources */, + 2CD262D82CFDC5EB00A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD262BF2CFDC5EB00A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD263172CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, + 2CD263592CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, + 2CD263382CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png in Resources */, + 2CD262B82CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD262F62CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_de.1.png in Resources */, + 2CD2638C2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */, + 2CD2636C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, + 2CD263792CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png in Resources */, + 2CD263062CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, + 2CD262BA2CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD262E12CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, + 2CD2639E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png in Resources */, + 2CD263722CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png in Resources */, + 2CD262D52CFDC5EB00A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD262DA2CFDC5EB00A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD263802CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, + 2CD263952CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, + 2CD262BC2CFDC5EB00A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD262B62CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD262F02CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */, + 2CD2632D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, + 2CD263882CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png in Resources */, + 2CD2633B2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, + 2CD262D02CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD263B02CFDC5EB00A040A7 /* NTPComponentTests_tests.xcresult in Resources */, + 2CD2637C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */, + 2CD2633C2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */, + 2CD263AB2CFDC5EB00A040A7 /* snapshot_configuration.json in Resources */, + 2CD263292CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png in Resources */, + 2CD2638E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */, + 2CD263602CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png in Resources */, + 2CD263492CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png in Resources */, + 2CD262EB2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, + 2CD263582CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, + 2CD262E22CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_de.1.png in Resources */, + 2CD262E72CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png in Resources */, + 2CD2637D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, + 2CD263502CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png in Resources */, + 2CD263082CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, + 2CD263572CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, + 2CD262AE2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD2631F2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD263132CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, + 2CD262E42CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD262BE2CFDC5EB00A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD262D42CFDC5EB00A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD262BB2CFDC5EB00A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD263842CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD262CA2CFDC5EB00A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD263072CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, + 2CD262F12CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, + 2CD263212CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png in Resources */, + 2CD263092CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, + 2CD263302CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, + 2CD263762CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png in Resources */, + 2CD263732CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png in Resources */, + 2CD2637F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, + 2CD263912CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, + 2CD263822CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png in Resources */, + 2CD262B72CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD2630B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD262C72CFDC5EB00A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD262DE2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, + 2CD2636F2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD262B22CFDC5EB00A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD262E92CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png in Resources */, + 2CD263262CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png in Resources */, + 2CD263782CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png in Resources */, + 2CD263852CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png in Resources */, + 2CD263812CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, + 2CD263022CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png in Resources */, + 2CD262BD2CFDC5EB00A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD263562CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, + 2CD263692CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, + 2CD2635A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png in Resources */, + 2CD2635D2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png in Resources */, + 2CD263402CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */, + 2CD263182CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */, + 2CD263412CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, + 2CD263772CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png in Resources */, + 2CD263862CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png in Resources */, + 2CD263482CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD2634C2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png in Resources */, + 2CD262EC2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */, + 2CD2635F2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png in Resources */, + 2CD263462CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png in Resources */, + 2CD262D12CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD2634E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png in Resources */, + 2CD2639C2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png in Resources */, + 2CD2631E2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png in Resources */, + 2CD262D72CFDC5EB00A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD263252CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png in Resources */, + 2CD263272CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png in Resources */, + 2CD262AF2CFDC5EB00A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD262B52CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD262F72CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD263992CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png in Resources */, + 2CD263512CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png in Resources */, + 2CD2630E2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png in Resources */, + 2CD262CE2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD2636B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, + 2CD262DD2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, + 2CD262E82CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png in Resources */, + 2CD2634A2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png in Resources */, + 2CD263832CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD2634D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png in Resources */, + 2CD263242CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png in Resources */, + 2CD262CB2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD2636A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, + 2CD262E02CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, + 2CD263142CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */, + 2CD262B32CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD2636E2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png in Resources */, + 2CD263932CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, + 2CD262C32CFDC5EB00A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD263A72CFDC5EB00A040A7 /* EcosiaSnapshotTests.xctestplan in Resources */, + 2CD263102CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png in Resources */, + 2CD2633D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */, + 2CD262D92CFDC5EB00A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD263672CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, + 2CD263652CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */, + 2CD263712CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png in Resources */, + 2CD2638D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */, + 2CD263902CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */, + 2CD2631C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, + 2CD2636D2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, + 2CD263922CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, + 2CD263472CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD263552CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, + 2CD262B02CFDC5EB00A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD263332CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD263682CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */, + 2CD2632C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */, + 2CD263A32CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png in Resources */, + 2CD263752CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png in Resources */, + 2CD262D22CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD263032CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png in Resources */, + 2CD263432CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, + 2CD263392CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png in Resources */, + 2CD263A82CFDC5EB00A040A7 /* environment.json in Resources */, + 2CD263A12CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png in Resources */, + 2CD2637A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png in Resources */, + 2CD262DF2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, + 2CD262C42CFDC5EB00A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD2630A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png in Resources */, + 2CD263152CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */, + 2CD262AC2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD2630C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD263942CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, + 2CD262C12CFDC5EB00A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD262FA2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_nl.1.png in Resources */, + 2CD262F82CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD263282CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png in Resources */, + 2CD263422CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, + 2CD263982CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD262FC2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png in Resources */, + 2CD2633A2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png in Resources */, + 2CD2635E2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png in Resources */, + 2CD262C02CFDC5EB00A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png in Resources */, + 2CD2639D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png in Resources */, + 2CD263892CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png in Resources */, + 2CD263632CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, + 2CD263222CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png in Resources */, + 2CD2632A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png in Resources */, + 2CD262AB2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png in Resources */, + 2CD262F92CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_it.1.png in Resources */, + 2CD262AD2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD262F32CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, + 2CD262D62CFDC5EB00A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD263972CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD263202CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png in Resources */, + 2CD262F22CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, + 2CD262EE2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */, + 2CD262B12CFDC5EB00A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD2637E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, + 2CD263362CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png in Resources */, + 2CD2637B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png in Resources */, + 2CD262C92CFDC5EB00A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD263962CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png in Resources */, + 2CD262F52CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, + 2CD263A02CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png in Resources */, + 2CD262E52CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_it.1.png in Resources */, + 2CD263052CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, + 2CD262ED2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */, + 2CD263312CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, + 2CD263522CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png in Resources */, + 2CD2634B2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png in Resources */, + 2CD2630F2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png in Resources */, + 2CD2638B2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, + 2CD262CD2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD263192CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, + 2CD263532CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png in Resources */, + 2CD263642CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */, + 2CD263042CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */, + 2CD262FE2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png in Resources */, + 2CD262B92CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png in Resources */, + 2CD263322CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png in Resources */, + 2CD263872CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png in Resources */, + 2CD263232CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png in Resources */, + 2CD263372CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png in Resources */, + 2CD262FB2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png in Resources */, + 2CD2631B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, + 2CD263A22CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png in Resources */, + 2CD262EA2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -13270,8 +14358,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2C19DACF2C74C7BF00D2641C /* snapshot_configuration.json in Resources */, - 2C4D16602C76360800E89C95 /* environment.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -13289,10 +14375,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2C6189632B7A8A22006B70D7 /* Colours.xcassets in Resources */, 8AA1A8842AF2A0C90026B0E0 /* disconnect-block-social.json in Resources */, - 2C61897A2B7A8A22006B70D7 /* Plurals.stringsdict in Resources */, - 2C6189792B7A8A22006B70D7 /* Ecosia.strings in Resources */, 8AA1A8852AF2A0C90026B0E0 /* disconnect-block-cookies-social.json in Resources */, 8AA1A8862AF2A0C90026B0E0 /* disconnect-block-fingerprinting.json in Resources */, 8AA1A8872AF2A0C90026B0E0 /* disconnect-block-cryptomining.json in Resources */, @@ -13309,7 +14392,6 @@ 8AEE62CB2756BA34003207D1 /* DownloadHelper.js in Resources */, 8AEE62CA2756BA34003207D1 /* TrackingProtectionStats.js in Resources */, 0BA1E0301B051A07007675AF /* NetError.css in Resources */, - 2C6189992B7A8A22006B70D7 /* markets.json in Resources */, 3BC659491E5BA4AE006D560F /* TopSites in Resources */, F84B220B1A0910F600AAB793 /* Images.xcassets in Resources */, F35B8D2B1D6380EA008E3D61 /* SessionRestore.html in Resources */, @@ -13319,12 +14401,12 @@ 3BC659591E5BA505006D560F /* bundle_sites.json in Resources */, E4CD9F541A71506400318571 /* Reader.html in Resources */, E1AF3563286DE5F800960045 /* FullFunctionalTestPlan.xctestplan in Resources */, - 2C6189322B7A8A22006B70D7 /* EcosiaLaunchScreen.xib in Resources */, E1AF3567286DE5F800960045 /* PerformanceTestPlan.xctestplan in Resources */, 23BEA76A251A99ED00A014BF /* NewYorkMedium-RegularItalic.otf in Resources */, 7B2142FE1E5E055000CDD3FC /* InfoPlist.strings in Resources */, E1AF27442A17BCF700CE5991 /* engagementNotificationWithoutConditions.json in Resources */, E69922171B94E3EF007C480D /* Licenses.html in Resources */, + 2CD266042CFE382C00A040A7 /* Colours.xcassets in Resources */, E1AF3560286DE5F800960045 /* Smoketest3.xctestplan in Resources */, E4CD9F5B1A71506C00318571 /* Reader.css in Resources */, D0FCF8061FE4772D004A7995 /* AllFramesAtDocumentEnd.js in Resources */, @@ -13342,12 +14424,12 @@ FA9294011D6584A200AC8D33 /* QRCode.xcassets in Resources */, D308EE561CBF0BF5006843F2 /* CertError.css in Resources */, E1AF3566286DE5F800960045 /* SmokeXCUITests.xctestplan in Resources */, + 2CD266052CFE382C00A040A7 /* Ecosia.xcassets in Resources */, E1AF3561286DE5F800960045 /* Smoketest4.xctestplan in Resources */, 0BA1E00E1B03FB0B007675AF /* NetError.html in Resources */, 23BEA768251A99ED00A014BF /* NewYorkMedium-BoldItalic.otf in Resources */, E4A961381AC06FA50069AD6F /* ReaderViewLoading.html in Resources */, E1AF3565286DE5F800960045 /* UnitTest.xctestplan in Resources */, - 2C61893A2B7A8A22006B70D7 /* Ecosia.xcassets in Resources */, E1AF3564286DE5F800960045 /* SyncIntegrationTestPlan.xctestplan in Resources */, 8AEE62C92756BA34003207D1 /* LoginsHelper.js in Resources */, D0E17FB6201F847600F1FCB5 /* FxASignIn.js in Resources */, @@ -13509,18 +14591,20 @@ buildActionMask = 2147483647; files = ( 2C6189E42B7B7946006B70D7 /* LegacyDarkTheme.swift in Sources */, - 2C6189DD2B7B7776006B70D7 /* AppInfo+Ecosia.swift in Sources */, + 2CD266442CFF4FC400A040A7 /* SemanticColor.swift in Sources */, 047F9B3E24E1FF4000CD7DF7 /* SearchQuickLinks.swift in Sources */, 43118CF3251A9CCA00F24376 /* LegacyTabDataRetriever.swift in Sources */, DA9FD88624E213CD00168D1E /* Helpers.swift in Sources */, 1DF426CF251BDF6A0086386A /* photon-colors.swift in Sources */, 4392FB5C252EC51E00AD3D23 /* PrivilegedRequest.swift in Sources */, 1D06AE6A24FEE8D6000B092B /* TabProvider.swift in Sources */, - 2C6189E02B7B7916006B70D7 /* EcosiaThemeColourPalette.swift in Sources */, 8A03309828C2691800286539 /* LegacyTabFileManager.swift in Sources */, DA9FD88424E213B500168D1E /* SmallQuickLink.swift in Sources */, + 2CD266402CFF4FA300A040A7 /* EcosiaTheme.swift in Sources */, 435222C225882E3800FCA5B6 /* WidgetKitTopSiteModel.swift in Sources */, 1D06AE6624FEE4D5000B092B /* TopSitesProvider.swift in Sources */, + 2CD266462CFF4FD200A040A7 /* EcosiaThemeManager.swift in Sources */, + 2CD266422CFF4FB200A040A7 /* LegacyThemeManager+Ecosia.swift in Sources */, 215B458027D7FD7D00E5E800 /* LegacyTabGroupData.swift in Sources */, 2C6189E22B7B7929006B70D7 /* LegacyThemeManager.swift in Sources */, 2C6189EB2B7B7AB4006B70D7 /* DispatchQueueHelper.swift in Sources */, @@ -13528,8 +14612,6 @@ E18BAB0128E4AEF300098AE2 /* ImageIdentifiers.swift in Sources */, 4392FB48252EC50400AD3D23 /* InternalSchemeHandler.swift in Sources */, 435E34B3254A6A6000406D92 /* TimeConstants.swift in Sources */, - 2C6189E92B7B7979006B70D7 /* EcosiaTheme.swift in Sources */, - 2C6189E72B7B7952006B70D7 /* SemanticColor.swift in Sources */, 43E69ED7254D081F00B591C2 /* SimpleTab.swift in Sources */, 1DDAD13E24F0651C007623C8 /* TopSitesWidget.swift in Sources */, 4392FB20252EC49D00AD3D23 /* LegacySessionData.swift in Sources */, @@ -13537,10 +14619,9 @@ 047F9B4224E1FF4000CD7DF7 /* ImageButtonWithLabel.swift in Sources */, 2C6189DE2B7B78ED006B70D7 /* LegacyTheme.swift in Sources */, 047F9B2C24E1FE1C00CD7DF7 /* WidgetKit.swift in Sources */, - 2C3BD5EB2BF6193B00E25B0D /* EcosiaThemeManager.swift in Sources */, 1DA3CE6724EEE86C00422BB2 /* AppInfo.swift in Sources */, - 2C26FAAA2C8752D20055760A /* LegacyThemeManager+Ecosia.swift in Sources */, 4392FB34252EC4CE00AD3D23 /* SessionRestoreHandler.swift in Sources */, + 2CD266482CFF4FE800A040A7 /* EcosiaThemeColourPalette.swift in Sources */, DA9FD88824E213DD00168D1E /* QuickLink.swift in Sources */, 1DA3CE5D24EEE73100422BB2 /* OpenTabsWidget.swift in Sources */, ); @@ -13550,21 +14631,29 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 122935A22CE79A9400EC1297 /* EcosiaInstallType.swift in Sources */, - 122935B02CE79DB100EC1297 /* NewsletterCardExperiment.swift in Sources */, - 122935A72CE79B0400EC1297 /* Version.swift in Sources */, - 122935A82CE79B0800EC1297 /* Version+Extensions.swift in Sources */, - 1229359E2CE79A2600EC1297 /* Analytics.swift in Sources */, - 122935AC2CE79DA200EC1297 /* BrazeIntegrationExperiment.swift in Sources */, - 122935AE2CE79DA900EC1297 /* APNConsentOnLaunchExperiment.swift in Sources */, - 122935AF2CE79DAD00EC1297 /* OnboardingRemoveExperiment.swift in Sources */, - 122935A52CE79AF400EC1297 /* DefaultAppVersionInfoProvider.swift in Sources */, - 1229359F2CE79A2800EC1297 /* Analytics+Configuration.swift in Sources */, - 1229359C2CE7927900EC1297 /* BrazeService.swift in Sources */, - 122935A62CE79AF800EC1297 /* AppVersionInfoProvider.swift in Sources */, - 122935A02CE79A3100EC1297 /* Analytics.Values.swift in Sources */, - 122935A42CE79A9A00EC1297 /* EcosiaInstallType+Extensions.swift in Sources */, - 122935AB2CE79D6F00EC1297 /* AppInfo+Ecosia.swift in Sources */, + 2CD264FF2CFDC76A00A040A7 /* FakeNimbus.swift in Sources */, + 2CD264AD2CFDC76A00A040A7 /* MMP.swift in Sources */, + 2CD2648A2CFDC76A00A040A7 /* BrazeService.swift in Sources */, + 2CD264AC2CFDC76A00A040A7 /* FeatureManagement.swift in Sources */, + 2CD264A02CFDC76A00A040A7 /* Version+Extensions.swift in Sources */, + 2CD2663E2CFF4ED000A040A7 /* DeviceInfo+Ecosia.swift in Sources */, + 2CD266322CFE403800A040A7 /* APNConsentOnLaunchExperiment.swift in Sources */, + 2CD264A12CFDC76A00A040A7 /* Analytics.swift in Sources */, + 2CD2649C2CFDC76A00A040A7 /* DefaultAppVersionInfoProvider.swift in Sources */, + 2CD2649A2CFDC76A00A040A7 /* String.swift in Sources */, + 2CD2663C2CFE423D00A040A7 /* AppInfo+Ecosia.swift in Sources */, + 2CD266352CFE403800A040A7 /* OnboardingRemoveExperiment.swift in Sources */, + 2CD265012CFDC76A00A040A7 /* FakeTelemetry.swift in Sources */, + 2CD2649B2CFDC76A00A040A7 /* AppVersionInfoProvider.swift in Sources */, + 2CD266332CFE403800A040A7 /* BrazeIntegrationExperiment.swift in Sources */, + 2CD264A52CFDC76A00A040A7 /* EcosiaLaunchScreenView.swift in Sources */, + 2CD2649F2CFDC76A00A040A7 /* Version.swift in Sources */, + 2CD264A32CFDC76A00A040A7 /* Analytics+Configuration.swift in Sources */, + 2CD2649D2CFDC76A00A040A7 /* EcosiaInstallType.swift in Sources */, + 2CD266342CFE403800A040A7 /* NewsletterCardExperiment.swift in Sources */, + 2CD265002CFDC76A00A040A7 /* FakeSentry.swift in Sources */, + 2CD2649E2CFDC76A00A040A7 /* EcosiaInstallType+Extensions.swift in Sources */, + 2CD264A22CFDC76A00A040A7 /* Analytics.Values.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -13572,7 +14661,34 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2CD263A92CFDC5EB00A040A7 /* LocaleRetriever.swift in Sources */, + 2CD263BF2CFDC5EB00A040A7 /* AnalyticsSpyTests.swift in Sources */, + 2CD263C02CFDC5EB00A040A7 /* AnalyticsTests.swift in Sources */, + 2CD263A52CFDC5EB00A040A7 /* OnboardingTests.swift in Sources */, + 2CD263AC2CFDC5EB00A040A7 /* SnapshotBaseTests.swift in Sources */, + 2CD263B32CFDC5EB00A040A7 /* AppDelegateFeatureManagementIntegrationTests.swift in Sources */, 1229358D2CE78D5D00EC1297 /* BrazeServiceTests.swift in Sources */, + 2CD263AE2CFDC5EB00A040A7 /* String+Extension.swift in Sources */, + 2CD262AA2CFDC5EB00A040A7 /* Welcome.swift in Sources */, + 2CD263B52CFDC5EB00A040A7 /* EcosiaPerformanceTestHistory.swift in Sources */, + 2CD263B72CFDC5EB00A040A7 /* PrivateModeButtonTests.swift in Sources */, + 2CD263BE2CFDC5EB00A040A7 /* EcosiaPageActionMenuCellTests.swift in Sources */, + 2CD263B62CFDC5EB00A040A7 /* MockAppVersionInfoProvider.swift in Sources */, + 2CD263B42CFDC5EB00A040A7 /* EcosiaInstallTypeTests.swift in Sources */, + 2CD263AF2CFDC5EB00A040A7 /* VersionTests.swift in Sources */, + 2CD263BD2CFDC5EB00A040A7 /* EcosiaOverlayModeManagerTests.swift in Sources */, + 2CD263BB2CFDC5EB00A040A7 /* UserDefaultsSeedProgressManagerTests.swift in Sources */, + 2CD263B22CFDC5EB00A040A7 /* WhatsNewLocalDataProviderTests.swift in Sources */, + 2CD263A62CFDC5EB00A040A7 /* DeviceType.swift in Sources */, + 2CD263AA2CFDC5EB00A040A7 /* LocalizationOverrideTestingBundle.swift in Sources */, + 2CD263B82CFDC5EB00A040A7 /* EcosiaNTPTooltipHighlightTests.swift in Sources */, + 2CD262DB2CFDC5EB00A040A7 /* NTPComponentTests.swift in Sources */, + 2CD262DC2CFDC5EB00A040A7 /* NTPTests.swift in Sources */, + 2CD263B92CFDC5EB00A040A7 /* EcosiaHomeViewModelTests.swift in Sources */, + 2CD263BC2CFDC5EB00A040A7 /* EcosiaTopSitesHelperTests.swift in Sources */, + 2CD263BA2CFDC5EB00A040A7 /* UnleashUserDefaultsSeedProgressManagerTests.swift in Sources */, + 2CD263AD2CFDC5EB00A040A7 /* SnapshotTestHelper.swift in Sources */, + 2CD262A92CFDC5EB00A040A7 /* EcosiaMockThemeManager.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -13660,22 +14776,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2C69DA752C62185A00D7F69F /* Welcome.swift in Sources */, 2C69DA7D2C6244BE00D7F69F /* MockTabDataStore.swift in Sources */, - 2C69DA922C63A92D00D7F69F /* SnapshotBaseTests.swift in Sources */, - 2C6C90902C614A76007D9B43 /* OnboardingTests.swift in Sources */, - 2C69DA942C63B0C000D7F69F /* String+Extension.swift in Sources */, - 2C82625E2C66661700E2A255 /* EcosiaMockThemeManager.swift in Sources */, - 2C69DA772C62243300D7F69F /* NTPTests.swift in Sources */, 2C69DA782C62259D00D7F69F /* MockProfile.swift in Sources */, - 2C5B81C82C75388300B81D95 /* LocaleRetriever.swift in Sources */, - 2C82625A2C64BB9300E2A255 /* DeviceType.swift in Sources */, 2C69DA792C6225AE00D7F69F /* DependencyHelperMock.swift in Sources */, - 2C69DA842C62B44B00D7F69F /* NTPComponentTests.swift in Sources */, - 2C82625C2C6648D900E2A255 /* LocalizationOverrideTestingBundle.swift in Sources */, 2C69DA7C2C6225DB00D7F69F /* MockOverlayModeManager.swift in Sources */, 2C69DA7E2C6244C400D7F69F /* MockThemeManager.swift in Sources */, - 2C69DA722C62175400D7F69F /* SnapshotTestHelper.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -13838,6 +14943,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2CD265EE2CFE382C00A040A7 /* NTPTooltipDelegate.swift in Sources */, 45D5EDD2292D89A200311934 /* PinnedSite.swift in Sources */, 8A4AC0EC28C929D700439F83 /* URLSessionProtocol.swift in Sources */, C2A72A672A76938C002ACCE2 /* DownloadsCoordinator.swift in Sources */, @@ -13845,8 +14951,8 @@ E1CD81C5290C6D5800124B27 /* HelpView.swift in Sources */, 5A47CFF52860FB8900B2B7BF /* AppLaunchUtil.swift in Sources */, D04CD74A216CF86B004FF5B0 /* SiriShortcuts.swift in Sources */, + 2CD265E82CFE382C00A040A7 /* NTPConfigurableNudgeCardCellViewModel.swift in Sources */, EB9A179F20E6C1A200B12184 /* ThemedTableViewController.swift in Sources */, - 2C6189482B7A8A22006B70D7 /* NTPLayout.swift in Sources */, E68E39BE1C46F42000B85F42 /* AppSettingsTableViewController.swift in Sources */, E1A6AB4628CA6A4C00EBEBDD /* String+Extension.swift in Sources */, 1D2F68AF2ACB272500524B92 /* RemoteTabsTableViewController.swift in Sources */, @@ -13856,14 +14962,13 @@ F85C7F0F271DD154004BDBA4 /* AppAuthenticator.swift in Sources */, D029A04920A62DB0001DB72F /* TemporaryDocument.swift in Sources */, C8BA0E7627F20B8E00DD8214 /* HistoryDeletionUtility.swift in Sources */, - 2C61894D2B7A8A22006B70D7 /* NTPLibraryShortcutView.swift in Sources */, 8A93F86D29D3A131004159D9 /* DefaultRouter.swift in Sources */, 5AB4237E28A2BA9C003BC40C /* HistoryHighlightsDataAdaptor.swift in Sources */, 8ADAE4262A33A13B007BF926 /* OpenSupportPageSetting.swift in Sources */, 8A590C6128C123100032F1AA /* OpenPassBookHelper.swift in Sources */, EBB895332193FFF400EB91A0 /* ContentBlockerSettingViewController.swift in Sources */, - 2CCBB5372CAF0E8C006E2E10 /* SeedCounterHiddenSettings.swift in Sources */, 8A5D1CB42A30D7D9005AD35C /* NoImageModeSetting.swift in Sources */, + 2CD266012CFE382C00A040A7 /* WhatsNewItem.swift in Sources */, 8A3EF8152A2FD08800796E3A /* OpenFiftyTabsDebugOption.swift in Sources */, D38F02D11C05127100175932 /* Authenticator.swift in Sources */, CAA3B7E62497DCB60094E3C1 /* LoginDataSource.swift in Sources */, @@ -13875,41 +14980,37 @@ 396E38F11EE0C8EC00CC180F /* FxAPushMessageHandler.swift in Sources */, 8A76B01629F6EB3900A82607 /* ScreenshotService.swift in Sources */, E4CD9F6D1A77DD2800318571 /* ReaderModeStyleViewController.swift in Sources */, - 2C6189622B7A8A22006B70D7 /* NTPAboutEcosiaCell.swift in Sources */, E13E9AB52AAB0FB5001A0E9D /* FakespotViewModel.swift in Sources */, - 2C61894B2B7A8A22006B70D7 /* NTPCustomizationCell.swift in Sources */, 8A5D1CBD2A30DC4E005AD35C /* AccountStatusSetting.swift in Sources */, E1CD81BC290C5C3F00124B27 /* DevicePickerTableViewCell.swift in Sources */, 1DDE3DB72AC3820A0039363B /* TabModel.swift in Sources */, 8A19ACB02A329078001C2147 /* AutofillCreditCardSettings.swift in Sources */, - 2C61895D2B7A8A22006B70D7 /* NTPImpactRowView.swift in Sources */, E1E5BE252A28F7BE00248F77 /* PasswordDetailViewControllerModel.swift in Sources */, E1FE133129C22726002A65FF /* BackgroundFetchAndProcessingUtility.swift in Sources */, + 2CD265D52CFE382C00A040A7 /* CustomizableNTPSettingConfig.swift in Sources */, 8AD40FD527BB1C1000672675 /* LockButton.swift in Sources */, 5F130D2E2483508E00B0F7D0 /* FxAWebViewModel.swift in Sources */, 2109478928AFD24C00B73D44 /* OnboardingViewControllerProtocol.swift in Sources */, D0FCF7F51FE45842004A7995 /* UserScriptManager.swift in Sources */, 8AB8573027D94CAD0075C173 /* HomepageViewModelProtocol.swift in Sources */, - 2C6189692B7A8A22006B70D7 /* MarketsController.swift in Sources */, + 2CD265CA2CFE382C00A040A7 /* SeedCounter.xcdatamodeld in Sources */, 5A9F83422B2B796800272819 /* TabPeekState.swift in Sources */, 21E77E522AA8BE5C00FABA10 /* TabTrayFlagManager.swift in Sources */, CA8226F324C11DB7008A6F38 /* PasswordManagerTableViewCell.swift in Sources */, 8A0A1BA02B2200FD00E8706F /* PrivateHomepageViewController.swift in Sources */, E4A960061ABB9C450069AD6F /* ReaderModeUtils.swift in Sources */, - 2C61896A2B7A8A22006B70D7 /* EmptyBookmarksView.swift in Sources */, 8AD40FCB27BADC4B00672675 /* StatefulButton.swift in Sources */, C84655E62887398700861B4A /* WallpaperCollection.swift in Sources */, EBF47E701F7979DF00899189 /* TelemetryWrapper.swift in Sources */, - 2C6189502B7A8A22006B70D7 /* NTPTooltip.swift in Sources */, 8AD40FCF27BADC6B00672675 /* URLTextField.swift in Sources */, - 2C6189762B7A8A22006B70D7 /* EcosiaDebugSettings.swift in Sources */, + 2CD265EB2CFE382C00A040A7 /* NTPLayout.swift in Sources */, 31ADB5DA1E58CEC300E87909 /* ClipboardBarDisplayHandler.swift in Sources */, 8AD1980F27BEB3F100D64B0E /* PhotonActionSheetViewModel.swift in Sources */, EB9A179D20E69A7F00B12184 /* LegacyTheme.swift in Sources */, 2128E2802934FBB400FB91BE /* CopyLinkActivity.swift in Sources */, E17BE4C42A94BA6900C5124E /* FakespotHighlightGroupView.swift in Sources */, C825E9832832A425006CB811 /* NimbusSearchBarLayer.swift in Sources */, - 2C6B5B3F2CAAF28000F15323 /* NTPSeedCounterViewModel.swift in Sources */, + 2CD265C72CFE382C00A040A7 /* AboutEcosiaSection.swift in Sources */, E1FC23F12A8629380089E14D /* FakespotReliabilityCardView.swift in Sources */, C8DC90C92A0675E70008832B /* MarkupParsingUtility.swift in Sources */, CA03B26A247F1D9E00382B62 /* BreachAlertsClient.swift in Sources */, @@ -13921,7 +15022,9 @@ DFFC9AD12A681FA0002A6AAD /* NimbusFakespotFeatureLayer.swift in Sources */, 1DEBC55E2AC4ED70006E4801 /* RemoteTabsPanel.swift in Sources */, 435D660523D794B90046EFA2 /* UpdateViewModel.swift in Sources */, + 2CD265FE2CFE382C00A040A7 /* WhatsNewDataProvider.swift in Sources */, 9658143C29FAB610007339BD /* CreditCardInputFieldHelper.swift in Sources */, + 2CD265F42CFE382C00A040A7 /* WelcomeTourGreen.swift in Sources */, 5A9F83442B2B8CE900272819 /* TabPeekModel.swift in Sources */, 810FF3542B178343009F062C /* FeltPrivacyMiddleware.swift in Sources */, 215B457F27D7FD4B00E5E800 /* LegacyTabGroupData.swift in Sources */, @@ -13931,9 +15034,7 @@ D0152245229855A8009DE753 /* OneLineTableViewCell.swift in Sources */, F018F84C2719AE8300B9A52D /* ThemedDefaultNavigationController.swift in Sources */, 602B3D6729B0E1DB0066DEF8 /* ConversionValueUtil.swift in Sources */, - 2C61894C2B7A8A22006B70D7 /* NTPCustomizationCellViewModel.swift in Sources */, 8ADED7EE276A7750009C19E6 /* CumulativeDaysOfUseCounter.swift in Sources */, - 2C6189352B7A8A22006B70D7 /* PageActionMenuCell.swift in Sources */, 4346FF08295BA6A300F4D220 /* CreditCardSettingsViewController.swift in Sources */, E19B38B528A42EBC00D8C541 /* WallpaperCellViewModel.swift in Sources */, C80E1A102A0943640025B9E1 /* UIFont+Extension.swift in Sources */, @@ -13941,48 +15042,47 @@ C23889DF2A4EFCE500429673 /* ShareExtensionCoordinator.swift in Sources */, 8C6F94652A972EB300415FF6 /* FakespotAdjustRatingView.swift in Sources */, 8A3EF7FD2A2FCFAC00796E3A /* AppReviewPromptSetting.swift in Sources */, - 2C6189602B7A8A22006B70D7 /* AboutEcosiaSection.swift in Sources */, D3B6923F1B9F9A58004B87A4 /* FindInPageHelper.swift in Sources */, E1FE133329C22782002A65FF /* BackgroundNotificationSurfaceUtility.swift in Sources */, + 2CD2662B2CFE402000A040A7 /* SeedCounterNTPExperiment.swift in Sources */, 8A395552299AF83400B2AFBB /* UIControl+Extension.swift in Sources */, C2A72A692A769460002ACCE2 /* ReadingListCoordinator.swift in Sources */, F85C7F122721048E004BDBA4 /* Layout.swift in Sources */, DF036E43274FD434002E834E /* HistoryHighlightsCell.swift in Sources */, - 2C6189392B7A8A22006B70D7 /* EcosiaFindInPageBar.swift in Sources */, EB9A179C20E69A7F00B12184 /* LegacyDarkTheme.swift in Sources */, 21618A8A2A4389F700A5189E /* ActiveScreenState.swift in Sources */, + 2CD265D42CFE382C00A040A7 /* Sparkle.swift in Sources */, DA52E1DA25F5961F0092204C /* LegacyTabTrayViewController.swift in Sources */, + 2CD2655A2CFDCF0900A040A7 /* NumberFormatter+Ecosia.swift in Sources */, 8AD40FD327BB068F00672675 /* MainMenuActionHelper.swift in Sources */, EB1C84BF212EFFBF001489DF /* BrowserViewController+ReaderMode.swift in Sources */, 96D95016270238500079D39D /* Throttler.swift in Sources */, 8A93080B27C01AD60052167D /* SingleActionViewModel.swift in Sources */, 219914052AF963F900153598 /* TabTrayAction.swift in Sources */, 5AA0CC662A4B8F6100014E2A /* PasswordManagerCoordinator.swift in Sources */, + 2CD265C92CFE382C00A040A7 /* NTPAboutEcosiaCellViewModel.swift in Sources */, 8A7368AD27924AAF005D7704 /* CanRemoveQuickActionBookmark.swift in Sources */, C2296FCC2A601C190046ECA6 /* IntensityVisualEffectView.swift in Sources */, 8ADC2A102A33758E00543DAA /* FxALaunchParams.swift in Sources */, - 2C6189572B7A8A22006B70D7 /* NTPNewsCell.swift in Sources */, D3C3696E1CC6B78800348A61 /* LocalRequestHelper.swift in Sources */, E17496382991A2720096900A /* AdaptiveStack.swift in Sources */, + 2CD265522CFDCF0900A040A7 /* AppSettingsTableViewController+Ecosia.swift in Sources */, E4B423DD1ABA0318007E66C8 /* ReaderModeHandlers.swift in Sources */, F8A0B08229AD61FA0091C75B /* RustSyncManager.swift in Sources */, D308E4E41A5306F500842685 /* SearchEngines.swift in Sources */, - 2C6189922B7A8A22006B70D7 /* BrowserCoordinator+Ecosia.swift in Sources */, 438FE8642988ABA600155B10 /* CreditCardTableViewController.swift in Sources */, - 2C6189702B7A8A22006B70D7 /* WelcomeTourTransparent.swift in Sources */, 3BCE6D3C1CEB9E4D0080928C /* ThirdPartySearchAlerts.swift in Sources */, - 2C61895A2B7A8A22006B70D7 /* ProgressView.swift in Sources */, 8A93F86229D36F0F004159D9 /* NavigationController.swift in Sources */, + 2CD265E32CFE382C00A040A7 /* NTPNewsCell.swift in Sources */, E13F8C342928194800BDC8B4 /* PhotonActionSheetSiteHeaderView.swift in Sources */, C2D71B9B2A3850B4003DEC7A /* ThemedTableViewCellViewModel.swift in Sources */, C869912F28917688007ACC5C /* WallpaperMetadataLoader.swift in Sources */, - 2C6189372B7A8A22006B70D7 /* PageActionMenu.swift in Sources */, 2137785D297F1F2800D01309 /* DownloadedFile.swift in Sources */, 745DAB301CDAAFAA00D44181 /* RecentlyClosedTabsPanel.swift in Sources */, D0B9483D22A18B78002F4AA1 /* TextFieldTableViewCell.swift in Sources */, 8AF99B4F29EF1BA700108DEC /* BrowserDelegate.swift in Sources */, C87D8B802818333F00A6307D /* NimbusManager.swift in Sources */, - 2C6189582B7A8A22006B70D7 /* NTPLogoCell.swift in Sources */, + 2CD2655E2CFDCF0900A040A7 /* UIFont+Ecosia.swift in Sources */, 8A4AC0EB28C929D700439F83 /* URLSessionDataTaskProtocol.swift in Sources */, C45F44691D087DB600CB7EF0 /* TopTabsViewController.swift in Sources */, 8ADC2A212A3399DC00543DAA /* YourRightsSetting.swift in Sources */, @@ -13994,9 +15094,11 @@ D01017F5219CB6BD009CBB5A /* DownloadContentScript.swift in Sources */, 8A093D832A4B68940099ABA5 /* PrivacySettingsDelegate.swift in Sources */, 39F819C61FD70F5D009E31E4 /* TabEventHandlers.swift in Sources */, + 2CD265CF2CFE382C00A040A7 /* NTPSeedCounterViewModel.swift in Sources */, C8DC90C32A066B4A0008832B /* MarkupToken.swift in Sources */, FA6B2AC21D41F02D00429414 /* String+Punycode.swift in Sources */, E174963C2992B6A60096900A /* HostingTableViewSectionHeader.swift in Sources */, + 2CD265602CFDCF0900A040A7 /* URL+Ecosia.swift in Sources */, 8A471185287F6E4800F5A6EA /* SeparatorTableViewCell.swift in Sources */, D301AAEE1A3A55B70078DD1D /* LegacyGridTabViewController.swift in Sources */, EB9A179B20E69A7F00B12184 /* LegacyThemeManager.swift in Sources */, @@ -14010,15 +15112,14 @@ D3BE7B461B054F8600641031 /* UITestAppDelegate.swift in Sources */, C8DC90C72A06759E0008832B /* MarkupAttributionUtility.swift in Sources */, 219A0FD52ACC8506009A6D1A /* InactiveTabsCell.swift in Sources */, - 2C6189422B7A8A22006B70D7 /* WhatsNewCell.swift in Sources */, 23D57E6E25ED6F2700883FAD /* SearchViewController.swift in Sources */, - 2C6189342B7A8A22006B70D7 /* SemanticColor.swift in Sources */, + 2CD265FB2CFE382C00A040A7 /* EcosiaTheme.swift in Sources */, C82A94F2269F68ED00624AA7 /* LegacyFeatureFlagsManager.swift in Sources */, C8610DAA2A0EBF7100B79FF1 /* OnboardingCardDelegate.swift in Sources */, E127313D28B6AD99006F39D2 /* WallpaperSettingsViewModel.swift in Sources */, 8A07910F278F62F2005529CB /* AdjustHelper.swift in Sources */, - 2C6189802B7A8A22006B70D7 /* EcosiaTopSiteItemCell.swift in Sources */, - 2C6189952B7A8A22006B70D7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift in Sources */, + 2CD266232CFE3ADA00A040A7 /* BookmarksExchange.swift in Sources */, + 2CD265E52CFE382C00A040A7 /* NTPNewsletterCardCell.swift in Sources */, E1442FC2294782C3003680B0 /* NSAttributedString+Extension.swift in Sources */, 967A028E28FA026F003C35E3 /* SceneDelegate.swift in Sources */, 810FF3562B1783B0009F062C /* FeltPrivacyManager.swift in Sources */, @@ -14031,10 +15132,8 @@ C88E7A602A05551B0072E638 /* NimbusOnboardingFeatureLayerProtocol.swift in Sources */, 8CFD56882AAF057D003157A6 /* SwitchFakespotProduction.swift in Sources */, C40046FA1CF8E0B200B08303 /* BackForwardListAnimator.swift in Sources */, + 2CD265DF2CFE382C00A040A7 /* NTPLibraryCell.swift in Sources */, DD31E0FB1B382B520077078A /* TabPrintPageRenderer.swift in Sources */, - 2C6189732B7A8A22006B70D7 /* WelcomeTourProfit.swift in Sources */, - 2C6189412B7A8A22006B70D7 /* EmptyHeader.swift in Sources */, - 2C61896F2B7A8A22006B70D7 /* WelcomeTour.swift in Sources */, D81E45131F82C56D004EFFBA /* NewTabContentSettingsViewController.swift in Sources */, E4CD9E911A6897FB00318571 /* ReaderMode.swift in Sources */, 96A562A327D7B32A0045144A /* Contile.swift in Sources */, @@ -14048,25 +15147,25 @@ C8B41E0A29F0284B00FE218A /* NimbusOnboardingFeatureLayer.swift in Sources */, BD4B2DE229BB4CD9005FAA50 /* SnackButton.swift in Sources */, F85C7F0E2711C556004BDBA4 /* SettingsViewController.swift in Sources */, - 2C6189362B7A8A22006B70D7 /* PageActionsShortcutsHeader.swift in Sources */, - 2C6B5B3E2CAAF28000F15323 /* NTPSeedCounterCell.swift in Sources */, C8B509E3293FA39900AC013C /* AppVersionUpdateCheckerProtocol.swift in Sources */, E1AFBAF9292EA0330065E35E /* SendToDeviceHelper.swift in Sources */, + 2CD2655D2CFDCF0900A040A7 /* UIButton+Ecosia.swift in Sources */, 21D151262AFC28960062D891 /* TabManagerMiddleware.swift in Sources */, 74C027451B2A348C001B1E88 /* LegacySessionData.swift in Sources */, + 2CD265F82CFE382C00A040A7 /* PageActionMenu.swift in Sources */, C84266752728462900382274 /* AccessibilityIdentifiers.swift in Sources */, C8BD87622A0C257C00CD803A /* OnboardingCardInfoModelProtocol.swift in Sources */, DA27EEDB28BADF4700DD6F5D /* MenuBuilderHelper.swift in Sources */, E16AD22C2A8A7AE800F0AA58 /* FakespotHighlightsCardView.swift in Sources */, B2999FF12B194A5800F0FEC1 /* CreditCardPayload.swift in Sources */, + 2CD265622CFDCF6D00A040A7 /* UIImage+Ecosia.swift in Sources */, E1877A81286E0EFD00F5BDF2 /* WebViewNavigationHandler.swift in Sources */, 274A36CC239EB99400A21587 /* LibraryPanelContextMenu.swift in Sources */, D314E7F71A37B98700426A76 /* TabToolbar.swift in Sources */, 43D00493296FC48F00CB0F31 /* CreditCardSettingsEmptyView.swift in Sources */, - 2C61896D2B7A8A22006B70D7 /* WelcomeTour.Step.swift in Sources */, - 2CCBB5252CAEA9DF006E2E10 /* SeedProgressView.swift in Sources */, CEFA977E1FAA6B490016F365 /* SyncContentSettingsViewController.swift in Sources */, C8CD80DC2A1E8C970097C3AE /* OnboardingTelemetryUtility.swift in Sources */, + 2CD2661D2CFE38AD00A040A7 /* EcosiaSettings.swift in Sources */, 96C11E9B2864C2DD00840E7C /* DependencyHelper.swift in Sources */, F18859502A3E454E0004AA7B /* EnhancedTrackingProtectionCoordinator.swift in Sources */, 21618A8C2A438A0900A5189E /* ActiveScreenAction.swift in Sources */, @@ -14075,14 +15174,13 @@ 21E77E4E2AA8BA5200FABA10 /* TabTrayViewController.swift in Sources */, 43BDBBFE2752FA8600254DE4 /* LegacyTabCell.swift in Sources */, E60D03181D511398002FE3F6 /* SyncDisplayState.swift in Sources */, - 2C4ABD492CB58E4F00FF86F9 /* Sparkle.swift in Sources */, C4E3983D1D21F1E7004E89BA /* TopTabCell.swift in Sources */, - 2C61898C2B7A8A22006B70D7 /* HomepageViewController+Ecosia.swift in Sources */, 210E0EBA298D9D6400BB4F33 /* OpenSearchEngine.swift in Sources */, FA9293D41D6580E100AC8D33 /* QRCodeViewController.swift in Sources */, 5A679E4B2B239FAE004F2B0D /* TabPeekViewController.swift in Sources */, 2178A6A0291454B5002EC290 /* ReaderModeThemeButton.swift in Sources */, 39F4C10A2045DB2E00746155 /* FocusHelper.swift in Sources */, + 2CD265E92CFE382C00A040A7 /* CircleButton.swift in Sources */, E4CD9F2D1A6DC91200318571 /* TabLocationView.swift in Sources */, 81CAE4DB2B1A2C220040C78A /* BrowserViewControllerState.swift in Sources */, C8BD87602A0C248000CD803A /* OnboardingButtonsModel.swift in Sources */, @@ -14091,9 +15189,7 @@ 8AB8572C27D945FA0075C173 /* TopSitesDataAdaptor.swift in Sources */, EBC4869F2195F58300CDA48D /* SessionRestoreHandler.swift in Sources */, C889569A27E8D1AC00E3779E /* LegacyInactiveTabHeader.swift in Sources */, - 2C6189862B7A8A22006B70D7 /* BrowserViewController+Ecosia.swift in Sources */, 7BEFC6801BFF68C30059C952 /* QuickActions.swift in Sources */, - 2C6189932B7A8A22006B70D7 /* AppSettingsTableViewController+Ecosia.swift in Sources */, 8A3EF8132A2FD07A00796E3A /* ResetContextualHints.swift in Sources */, D0C95E36200FDC5500E4E51C /* MetadataParserHelper.swift in Sources */, 0BF1B7E31AC60DEA00A7B407 /* InsetButton.swift in Sources */, @@ -14121,8 +15217,8 @@ C87DF9DB267247190097E707 /* UIConstants+BottomInset.swift in Sources */, 8AD08D1527E9198E00B8E907 /* TabsQuantityTelemetry.swift in Sources */, 74B420C92A1D0D7A00370E53 /* OnboardingInstructionsPopupInfoModel.swift in Sources */, - 2C61898B2B7A8A22006B70D7 /* SnapKit+Ecosia.swift in Sources */, E13E9AB32AAB0FB5001A0E9D /* FakespotViewController.swift in Sources */, + 2CD265DA2CFE382C00A040A7 /* NTPImpactCellViewModel.swift in Sources */, E15DE7C4293A7B0F00B32667 /* PhotonActionSheetTitleHeaderView.swift in Sources */, 392ED7E61D0AEFEF009D9B62 /* HomePageAccessors.swift in Sources */, 8A0017C128A3FF6100FEFC8B /* MessageCardDataAdaptor.swift in Sources */, @@ -14131,6 +15227,7 @@ 8A5D1CA42A30D69A005AD35C /* SearchSetting.swift in Sources */, 74BBDF472A17979000D3BEFE /* OnboardingDefaultBrowserModelProtocol.swift in Sources */, 8AD40FC727BADC3400672675 /* ToolbarTextField.swift in Sources */, + 2CD266092CFE382C00A040A7 /* EmptyBookmarksViewDelegate.swift in Sources */, 8A720C5E2A4C85DA0003018A /* AccountSettingsDelegate.swift in Sources */, CA90753824929B22005B794D /* NoLoginsView.swift in Sources */, E4B423BE1AB9FE6A007E66C8 /* ReaderModeCache.swift in Sources */, @@ -14140,31 +15237,30 @@ EBB8950C21939E4100EB91A0 /* FirefoxTabContentBlocker.swift in Sources */, 21618A632A422A3900A5189E /* ThemeMiddleware.swift in Sources */, 219A0FDB2ACCCFFC009A6D1A /* InactiveTabsSectionManager.swift in Sources */, - 2CCBB5272CAEAD53006E2E10 /* SeedCounterView.swift in Sources */, 211F00AC27F4D918001D9189 /* HistoryPanel+Search.swift in Sources */, 96EB6C3827D821B800A9D159 /* HistoryPanelViewModel.swift in Sources */, + 2CD2655C2CFDCF0900A040A7 /* SnapKit+Ecosia.swift in Sources */, AB52ED3B2A0E8873001067F5 /* UserConversionMetrics.swift in Sources */, 219935EC2B07110900E5966F /* TabTrayModel.swift in Sources */, 8A3EF7F72A2FCF6D00796E3A /* ExportLogDataSetting.swift in Sources */, - 2C5A5E652CB53DB7005BFE8B /* SeedCounterConfig.swift in Sources */, 43E69EC3254D081D00B591C2 /* SimpleTab.swift in Sources */, 8ADAE4202A33A0FD007BF926 /* SendFeedbackSetting.swift in Sources */, C29B64812AD6959E00F3244B /* QRCodeCoordinator.swift in Sources */, - 2C6189442B7A8A22006B70D7 /* WhatsNewViewController.swift in Sources */, 21A7C45028353D0E0071D996 /* OnboardingCardViewController.swift in Sources */, 742A56391D80B54A00BDB803 /* PhotonActionSheet.swift in Sources */, C4EFEECF1CEBB6F2009762A4 /* BackForwardTableViewCell.swift in Sources */, + 2CD265DB2CFE382C00A040A7 /* NTPImpactDividerFooter.swift in Sources */, E1442FD3294782D9003680B0 /* UIView+Constraints.swift in Sources */, 2C0360DA2C1747E6006706F2 /* FxNimbus.swift in Sources */, 5A70EF21295E3E0B00790249 /* UnitTestSceneDelegate.swift in Sources */, 2C49854E206173C800893DAE /* photon-colors.swift in Sources */, B2999FF72B194ADE00F0FEC1 /* FormAutofillPayloadType.swift in Sources */, 8A285B08294A5D4C00149B0F /* HomepageHeroImageViewModel.swift in Sources */, - 2C61897D2B7A8A22006B70D7 /* String.swift in Sources */, 8C92DE8B2A711ED60090BD28 /* FakespotClient.swift in Sources */, 8AC1065F28D0CD700013263A /* OpenQLPreviewHelper.swift in Sources */, EBA3B2C32268F16300728BDB /* PhotonActionSheetView.swift in Sources */, E18EA56F28AD3279003F97FC /* UIDevice+Extension.swift in Sources */, + 2CD266202CFE39E300A040A7 /* EcosiaPrimaryButton.swift in Sources */, CDB3BE8724746787009320EE /* FirefoxAccountSignInViewController.swift in Sources */, 8A471183287F6D9C00F5A6EA /* BookmarksPanelViewModel.swift in Sources */, E1FF93E428A2E74600E6360E /* WallpaperSelectorViewModel.swift in Sources */, @@ -14176,7 +15272,6 @@ 282DA4731A68C1E700A406E2 /* OpenSearchParser.swift in Sources */, 8A13FA8D2AD834FA007527AB /* BackgroundTabLoader.swift in Sources */, D04CD74B216CF86B004FF5B0 /* DevicePickerViewController.swift in Sources */, - 2C61896B2B7A8A22006B70D7 /* WelcomeTourRow.swift in Sources */, C8DC90BD2A06699E0008832B /* MarkupNode.swift in Sources */, E63ED8E11BFD25580097D08E /* PasswordManagerListViewController.swift in Sources */, 8ADC2A162A33765E00543DAA /* UrlToOpenModel.swift in Sources */, @@ -14194,44 +15289,40 @@ 4331A9BD271D267E005E8080 /* ContextualHintViewProvider.swift in Sources */, 8CAF29A02AA5E76B00DC3486 /* FakespotMessageCardView.swift in Sources */, 8A093D7F2A4B3E7D0099ABA5 /* GeneralSettingsDelegate.swift in Sources */, + 2CD2661C2CFE38AD00A040A7 /* EcosiaDebugSettings.swift in Sources */, D88FDAAF1F4E2BA000FD9709 /* PhotonActionSheetAnimator.swift in Sources */, C83432FE26BAD30D00ABAAA6 /* EnhancedTrackingProtectionDetailsVC.swift in Sources */, E698FFDA1B4AADF40001F623 /* TabScrollController.swift in Sources */, - 2C6189662B7A8A22006B70D7 /* EcosiaThemeColourPalette.swift in Sources */, 8A359EF32A1FD449004A5BB7 /* AdjustWrapper.swift in Sources */, D34510881ACF415700EC27F0 /* SearchLoader.swift in Sources */, - 2C61897E2B7A8A22006B70D7 /* FeatureManagement.swift in Sources */, E17496402994302D0096900A /* PreferredFont.swift in Sources */, E1442FD4294782D9003680B0 /* URL+Mail.swift in Sources */, 9636D92827F5D72D00771F5E /* GleanPlumbMessageManager.swift in Sources */, C80685D126A0C93900DCD895 /* UserResearch.swift in Sources */, B2999FF52B194AB200F0FEC1 /* FormAutofillHelperError.swift in Sources */, + 2CD2660F2CFE382C00A040A7 /* SemanticColor.swift in Sources */, + 2CD265572CFDCF0900A040A7 /* ErrorPageHandler+Ecosia.swift in Sources */, 8AED23C527AC1F9500DE7E97 /* BaseContentStackView.swift in Sources */, C8699131289176A5007ACC5C /* WallpaperNetworking.swift in Sources */, 5A271ABD2860B0D700471CE4 /* WebServerUtil.swift in Sources */, 964FA97528A1A8F20024BB3B /* ContextualHintEligibilityUtility.swift in Sources */, 439C489C29760575007C3DCD /* CreditCardValidator.swift in Sources */, 8ADC2A122A3375B900543DAA /* FxAEntryPoint.swift in Sources */, - 12147F312CDA3CD80009D300 /* NTPNewsletterCardViewModel.swift in Sources */, 216A0D7B2A40F08B008077BA /* ThemeSettingsAction.swift in Sources */, C2506C932A6A863600F2B76E /* HistoryCoordinator.swift in Sources */, 8A3EF8012A2FCFC900796E3A /* FasterInactiveTabs.swift in Sources */, CA7FC7D324A6A9B70012F347 /* PasswordManagerDataSourceHelper.swift in Sources */, 43AB6FA425DC53D30016B015 /* LabelButtonHeaderView.swift in Sources */, + 2CD265532CFDCF0900A040A7 /* BrowserCoordinator+Ecosia.swift in Sources */, 43D16B7C29831CD0009F8279 /* CreditCardItemRow.swift in Sources */, + 2CD265F92CFE382C00A040A7 /* PageActionMenuCell.swift in Sources */, 965C3C942933A860006499ED /* LaunchSessionProvider.swift in Sources */, - 2C6189382B7A8A22006B70D7 /* EmptyBookmarksViewDelegate.swift in Sources */, C8163851268A0899004C7160 /* AddCredentialViewController.swift in Sources */, - 2C61898E2B7A8A22006B70D7 /* UIView+maskedCorners.swift in Sources */, - 2C61895F2B7A8A22006B70D7 /* ClimateImpactInfo.swift in Sources */, - 2C6189612B7A8A22006B70D7 /* NTPAboutEcosiaCellViewModel.swift in Sources */, 8A19ACB22A3290AE001C2147 /* ClearPrivateDataSetting.swift in Sources */, CA520E7A24913C1B00CCAB48 /* PasswordManagerViewModel.swift in Sources */, - 2CA9952A2CA2C0BB001064CC /* NTPConfigurableNudgeCardCellViewModel.swift in Sources */, 8AE1E1CD27B191110024C45E /* SearchBarSettingsViewModel.swift in Sources */, 43D16B8529831EA5009F8279 /* Style.swift in Sources */, E16258EF2A83BE0800522742 /* FakespotLoadingView.swift in Sources */, - 2C61894A2B7A8A22006B70D7 /* CustomizableNTPSettingConfig.swift in Sources */, 8A19ACAB2A32895E001C2147 /* BrowserNavigationHandler.swift in Sources */, 8A01891C275E9C2A00923EFE /* ClearHistorySheetProvider.swift in Sources */, 8C44A9D22A6A99FE009A1AA7 /* ShoppingProduct.swift in Sources */, @@ -14243,19 +15334,26 @@ 8CBDE8E32AB09804001985BF /* ProductAnalyzeResponse.swift in Sources */, 96EB6C4327DC205D00A9D159 /* SearchGroupedItemsViewModel.swift in Sources */, 8A5BD95F2878B7B6000FE773 /* TopSitesWidgetManager.swift in Sources */, + 2CD265F52CFE382C00A040A7 /* WelcomeTourProfit.swift in Sources */, F84B22041A0910F600AAB793 /* AppDelegate.swift in Sources */, E1442FD2294782D9003680B0 /* UIViewController+Extension.swift in Sources */, E653422D1C5944F90039DD9E /* BrowserPrompts.swift in Sources */, + 2CD2660D2CFE382C00A040A7 /* LoadingScreen.swift in Sources */, E127313C28B6AD99006F39D2 /* WallpaperSettingsViewController.swift in Sources */, 43D4BCBA2972082400775FB5 /* CreditCardSettingsViewModel.swift in Sources */, 21583E422B1A3703009D084D /* LegacyInactiveTabModel.swift in Sources */, DF529EA12AB1B421003C5373 /* FakespotReliabilityScoreView.swift in Sources */, + 2CD265F32CFE382C00A040A7 /* WelcomeTourAction.swift in Sources */, 9636D92A27F767EC00771F5E /* NimbusMessagingEvaluationUtility.swift in Sources */, E127313F28B6C194006F39D2 /* WallpaperSettingsHeaderView.swift in Sources */, 2FDE87FE1ABB3817005317B1 /* LegacyRemoteTabsPanel.swift in Sources */, 8A3EF80F2A2FD05D00796E3A /* ToggleInactiveTabs.swift in Sources */, 435222C125882E3800FCA5B6 /* WidgetKitTopSiteModel.swift in Sources */, + 2CD265E62CFE382C00A040A7 /* NTPNewsletterCardViewModel.swift in Sources */, + 2CD265DE2CFE382C00A040A7 /* NTPLibaryCellViewModel.swift in Sources */, 96EB6C3E27D9266500A9D159 /* HistoryActionables.swift in Sources */, + 2CD265E02CFE382C00A040A7 /* NTPLibraryShortcutView.swift in Sources */, + 2CD2660C2CFE382C00A040A7 /* FilterController.swift in Sources */, 8C6F94662A972EB300415FF6 /* FakespotStarRatingView.swift in Sources */, C4F3B29A1CFCF93A00966259 /* ButtonToast.swift in Sources */, 1D7B78972ADF32590011E9F2 /* EventQueue.swift in Sources */, @@ -14266,70 +15364,69 @@ 8A57519927AD80B800A84DBF /* ReaderModeStyleViewModel.swift in Sources */, 435D7CC5246209AA0043ACB9 /* IntroViewController.swift in Sources */, C855728429AEA3C300AF32B0 /* SurveySurfaceViewModel.swift in Sources */, - 2C6189562B7A8A22006B70D7 /* NTPNewsCellViewModel.swift in Sources */, CA4ACE4924C8C91600F55894 /* BreachAlertsDetailView.swift in Sources */, C834ACD128D3ACA900203AD1 /* Blurrable.swift in Sources */, + 2CD265562CFDCF0900A040A7 /* DispatchQueueHelper+BuildChannel.swift in Sources */, C84655E22887388F00861B4A /* Wallpaper.swift in Sources */, C849E46326B9C3AF00260F0B /* EnhancedTrackingProtectionVM.swift in Sources */, 5A9F83402B2B4AE800272819 /* TabPeekAction.swift in Sources */, - 2C6189842B7A8A22006B70D7 /* WebsiteConnectionStatus.swift in Sources */, C8EDDBF429DF119F003A4C07 /* DeeplinkInput.swift in Sources */, D0E55C4F1FB4FD23006DC274 /* FormPostHelper.swift in Sources */, + 2CD265F12CFE382C00A040A7 /* WelcomeTour.Step.swift in Sources */, E118B9292862674E00C84831 /* LegacyInactiveTabItemCellModel.swift in Sources */, C88E7A552A0553180072E638 /* OnboardingViewModel.swift in Sources */, 8C29627C2B1F473800571655 /* AdEventsResponse.swift in Sources */, - 2C61898A2B7A8A22006B70D7 /* ErrorPageHandler+Ecosia.swift in Sources */, 962021E128B8078400BDF3D9 /* ContextualHintCopyProvider.swift in Sources */, - 2C6189672B7A8A22006B70D7 /* EcosiaTheme.swift in Sources */, 8AE1E1D227B1ADC40024C45E /* TopBottomInterchangeable.swift in Sources */, 8A093D7D2A4B3E4F0099ABA5 /* DebugSettingsDelegate.swift in Sources */, 96EA9454293655BF00123345 /* AppSession+Enums.swift in Sources */, C8B0F5F4283B7CCE007AE65D /* PocketProvider.swift in Sources */, - 2C6189642B7A8A22006B70D7 /* EcosiaNavigation.swift in Sources */, - 2CCBB5352CAF06DE006E2E10 /* SeedProgressManagerProtocol.swift in Sources */, 1DC372022B23C80F000F96C8 /* WindowManager.swift in Sources */, + 2CD265F22CFE382C00A040A7 /* WelcomeTour.swift in Sources */, C8E531C829E5EB6100E03FEF /* RouteBuilder.swift in Sources */, D3972BF41C22412B00035B87 /* TitleActivityItemProvider.swift in Sources */, D38A1BEE1A9FA2CA00F6A386 /* SiteTableViewController.swift in Sources */, 7BA0601B1C0F4DE200DFADB6 /* LegacyTabPeekViewController.swift in Sources */, - 2C6189652B7A8A22006B70D7 /* EcosiaThemeManager.swift in Sources */, 212985E42A6F078800546684 /* ScreenState.swift in Sources */, + 2CD2661E2CFE38AD00A040A7 /* NTPCustomizationSettingsViewController.swift in Sources */, D51EA5BA26406A0000334331 /* ExperimentsBranchesViewController.swift in Sources */, + 2CD265C62CFE382C00A040A7 /* MultiplyImpactStep.swift in Sources */, C84655F728879EF100861B4A /* WallpaperManager.swift in Sources */, 6669B5E2211418A200CA117B /* WebsiteDataSearchResultsViewController.swift in Sources */, - 2C6189722B7A8A22006B70D7 /* WelcomeNavigation.swift in Sources */, D51EA5CF26406D8300334331 /* ExperimentsViewController.swift in Sources */, + 2CD265C52CFE382C00A040A7 /* MultiplyImpact.swift in Sources */, 1DFE57FB27B2CB870025DE58 /* HighlightItem.swift in Sources */, CA77ABFD24773C92005079F9 /* BreachAlertsManager.swift in Sources */, 8AB8572727D93AEC0075C173 /* TopSiteHistoryManager.swift in Sources */, C81A8F2526D3ED1900EBA539 /* UIWindow+Extension.swift in Sources */, EBC4869E2195F58300CDA48D /* AboutHomeHandler.swift in Sources */, DDA24A431FD84D630098F159 /* DefaultSearchPrefs.swift in Sources */, - 2C9258DB2CEFB26500C6BB8D /* AnalyticsNotificationSettings.swift in Sources */, + 2CD265CE2CFE382C00A040A7 /* NTPSeedCounterCell.swift in Sources */, E65075611E37F77D006961AC /* MenuHelper.swift in Sources */, 8A7A26E529D4C0A800EA76F1 /* IntroScreenManager.swift in Sources */, 8AB8574827D97CD40075C173 /* HomePanelType.swift in Sources */, E174963A2992B42C0096900A /* CreditCardSectionHeader.swift in Sources */, - 2C61895C2B7A8A22006B70D7 /* NTPImpactCellViewModel.swift in Sources */, 8A3EF7F42A2FCF5700796E3A /* ExportBrowserDataSetting.swift in Sources */, 2128E27B292E624400FB91BE /* SendToDeviceActivity.swift in Sources */, E63ED7D81BFCD9990097D08E /* LoginDetailTableViewCell.swift in Sources */, C855728229AE7F1700AF32B0 /* SurveySurfaceManager.swift in Sources */, 66CE54A820FCF6CF00CC310B /* WebsiteDataManagementViewController.swift in Sources */, - 2C6189772B7A8A22006B70D7 /* EcosiaSettings.swift in Sources */, C8E2E80E23D20FD2005AACE6 /* FxAWebViewController.swift in Sources */, E14F7DF2288F3F9F00E3722C /* ThemedTableSectionHeaderFooterView.swift in Sources */, 8A3EF7F22A2FCF4000796E3A /* DeleteExportedDataSetting.swift in Sources */, 8ADC2A142A33762900543DAA /* ReferringPage.swift in Sources */, E1442FBF294782B6003680B0 /* CGRect+Extension.swift in Sources */, + 2CD265EA2CFE382C00A040A7 /* DefaultBrowser.swift in Sources */, 96F8DA49280452CA00E53239 /* GleanPlumbContextProvider.swift in Sources */, + 2CD265DD2CFE382C00A040A7 /* ProgressView.swift in Sources */, 43DB9784292D6846002E0B9F /* ShareButton.swift in Sources */, 8AB8574627D97CB00075C173 /* HomepageContextMenuProtocol.swift in Sources */, + 2CD265DC2CFE382C00A040A7 /* NTPImpactRowView.swift in Sources */, 3BB50E201D627539004B33DF /* HomepageViewController.swift in Sources */, C82A94F3269F68F300624AA7 /* CoreFlaggableFeature.swift in Sources */, - 2C6189742B7A8A22006B70D7 /* MultiplyImpact.swift in Sources */, F84B22241A09122500AAB793 /* LibraryViewController.swift in Sources */, 39455F771FC83F430088A22C /* TabEventHandler.swift in Sources */, + 2CD2660E2CFE382C00A040A7 /* MarketsController.swift in Sources */, 8A36BE2929EDBC6900AC1C5C /* ContentContainer.swift in Sources */, 215B458227DA420400E5E800 /* LegacyTabMetadataManager.swift in Sources */, E47616C71AB74CA600E7DD25 /* ReaderModeBarView.swift in Sources */, @@ -14339,9 +15436,13 @@ 5A3A2A0D287F742C00B79EAC /* BackgroundSyncUtility.swift in Sources */, 21AFCFEE2AE80B700027E9CE /* TabsCoordinator.swift in Sources */, 23ED80FF25C89C9800D0E9D5 /* DefaultBrowserOnboardingViewController.swift in Sources */, + 2CD266032CFE382C00A040A7 /* WhatsNewViewModel.swift in Sources */, + 2CD2660B2CFE382C00A040A7 /* EmptyReadingListView.swift in Sources */, + 2CD265EC2CFE382C00A040A7 /* NTPTooltip.Highlight.swift in Sources */, 8A3EF80D2A2FD04D00796E3A /* ResetWallpaperOnboardingPage.swift in Sources */, E1FE132F29C0B3CB002A65FF /* NotificationSurfaceManager.swift in Sources */, D88FDA9F1F4E2B9200FD9709 /* PhotonActionSheetProtocol.swift in Sources */, + 2CD265D72CFE382C00A040A7 /* NTPCustomizationCellViewModel.swift in Sources */, 21618A932A4499FC00A5189E /* AppState.swift in Sources */, BD1C89CA2A1E3CE7000A4201 /* PocketFooterView.swift in Sources */, E12BD0AE28AC38480029AAF0 /* UIImage+Extension.swift in Sources */, @@ -14352,16 +15453,15 @@ C8656D79270F866700E199EA /* CustomizeHomepageSectionCell.swift in Sources */, ABE4393E2AC432040074FFE1 /* PartnerWebsites.swift in Sources */, C84655FB28879FC600861B4A /* WallpaperStorageUtility.swift in Sources */, + 2CD265E12CFE382C00A040A7 /* NTPLogoCell.swift in Sources */, 8A13FA8B2AD82E6D007527AB /* ApplicationStateProvider.swift in Sources */, 4347B39A298DA5BB0045F677 /* CreditCardInputViewModel.swift in Sources */, 6025B10D267B6C5400F59F6B /* LoginRecordExtension.swift in Sources */, - 2C61893B2B7A8A22006B70D7 /* EmptyReadingListView.swift in Sources */, 2F44FCC51A9E85E900FD20CC /* SettingsTableViewController.swift in Sources */, - 2C6189752B7A8A22006B70D7 /* MultiplyImpactStep.swift in Sources */, 211046C92A7ADE9000A7309F /* BlockPopupSetting.swift in Sources */, 8A3233FC286270CF003E1C33 /* FxBookmarkNode.swift in Sources */, E1CEC2022A28C3F100B177D5 /* LoginDetailCenteredTableViewCell.swift in Sources */, - 2C61898D2B7A8A22006B70D7 /* SimpleToast+Ecosia.swift in Sources */, + 2CD265D12CFE382C00A040A7 /* SeedCounterHiddenSettings.swift in Sources */, C2D71B972A384F40003DEC7A /* ThemedSubtitleTableViewCell.swift in Sources */, 8A83B7462A264FA0002FF9AC /* SettingsCoordinator.swift in Sources */, A9072B801D07B34100459960 /* NoImageModeHelper.swift in Sources */, @@ -14369,24 +15469,21 @@ D8AA923421A602DC002605C0 /* HomePageSettingViewController.swift in Sources */, 8A161411282C035D00DDBB02 /* CustomizeHomepageSectionViewModel.swift in Sources */, C8DC90C52A066B6A0008832B /* MarkupTokenizingUtility.swift in Sources */, - 2C61895B2B7A8A22006B70D7 /* NTPImpactCell.swift in Sources */, - 2C6189522B7A8A22006B70D7 /* NTPTooltip.Highlight.swift in Sources */, EBC4869D2195F58300CDA48D /* ErrorPageHelper.swift in Sources */, C84655E8288739CB00861B4A /* WallpaperCollectionAvailability.swift in Sources */, C834330026BAD32800ABAAA6 /* EnhancedTrackingProtectionDetailsVM.swift in Sources */, + 2CD265E22CFE382C00A040A7 /* NewsController.swift in Sources */, + 2CD2661A2CFE38AD00A040A7 /* EcosiaTopSiteItemCell.swift in Sources */, 8A03309528C2653600286539 /* LegacyTabFileManager.swift in Sources */, 8AB5958A284145B30090F4AE /* HomepageSectionHandler.swift in Sources */, - 2C6189512B7A8A22006B70D7 /* CircleButton.swift in Sources */, E1442FD0294782D9003680B0 /* UIAlertController+Extension.swift in Sources */, 8A76B01429F6E45600A82607 /* CoordinatorFlagManager.swift in Sources */, E660BDD91BB06521009AC090 /* TabsButton.swift in Sources */, 8C92DE932A7128DE0090BD28 /* ProductAdsResponse.swift in Sources */, E1A6AB4828CA833000EBEBDD /* WallpaperBaseViewController.swift in Sources */, 4331A9BB27193DF0005E8080 /* ContextualHintViewController.swift in Sources */, - 2C6189882B7A8A22006B70D7 /* UIButton+Ecosia.swift in Sources */, 39EF434E260A73950011E22E /* Experiments.swift in Sources */, E15DE7C0293A670700B32667 /* PhotonActionSheetSeparator.swift in Sources */, - 2C6189452B7A8A22006B70D7 /* WhatsNewItem.swift in Sources */, DFEA639E279F468A00D489C3 /* DynamicHeightCollectionView.swift in Sources */, F8B7109E2ABE380B0029726E /* RustErrors.swift in Sources */, C8124BB129D6F55400540B79 /* Route.swift in Sources */, @@ -14397,6 +15494,8 @@ 8A7A26EA29D4C3C800EA76F1 /* LaunchType.swift in Sources */, D04D1B92209790B60074B35F /* Toast.swift in Sources */, 8A93F87429D3A5C1004159D9 /* LaunchCoordinator.swift in Sources */, + 2CD266022CFE382C00A040A7 /* WhatsNewViewController.swift in Sources */, + 2CD265CC2CFE382C00A040A7 /* UserDefaultsSeedProgressManager.swift in Sources */, 8AD5702F27AB4DEA005BFDC8 /* UIStackView+Extension.swift in Sources */, C2D71B952A384F11003DEC7A /* ThemedTableViewCell.swift in Sources */, 219A0FD72ACC8C03009A6D1A /* InactiveTabsHeaderView.swift in Sources */, @@ -14411,24 +15510,25 @@ 8A1E93EA2A3CDC6100DD540A /* BaseCoordinator.swift in Sources */, E1442FD6294782D9003680B0 /* UIView+Extension.swift in Sources */, 74F80D342A0A52D700013C3D /* PrivacyPolicyViewController.swift in Sources */, - 2C61894F2B7A8A22006B70D7 /* NTPLibaryCellViewModel.swift in Sources */, + 2CD265FC2CFE382C00A040A7 /* EcosiaThemeColourPalette.swift in Sources */, 274A36CE239EB9EC00A21587 /* LibraryViewController+LibraryPanelDelegate.swift in Sources */, C869912D28917688007ACC5C /* WallpaperImageLoader.swift in Sources */, 96A5F73829928B3700234E5F /* GeneralizedImageFetcher.swift in Sources */, 1D7B78992ADF328E0011E9F2 /* AppEvent.swift in Sources */, - 2C6189972B7A8A22006B70D7 /* ConnectionStatusImage.swift in Sources */, 43F7952525795F69005AEE40 /* SearchTelemetry.swift in Sources */, E65075541E37F6FC006961AC /* LegacyDynamicFontHelper.swift in Sources */, - 2CCBB5232CAE9826006E2E10 /* ArcProgressView.swift in Sources */, 8ADAE4242A33A126007BF926 /* StudiesToggleSetting.swift in Sources */, C82CDD47233E8996002E2743 /* Tab+ChangeUserAgent.swift in Sources */, 81122E212B221AC0003DD9F8 /* SearchScreenState.swift in Sources */, + 2CD265ED2CFE382C00A040A7 /* NTPTooltip.swift in Sources */, C4E3984C1D21F2FD004E89BA /* TabTrayButtonExtensions.swift in Sources */, 437A857827E43FE100E42764 /* FxAWebViewTelemetry.swift in Sources */, E13E9AB42AAB0FB5001A0E9D /* FakespotCoordinator.swift in Sources */, E1442FD1294782D9003680B0 /* UIModalPresentationStyle+Photon.swift in Sources */, E1ADE23E2B06559500FD17AA /* FakespotAction.swift in Sources */, 5A32C2B62AD8517200A9B5A4 /* MetricKitWrapper.swift in Sources */, + 2CD265D32CFE382C00A040A7 /* SeedProgressView.swift in Sources */, + 2CD266512CFF56CB00A040A7 /* ConnectionStatusImage.swift in Sources */, 8A95FF642B1E969E00AC303D /* TelemetryContextualIdentifier.swift in Sources */, D3FEC38D1AC4B42F00494F45 /* AutocompleteTextField.swift in Sources */, 8A19ACAE2A329058001C2147 /* PasswordManagerSetting.swift in Sources */, @@ -14438,7 +15538,7 @@ 1D8487B42AD0C6C100F7527C /* RemoteTabsPanelMiddleware.swift in Sources */, C849E46526B9C3DD00260F0B /* SlideoverPresentationController.swift in Sources */, E18F44072A951C330056160F /* FakespotHighlightGroup.swift in Sources */, - 2C6189312B7A8A22006B70D7 /* EcosiaLaunchScreenView.swift in Sources */, + 2CD265CB2CFE382C00A040A7 /* SeedProgressManagerProtocol.swift in Sources */, D5D0532E2645B3A700759F85 /* ExperimentsTableView.swift in Sources */, 8A832A9029DC96C50025D5DD /* LaunchScreenView.swift in Sources */, 214EF4152AC5D5D0005BCCDA /* TabDisplayView.swift in Sources */, @@ -14454,7 +15554,9 @@ AB03032B2AB47AF300DCD8EF /* FakespotOptInCardView.swift in Sources */, 0BA02DB22942605600C92603 /* FormAutofillHelper.swift in Sources */, 8A19ACB82A329128001C2147 /* PrivacyPolicySetting.swift in Sources */, + 2CD265592CFDCF0900A040A7 /* LegacyThemeManager+Ecosia.swift in Sources */, E68AEDB01B18F81A00133D99 /* SwipeAnimator.swift in Sources */, + 2CD266002CFE382C00A040A7 /* WhatsNewCell.swift in Sources */, 1DDE3DB32AC34E1E0039363B /* TabCell.swift in Sources */, 3BF56D271CDBBE1F00AC4D75 /* SimpleToast.swift in Sources */, C8B0F5F6283B7CCE007AE65D /* PocketStory.swift in Sources */, @@ -14464,21 +15566,22 @@ EBB89504219398E500EB91A0 /* TrackingProtectionPageStats.swift in Sources */, D31F95E91AC226CB005C9F3B /* ScreenshotHelper.swift in Sources */, 8A5D1CA62A30D6BD005AD35C /* NewTabPageSetting.swift in Sources */, + 2CD266082CFE382C00A040A7 /* EmptyBookmarksView.swift in Sources */, D3968F251A38FE8500CEFD3B /* TabManager.swift in Sources */, 2178A6A229145506002EC290 /* ReaderModeFontSizeLabel.swift in Sources */, 8ADC2A1D2A33999800543DAA /* VersionSetting.swift in Sources */, 96EB6C4027DBEE9800A9D159 /* SearchGroupedItemsViewController.swift in Sources */, 8ADAE41E2A33A0E2007BF926 /* ShowIntroductionSetting.swift in Sources */, 8AF10D8F29D774090086351D /* SceneSetupHelper.swift in Sources */, - 2C6189492B7A8A22006B70D7 /* DefaultBrowser.swift in Sources */, - 2C61896C2B7A8A22006B70D7 /* Welcome.swift in Sources */, C4E398601D22C409004E89BA /* TopTabsLayout.swift in Sources */, + 2CD265F72CFE382C00A040A7 /* WelcomeTourTransparent.swift in Sources */, + 2CD265FF2CFE382C00A040A7 /* WhatsNewLocalDataProvider.swift in Sources */, E1A102D62AC19B30007B617A /* FakespotUtils.swift in Sources */, 8A5D1CC12A30DCA4005AD35C /* SettingDisclosureUtility.swift in Sources */, E1442FD5294782D9003680B0 /* UIView+SnapKit.swift in Sources */, E1ADE23C2B0649F200FD17AA /* FakespotState.swift in Sources */, + 2CD265D62CFE382C00A040A7 /* NTPCustomizationCell.swift in Sources */, 2816F0001B33E05400522243 /* UIConstants.swift in Sources */, - 2C6189432B7A8A22006B70D7 /* WhatsNewViewModel.swift in Sources */, 21E78A7228F9A93100F8D687 /* UIDeviceInterface.swift in Sources */, EBB89508219398E500EB91A0 /* ContentBlocker+Safelist.swift in Sources */, 437A9B6A2681257F00FB41C1 /* LegacyInactiveTabViewModel.swift in Sources */, @@ -14487,14 +15590,13 @@ D0B9483422A03468002F4AA1 /* BookmarkDetailPanel.swift in Sources */, 968BD7EB27DFF0F8003148B3 /* ASGroup.swift in Sources */, 392ED7E41D0AEF56009D9B62 /* NewTabAccessors.swift in Sources */, - 2C61895E2B7A8A22006B70D7 /* NTPImpactDividerFooter.swift in Sources */, - 2C6189782B7A8A22006B70D7 /* NTPCustomizationSettingsViewController.swift in Sources */, 1D2F68AD2ACB266300524B92 /* RemoteTabsPanelState.swift in Sources */, + 2CD266062CFE382C00A040A7 /* EcosiaFindInPageBar.swift in Sources */, 4347B398298D6D7B0045F677 /* CreditCardTableViewModel.swift in Sources */, 1DFE57FD27BADD7D0025DE58 /* HomepageViewModel.swift in Sources */, - 2C03A4152CB7C7CC00AB228B /* DispatchQueueHelper+BuildChannel.swift in Sources */, D3A9949D1A3686BD008AD1AC /* Tab.swift in Sources */, 8AD40FD127BADCBA00672675 /* ToolbarButton.swift in Sources */, + 2CD2660A2CFE382C00A040A7 /* EmptyHeader.swift in Sources */, A93067E81D0FE18E00C49C6E /* NightModeHelper.swift in Sources */, 742BD99E2A13AC9000BA6B15 /* OnboardingInstructionPopupViewController.swift in Sources */, 9636D92C27F9E50100771F5E /* GleanPlumbMessageStore.swift in Sources */, @@ -14503,18 +15605,17 @@ 8A8629E2288096C40096DDB1 /* BookmarksFolderCell.swift in Sources */, DAE6DF1B29AD78DA0094BD1B /* BrowserViewController+ZoomPage.swift in Sources */, 8AB8574A27D97CE90075C173 /* HomePanelDelegate.swift in Sources */, - 2C6189872B7A8A22006B70D7 /* LegacyThemeManager+Ecosia.swift in Sources */, 2137786529832C8900D01309 /* OverlayModeManager.swift in Sources */, 8AF99B4D29EF076800108DEC /* WebviewViewController.swift in Sources */, 3B39EDCB1E16E1AA00EF029F /* CustomSearchViewController.swift in Sources */, - 2C5A5E672CB53DF9005BFE8B /* UserDefaultsSeedProgressManager.swift in Sources */, C8B0F5F7283B7CCE007AE65D /* PocketFeedStory.swift in Sources */, 96A562A027D6D0E80045144A /* ContileProvider.swift in Sources */, 8A5D1CAC2A30D70B005AD35C /* OpenWithSetting.swift in Sources */, 8AFA263227B6E9AB00D0C33B /* ToolbarBadge.swift in Sources */, 43D16B7A29831C7F009F8279 /* CreditCardAutofillToggle.swift in Sources */, + 2CD265D82CFE382C00A040A7 /* ClimateImpactInfo.swift in Sources */, C23889E12A4F3E7200429673 /* ParentCoordinatorDelegate.swift in Sources */, - 2C6189332B7A8A22006B70D7 /* MMP.swift in Sources */, + 2CD265D92CFE382C00A040A7 /* NTPImpactCell.swift in Sources */, 8AD40FCD27BADC5C00672675 /* TabLocationContainerView.swift in Sources */, 8A720C602A4C8B700003018A /* SharedSettingsDelegate.swift in Sources */, 211046CD2A7D842A00A7309F /* TPAccessoryInfo.swift in Sources */, @@ -14523,10 +15624,9 @@ E18EA57128AD46D3003F97FC /* WallpaperCollectionType.swift in Sources */, C84655E42887394B00861B4A /* WallpaperMetadata.swift in Sources */, 8AB8572E27D94A1A0075C173 /* UXSizeClass.swift in Sources */, + 2CD265F62CFE382C00A040A7 /* WelcomeTourRow.swift in Sources */, 965C3C8F29313A1B006499ED /* AppSessionManager.swift in Sources */, - 2C6189902B7A8A22006B70D7 /* NumberFormatter+Ecosia.swift in Sources */, 45D5EDA729269F7500311934 /* DataObserver.swift in Sources */, - 2C61896E2B7A8A22006B70D7 /* WelcomeTourAction.swift in Sources */, 961577922A38FDB300391E8D /* SponsoredTileDataUtility.swift in Sources */, D863C8F21F68BFC20058D95F /* GradientProgressBar.swift in Sources */, C8445A14264428DC00B83F53 /* LibraryPanelViewState.swift in Sources */, @@ -14534,22 +15634,22 @@ E134D5802B31FF3100C6B17B /* FakespotAdLinkButton.swift in Sources */, 8AE0BF4F2819B10E00F33EC4 /* TopSitesSettingsViewController.swift in Sources */, 8A8DDEBF276259A900E7B97A /* RatingPromptManager.swift in Sources */, + 2CD265CD2CFE382C00A040A7 /* ArcProgressView.swift in Sources */, 1D969C702B21322B004255B1 /* BrowserWindow.swift in Sources */, 8AB8571D27D929350075C173 /* TopSitesViewModel.swift in Sources */, - 2C6189942B7A8A22006B70D7 /* DeviceInfo+Ecosia.swift in Sources */, - 2C78374B2C1765DF00BBFFEB /* LoadingScreen.swift in Sources */, 8A93F85E29D36DA9004159D9 /* Coordinator.swift in Sources */, + 2CD265F02CFE382C00A040A7 /* WelcomeNavigation.swift in Sources */, 1D2F68B12ACCA22000524B92 /* RemoteTabsEmptyView.swift in Sources */, 43D16B8729831EEF009F8279 /* RemoveCardButton.swift in Sources */, D59431ED25E9912900F0BA82 /* WidgetIntents.intentdefinition in Sources */, 213778632980448C00D01309 /* DownloadFileFetcher.swift in Sources */, F85C7EDF2710B4DD004BDBA4 /* LoginOnboarding.swift in Sources */, C8B0F5F5283B7CCE007AE65D /* PocketSponsoredStory.swift in Sources */, - 2C6189982B7A8A22006B70D7 /* BookmarksExchange.swift in Sources */, 8AF6D4E12A856B4500B0474B /* ContileNetworking.swift in Sources */, 8AB8571F27D931B40075C173 /* EmptyTopSiteCell.swift in Sources */, CAC458F1249429C20042561A /* PasswordManagerSelectionHelper.swift in Sources */, C8656D75270F834600E199EA /* FlaggableFeatureOptions.swift in Sources */, + 2CD2655F2CFDCF0900A040A7 /* UIView+maskedCorners.swift in Sources */, C8CD80D82A1E31C20097C3AE /* NimbusOnboardingTestingConfigUtility.swift in Sources */, 8AB8573727D951640075C173 /* HomeLogoHeaderViewModel.swift in Sources */, D3C744CD1A687D6C004CE85D /* URIFixup.swift in Sources */, @@ -14560,9 +15660,11 @@ AB42CC752A1F5240003C9594 /* CreditCardBottomSheetHeaderView.swift in Sources */, 21371FA428AA7A8D00BC3F37 /* OnboardingViewModelProtocol.swift in Sources */, 21DB34342B20FE35008CCB8E /* LegacyRemoteTabsTableViewController.swift in Sources */, - 2C6189912B7A8A22006B70D7 /* URL+Ecosia.swift in Sources */, 8ABCFEA32B45C36100C2988A /* PrivateBrowsingTelemetry.swift in Sources */, + 2CD265EF2CFE382C00A040A7 /* Welcome.swift in Sources */, + 2CD266552CFF56EA00A040A7 /* WebsiteConnectionStatus.swift in Sources */, 8ADC2A1F2A3399BD00543DAA /* LicenseAndAcknowledgementsSetting.swift in Sources */, + 2CD266522CFF56CB00A040A7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift in Sources */, 8CCCB08B2AE26B5C0073ADB9 /* ReportResponse.swift in Sources */, 21A43CDD291461C700B1206D /* ReaderModeFontTypeButton.swift in Sources */, D3BE7B261B054D4400641031 /* main.swift in Sources */, @@ -14572,14 +15674,14 @@ E1FF93E228A2E55700E6360E /* WallpaperSelectorViewController.swift in Sources */, D3A9949C1A3686BD008AD1AC /* BrowserViewController.swift in Sources */, 8A5D1CBB2A30DC0B005AD35C /* ConnectSetting.swift in Sources */, + 2CD265FD2CFE382C00A040A7 /* EcosiaThemeManager.swift in Sources */, E6CF28E71CB43B7900151AB3 /* SensitiveViewController.swift in Sources */, 43AB6FA225DC53D30016B015 /* GoogleTopSiteManager.swift in Sources */, - 2C6189592B7A8A22006B70D7 /* NTPTooltipDelegate.swift in Sources */, 8A5D1CB62A30DBB0005AD35C /* DefaultBrowserSetting.swift in Sources */, 4393932029AC6CE900DC5A85 /* EnvironmentValues+Extension.swift in Sources */, ABEF80D12A24D2BE003F52C4 /* CreditCardBottomSheetViewModel.swift in Sources */, 21AFCFF02AE80D370027E9CE /* RemoteTabsCoordinator.swift in Sources */, - 12147F2F2CDA3CD00009D300 /* NTPNewsletterCardCell.swift in Sources */, + 2CD265FA2CFE382C00A040A7 /* PageActionsShortcutsHeader.swift in Sources */, 43162A2F2492DB7800F91658 /* EmptyPrivateTabsView.swift in Sources */, E1380B8D2AEA897C00630AFA /* SidebarEnabledView.swift in Sources */, D0625C98208E87F10081F3B2 /* DownloadQueue.swift in Sources */, @@ -14588,21 +15690,22 @@ 966E4B2629F2D4AC00299B8D /* AccessoryViewProvider.swift in Sources */, ABEF80D52A254185003F52C4 /* CreditCardBottomSheetFooterView.swift in Sources */, C869912E28917688007ACC5C /* WallpaperDataService.swift in Sources */, + 2CD2661B2CFE38AD00A040A7 /* EcosiaHomepageSectionType.swift in Sources */, 5A8017E029CE15D90047120D /* TabManagerImplementation.swift in Sources */, 8AABBD012A001ADF0089941E /* ApplicationHelper.swift in Sources */, E633E2DA1C21EAF8001FFF6C /* PasswordDetailViewController.swift in Sources */, - 2C6189472B7A8A22006B70D7 /* WhatsNewLocalDataProvider.swift in Sources */, + 2CD265E42CFE382C00A040A7 /* NTPNewsCellViewModel.swift in Sources */, 8A5D1CAE2A30D71A005AD35C /* ThemeSetting.swift in Sources */, C82F4C2B29AE2DF1005BD116 /* NotificationsSettingsViewController.swift in Sources */, - 2C6189712B7A8A22006B70D7 /* WelcomeTourGreen.swift in Sources */, 59A68B280D62462B85CF57A4 /* HistoryPanel.swift in Sources */, - 2CA995282CA2C06A001064CC /* NTPConfigurableNudgeCardCell.swift in Sources */, C400467C1CF4E43E00B08303 /* BackForwardListViewController.swift in Sources */, D5D237782640BBA600326204 /* ExperimentsSettingsViewController.swift in Sources */, + 2CD266072CFE382C00A040A7 /* EcosiaNavigation.swift in Sources */, D3972BF31C22412B00035B87 /* ShareExtensionHelper.swift in Sources */, F35B8D2D1D6383E9008E3D61 /* SessionRestoreHelper.swift in Sources */, 8A19ACB62A3290F9001C2147 /* NotificationsSetting.swift in Sources */, 43D16B8229831E6A009F8279 /* CreditCardInputField.swift in Sources */, + 2CD265D02CFE382C00A040A7 /* SeedCounterConfig.swift in Sources */, EB98550124226EF70040F24B /* AppDelegate+SyncSentTabs.swift in Sources */, 744ED5611DBFEB8D00A2B5BE /* MailtoLinkHandler.swift in Sources */, 8A720C622A4CBB370003018A /* SupportSettingsDelegate.swift in Sources */, @@ -14612,7 +15715,6 @@ BD4B2DE429BB4D9A005FAA50 /* TimerSnackBar.swift in Sources */, 810FF3582B1784E7009F062C /* PrivateModeAction.swift in Sources */, 21EA466A2B04130500AAAB2D /* TabsPanelState.swift in Sources */, - 122935B32CE79E2400EC1297 /* SeedCounterNTPExperiment.swift in Sources */, D04D1B862097859B0074B35F /* DownloadToast.swift in Sources */, C29B64EE2AD937D500F3244B /* QRCodeNavigationHandler.swift in Sources */, 8A19ACB42A3290D9001C2147 /* ContentBlockerSetting.swift in Sources */, @@ -14621,7 +15723,6 @@ 8A3EF8112A2FD06B00796E3A /* ToggleHistoryGroups.swift in Sources */, 219A0FD92ACC8C0F009A6D1A /* InactiveTabsFooterView.swift in Sources */, 884CA7492344A301002E4711 /* TextContentDetector.swift in Sources */, - 2C6189552B7A8A22006B70D7 /* NewsController.swift in Sources */, C8656D77270F858900E199EA /* TabsSettingsViewControler.swift in Sources */, 8A9F0B5627C595F300FE09AE /* ImageIdentifiers.swift in Sources */, 7B844E3D1BBDDB9D00E733A2 /* ChevronView.swift in Sources */, @@ -14631,16 +15732,19 @@ E4C358551AF144BA00299F7E /* FSReadingList.m in Sources */, 8AE1E1CB27B18F560024C45E /* SearchBarSettingsViewController.swift in Sources */, 8AD40FC527BADC1F00672675 /* TabToolbarHelper.swift in Sources */, + 2CD265E72CFE382C00A040A7 /* NTPConfigurableNudgeCardCell.swift in Sources */, 9609F4CA26B57CE800F81493 /* Calendar+Extension.swift in Sources */, + 2CD265D22CFE382C00A040A7 /* SeedCounterView.swift in Sources */, E663D5781BB341C4001EF30E /* ToggleButton.swift in Sources */, DFA51481275FFEE500266AA0 /* HistoryHighlightsManager.swift in Sources */, + 2CD265542CFDCF0900A040A7 /* BrowserViewController+Ecosia.swift in Sources */, 8ADC2A182A33775F00543DAA /* FxASignInViewParameters.swift in Sources */, EBA3B2D22268F57E00728BDB /* BadgeWithBackdrop.swift in Sources */, 8A83B7482A264FB7002FF9AC /* LibraryCoordinator.swift in Sources */, 96EB6C3C27D82AEA00A9D159 /* HistoryPanel+ContextMenuExtensions.swift in Sources */, - 2C61894E2B7A8A22006B70D7 /* NTPLibraryCell.swift in Sources */, E1CD81C2290C62A600124B27 /* HostingTableViewCell.swift in Sources */, 43175DB826B87D2C00C41C31 /* AdsTelemetryHelper.swift in Sources */, + 2CD2655B2CFDCF0900A040A7 /* SimpleToast+Ecosia.swift in Sources */, 8A3EF7FF2A2FCFBB00796E3A /* ChangeToChinaSetting.swift in Sources */, E6327A641BF6438E008D12E0 /* DebugSettingsBundleOptions.swift in Sources */, F85C7EDD27109241004BDBA4 /* PasswordManagerOnboardingViewController.swift in Sources */, @@ -14649,7 +15753,6 @@ 21F2A2D22B0BC85200626AEC /* InactiveTabsModel.swift in Sources */, D3E8EF101B97BE69001900FB /* ClearPrivateDataTableViewController.swift in Sources */, C8F457AA1F1FDD9B000CB895 /* BrowserViewController+KeyCommands.swift in Sources */, - 2C6189462B7A8A22006B70D7 /* WhatsNewDataProvider.swift in Sources */, 21357F2F294237D8004BF9FD /* RemoteTabsClientAndTabsDataSource.swift in Sources */, 59A68FD5260B8D520F890F4A /* ReaderPanel.swift in Sources */, 21D0F62129B91BF500022292 /* ToastView.swift in Sources */, @@ -14658,7 +15761,6 @@ 59A68D66379CFA85C4EAF00B /* TwoLineImageOverlayCell.swift in Sources */, 8A04136928258DF600D20B10 /* SponsoredTileTelemetry.swift in Sources */, D04CD718215EBD85004FF5B0 /* SettingsLoadingView.swift in Sources */, - 2C6189682B7A8A22006B70D7 /* FilterController.swift in Sources */, 21420EF72ABA338D00B28550 /* TabTrayCoordinator.swift in Sources */, 5A70EF1F295E3DFC00790249 /* UnitTestAppDelegate.swift in Sources */, 2128E27E2934F78600FB91BE /* CustomAppActivity.swift in Sources */, @@ -14667,7 +15769,7 @@ C8CD80D72A1E2C6E0097C3AE /* NimbusMessagingHelperUtilityProtocol.swift in Sources */, 8ACE9BFB2A54A010001E7A73 /* ExpandButtonState.swift in Sources */, 8AC5D55F28BFE6C8001F6F7F /* Presenter.swift in Sources */, - 2C6189892B7A8A22006B70D7 /* UIFont+Ecosia.swift in Sources */, + 2CD265C82CFE382C00A040A7 /* NTPAboutEcosiaCell.swift in Sources */, 8AEDB11529F9F00400F2A53B /* SceneContainer.swift in Sources */, AB42CC742A1F5240003C9594 /* CreditCardBottomSheetViewController.swift in Sources */, C8741FE928C4D30F00030029 /* FileManagerInterface.swift in Sources */, @@ -14675,9 +15777,9 @@ 8A3233FE28627446003E1C33 /* LocalDesktopFolder.swift in Sources */, 8AD40FCA27BADC4B00672675 /* ReaderModeButton.swift in Sources */, E1C437A32A96343A00D188CB /* FakespotFadeLabel.swift in Sources */, - 2C61897F2B7A8A22006B70D7 /* EcosiaHomepageSectionType.swift in Sources */, 8A3EF7FB2A2FCF9D00796E3A /* ForceCrashSetting.swift in Sources */, 2178A6A4291455F7002EC290 /* ReaderModeFontSizeButton.swift in Sources */, + 2CD265582CFDCF0900A040A7 /* HomepageViewController+Ecosia.swift in Sources */, BCFF93F02AABA55A005B5B71 /* BackgroundFirefoxSuggestIngestUtility.swift in Sources */, BCFF93F22AAF9688005B5B71 /* FirefoxSuggestSettings.swift in Sources */, BCFF93F42AAF9879005B5B71 /* FirefoxSuggestSettingsViewController.swift in Sources */, @@ -14688,14 +15790,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2C872A5A2B8CD7E000B318A0 /* MockAppVersionInfoProvider.swift in Sources */, - 2C872A5B2B8CD7E000B318A0 /* AnalyticsTests.swift in Sources */, - 2C872A5E2B8CD7E000B318A0 /* EcosiaInstallTypeTests.swift in Sources */, - 2C872A5F2B8CD7E000B318A0 /* EcosiaNTPTooltipHighlightTests.swift in Sources */, - 2C872A602B8CD7E000B318A0 /* EcosiaPageActionMenuCellTests.swift in Sources */, - 2C872A622B8CD7E000B318A0 /* VersionTests.swift in Sources */, - 2C872A632B8CD7E000B318A0 /* WhatsNewLocalDataProviderTests.swift in Sources */, - 2C872A642B8CD7E000B318A0 /* EcosiaHomeViewModelTests.swift in Sources */, E4CD9F1D1A6D9C2800318571 /* WebServerTests.swift in Sources */, C869916528918C8E007ACC5C /* WallpaperURLSessionMock.swift in Sources */, 961577942A39008100391E8D /* SponsoredTileDataUtilityTests.swift in Sources */, @@ -14704,7 +15798,6 @@ 213B67A827CE721E000542F5 /* StartAtHomeHelperTests.swift in Sources */, 8A13FA892AD82BC8007527AB /* AppSendTabDelegateTests.swift in Sources */, C8CD80D42A1E268C0097C3AE /* MockGleanPlumbEvaluationUtility.swift in Sources */, - 2C2349A32C57E5BC007A5894 /* EcosiaPerformanceTestHistory.swift in Sources */, 8A7A26E829D4C0FE00EA76F1 /* IntroScreenManagerTests.swift in Sources */, E1AEC17A286E0CF500062E29 /* WebViewNavigationHandlerTests.swift in Sources */, D3D488591ABB54CD00A93597 /* FileAccessorTests.swift in Sources */, @@ -14718,15 +15811,12 @@ C29B64872AD69D0200F3244B /* QRCodeCoordinatorTests.swift in Sources */, 0BA8964B1A250E6500C1010C /* ProfileTest.swift in Sources */, 8AE80BAF2891960300BC12EA /* MockTraitCollection.swift in Sources */, - 2C9A62C22CDE4A3B00CDA7D1 /* MockNewsModel.swift in Sources */, E19443F82AF953B000964EA5 /* MockSidebarEnabledView.swift in Sources */, 8A832A9729DCBD3C0025D5DD /* LaunchTypeTests.swift in Sources */, 8A28C628291028870078A81A /* CanRemoveQuickActionBookmarkTests.swift in Sources */, 03CCC9181AF05E7300DBF30D /* RelativeDatesTests.swift in Sources */, F84B21DA1A090F8100AAB793 /* ClientTests.swift in Sources */, - 2CABD7282C12EF1E00A0750F /* PrivateModeButtonTests.swift in Sources */, 219935F12B07DFA200E5966F /* TabDisplayPanelTests.swift in Sources */, - 2C16B7672CAF2441006118F8 /* UserDefaultsSeedProgressManagerTests.swift in Sources */, DF940A0C2A96352B00C1497D /* FakespotSettingsCardViewModelTests.swift in Sources */, 281B2BEA1ADF4D90002917DC /* MockProfile.swift in Sources */, 96AF8C1C29FC14F700EC2219 /* CreditCardInputFieldHelperTests.swift in Sources */, @@ -14783,7 +15873,6 @@ C81C66C429F00D1000F6422F /* UserActivityRouteTests.swift in Sources */, 8AFCE50529DDF38300B1B253 /* LaunchScreenViewControllerTests.swift in Sources */, D3FA777B1A43B2990010CD32 /* SearchTests.swift in Sources */, - 2C26EA142C04CAD100795552 /* EcosiaTopSitesHelperTests.swift in Sources */, D3BA41681BD82F2200DA5457 /* XCTestCaseExtensions.swift in Sources */, 8A86DAD8277298DE00D7BFFF /* ClosedTabsStoreTests.swift in Sources */, 21E78A7028F9A8C500F8D687 /* MockUIDevice.swift in Sources */, @@ -14802,7 +15891,6 @@ C2B808B12A77FA3F00A65487 /* DownloadsCoordinatorTests.swift in Sources */, 5A475E9129DB8AA7009C13FD /* MockDiskImageStore.swift in Sources */, DFA51484276103A000266AA0 /* HistoryHighlightsManagerTests.swift in Sources */, - 2C9A62C02CDE1F7600CDA7D1 /* MockWelcomeDelegate.swift in Sources */, C2506C952A6A8D2600F2B76E /* HistoryCoordinatorTests.swift in Sources */, 8ADAFAC628AEBF6300FFEBE3 /* HomeLogoHeaderViewModelTests.swift in Sources */, E14BF33E2950B1230039758D /* MailProvidersTests.swift in Sources */, @@ -14839,12 +15927,10 @@ 5AF6254728A58AC100A90253 /* MockHistoryHighlightsDataAdaptor.swift in Sources */, 8A7A26E329D4ACF300EA76F1 /* SceneCoordinatorTests.swift in Sources */, 39C137972655798A003DC662 /* NimbusIntegrationTests.swift in Sources */, - 2C7DBABD2C4EA37200BCD03F /* AppDelegateFeatureManagementIntegrationTests.swift in Sources */, 215B458427DA87FC00E5E800 /* TabMetadataManagerTests.swift in Sources */, 2173326A29CCF901007F20C7 /* UIPanGestureRecognizerMock.swift in Sources */, 5A9A09D628B01FD500B6F51E /* MockURLBarView.swift in Sources */, 8A33222227DFE658008F809E /* NimbusMock.swift in Sources */, - 2C728D7E2CBBDCDC00C7684B /* UnleashUserDefaultsSeedProgressManagerTests.swift in Sources */, 8A6E139E2A71C78A00A88FA8 /* GridTabViewControllerTests.swift in Sources */, 8A8629E72880B7330096DDB1 /* BookmarksPanelTests.swift in Sources */, C8B394362A0ED55D00700E49 /* MockOnboardingCardDelegate.swift in Sources */, @@ -14897,7 +15983,6 @@ 8A5604F629DF09FA00035CA3 /* MockLaunchCoordinatorDelegate.swift in Sources */, C807CCCC28367446008E6A5A /* FeatureFlagManagerTests.swift in Sources */, 8A5C3BC5282ABF8E003A8CCF /* LegacyRemoteTabsPanelTests.swift in Sources */, - 1285E2B52CC293CA0053506B /* AnalyticsSpyTests.swift in Sources */, 8AABBD032A001CBC0089941E /* MockApplicationHelper.swift in Sources */, 8A1E3BE328CBACDD003388C4 /* SponsoredContentFilterUtilityTests.swift in Sources */, 2173326829CCDA8E007F20C7 /* TabScrollControllerTests.swift in Sources */, @@ -14912,7 +15997,6 @@ A83E5B1D1C1DA8D80026D912 /* UIPasteboardExtensionsTests.swift in Sources */, 5AB4237C28A1947A003BC40C /* MockNotificationCenter.swift in Sources */, 8A37C79F28DA4BA600B1FAD4 /* ContextualHintViewProviderTests.swift in Sources */, - 2C9258D92CEF97B100C6BB8D /* MockUNNotificationSettings.swift in Sources */, 5A81C5DD2A4C981A00BE88C2 /* PasswordManagerCoordinatorTests.swift in Sources */, 8A355E5E27D267A400B9AF34 /* RecentItemsHelperTests.swift in Sources */, C8699153289177FB007ACC5C /* WallpaperDataServiceTests.swift in Sources */, @@ -14931,7 +16015,6 @@ D82ED2641FEB3C420059570B /* DefaultSearchPrefsTests.swift in Sources */, 1D74FF502B2797EA00FF01D0 /* WindowManagerTests.swift in Sources */, CA24B53B24ABFE5D0093848C /* PasswordManagerDataSourceHelperTests.swift in Sources */, - 2CD48B7F2C7F7E4100A70908 /* EcosiaOverlayModeManagerTests.swift in Sources */, E1390FB828B42EF200C9EF3E /* WallpaperManagerMock.swift in Sources */, ABB507CF2A136FB2009CAA67 /* UserConversionMetricsTests.swift in Sources */, 21FA8FB22AE856EB0013B815 /* MockTabTrayCoordinatorDelegate.swift in Sources */, @@ -14972,7 +16055,10 @@ D04CD74D216CF86F004FF5B0 /* DevicePickerViewController.swift in Sources */, 2C6189E12B7B7922006B70D7 /* LegacyTheme.swift in Sources */, E13A72D9291154E600E9A99D /* ReusableCell.swift in Sources */, + 2CD266412CFF4FB200A040A7 /* LegacyThemeManager+Ecosia.swift in Sources */, + 2CD266432CFF4FC300A040A7 /* SemanticColor.swift in Sources */, 6025B10F267B6C7F00F59F6B /* LoginRecordExtension.swift in Sources */, + 2CD2663F2CFF4FA300A040A7 /* EcosiaTheme.swift in Sources */, E418D0D91A251B3200CAE47A /* Profile.swift in Sources */, E1CD81C3290C670A00124B27 /* HostingTableViewCell.swift in Sources */, DDA24A451FD84D630098F159 /* DefaultSearchPrefs.swift in Sources */, @@ -14980,13 +16066,11 @@ F8708D321A0970B70051AB07 /* ShareViewController.swift in Sources */, EB9407492081353100702E05 /* UXConstants.swift in Sources */, 2C6189E32B7B792A006B70D7 /* LegacyThemeManager.swift in Sources */, - 2C6189EA2B7B7979006B70D7 /* EcosiaTheme.swift in Sources */, F8B710A02ABE38980029726E /* RustErrors.swift in Sources */, E60D03271D511554002FE3F6 /* SyncDisplayState.swift in Sources */, - 2C6189D22B7A8D69006B70D7 /* EcosiaThemeColourPalette.swift in Sources */, - 2C6189D12B7A8D3E006B70D7 /* EcosiaThemeManager.swift in Sources */, + 2CD266472CFF4FE800A040A7 /* EcosiaThemeColourPalette.swift in Sources */, 210E0EBB298D9D6600BB4F33 /* OpenSearchEngine.swift in Sources */, - 2C6189E62B7B7952006B70D7 /* SemanticColor.swift in Sources */, + 2CD266452CFF4FD100A040A7 /* EcosiaThemeManager.swift in Sources */, 2128E27C2930216F00FB91BE /* SendToDeviceHelper.swift in Sources */, E136D41A2B19D35D003D0302 /* EmbeddedNavController.swift in Sources */, E1CD81C0290C5C9800124B27 /* DevicePickerTableViewCell.swift in Sources */, @@ -14994,7 +16078,6 @@ 2C6189E52B7B7946006B70D7 /* LegacyDarkTheme.swift in Sources */, E1CD81BF290C5C9500124B27 /* DevicePickerTableViewHeaderCell.swift in Sources */, 1D1933782AF2C8CE005089C9 /* AppEvent.swift in Sources */, - 2C26FAA92C8752D20055760A /* LegacyThemeManager+Ecosia.swift in Sources */, 1D969C722B2132B7004255B1 /* BrowserWindow.swift in Sources */, 1D1933752AF2C8C9005089C9 /* EventQueue.swift in Sources */, E41A7D4B1A1BE04500245963 /* InitialViewController.swift in Sources */, @@ -15460,28 +16543,98 @@ name = Today.strings; sourceTree = ""; }; - 2C6188DB2B7A8A22006B70D7 /* Ecosia.strings */ = { + 2CD263C92CFDC76800A040A7 /* Ecosia.strings */ = { + isa = PBXVariantGroup; + children = ( + 2CD263C82CFDC76800A040A7 /* de */, + ); + name = Ecosia.strings; + sourceTree = ""; + }; + 2CD263CB2CFDC76800A040A7 /* Ecosia.strings */ = { + isa = PBXVariantGroup; + children = ( + 2CD263CA2CFDC76800A040A7 /* en */, + ); + name = Ecosia.strings; + sourceTree = ""; + }; + 2CD263CD2CFDC76800A040A7 /* Ecosia.strings */ = { + isa = PBXVariantGroup; + children = ( + 2CD263CC2CFDC76800A040A7 /* es */, + ); + name = Ecosia.strings; + sourceTree = ""; + }; + 2CD263CF2CFDC76800A040A7 /* Ecosia.strings */ = { + isa = PBXVariantGroup; + children = ( + 2CD263CE2CFDC76800A040A7 /* it */, + ); + name = Ecosia.strings; + sourceTree = ""; + }; + 2CD263D12CFDC76800A040A7 /* Ecosia.strings */ = { + isa = PBXVariantGroup; + children = ( + 2CD263D02CFDC76800A040A7 /* fr */, + ); + name = Ecosia.strings; + sourceTree = ""; + }; + 2CD263D32CFDC76800A040A7 /* Ecosia.strings */ = { isa = PBXVariantGroup; children = ( - 2C6188DC2B7A8A22006B70D7 /* de */, - 2C6188DF2B7A8A22006B70D7 /* en */, - 2C6188E12B7A8A22006B70D7 /* es */, - 2C6188E32B7A8A22006B70D7 /* it */, - 2C6188E92B7A8A22006B70D7 /* fr */, - 2C6188EB2B7A8A22006B70D7 /* nl */, + 2CD263D22CFDC76800A040A7 /* nl */, ); name = Ecosia.strings; sourceTree = ""; }; - 2C6188DD2B7A8A22006B70D7 /* Plurals.stringsdict */ = { + 2CD263D52CFDC76800A040A7 /* Plurals.stringsdict */ = { isa = PBXVariantGroup; children = ( - 2C6188DE2B7A8A22006B70D7 /* de */, - 2C6188E02B7A8A22006B70D7 /* en */, - 2C6188E22B7A8A22006B70D7 /* es */, - 2C6188E42B7A8A22006B70D7 /* it */, - 2C6188EA2B7A8A22006B70D7 /* fr */, - 2C6188EC2B7A8A22006B70D7 /* nl */, + 2CD263D42CFDC76800A040A7 /* de */, + ); + name = Plurals.stringsdict; + sourceTree = ""; + }; + 2CD263D72CFDC76800A040A7 /* Plurals.stringsdict */ = { + isa = PBXVariantGroup; + children = ( + 2CD263D62CFDC76800A040A7 /* en */, + ); + name = Plurals.stringsdict; + sourceTree = ""; + }; + 2CD263D92CFDC76800A040A7 /* Plurals.stringsdict */ = { + isa = PBXVariantGroup; + children = ( + 2CD263D82CFDC76800A040A7 /* es */, + ); + name = Plurals.stringsdict; + sourceTree = ""; + }; + 2CD263DB2CFDC76800A040A7 /* Plurals.stringsdict */ = { + isa = PBXVariantGroup; + children = ( + 2CD263DA2CFDC76800A040A7 /* it */, + ); + name = Plurals.stringsdict; + sourceTree = ""; + }; + 2CD263DD2CFDC76800A040A7 /* Plurals.stringsdict */ = { + isa = PBXVariantGroup; + children = ( + 2CD263DC2CFDC76800A040A7 /* fr */, + ); + name = Plurals.stringsdict; + sourceTree = ""; + }; + 2CD263DF2CFDC76800A040A7 /* Plurals.stringsdict */ = { + isa = PBXVariantGroup; + children = ( + 2CD263DE2CFDC76800A040A7 /* nl */, ); name = Plurals.stringsdict; sourceTree = ""; @@ -20712,6 +21865,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 2CBCAB0B2B88EEE40080AD68 /* EcosiaBeta.xcconfig */; buildSettings = { + INFOPLIST_FILE = Client/Info.plist; OTHER_LDFLAGS = ( "$(inherited)", "-Xlinker", @@ -21599,6 +22753,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 2CBCAB0C2B88EEE40080AD68 /* Ecosia.xcconfig */; buildSettings = { + INFOPLIST_FILE = Client/Info.plist; OTHER_LDFLAGS = ( "$(inherited)", "-Xlinker", @@ -21846,6 +23001,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 2CBCAAFE2B88EEE40080AD68 /* EcosiaBetaDebug.xcconfig */; buildSettings = { + INFOPLIST_FILE = Client/Info.plist; OTHER_LDFLAGS = ( "$(inherited)", "-Xlinker", @@ -22079,6 +23235,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 2CBCAB0B2B88EEE40080AD68 /* EcosiaBeta.xcconfig */; buildSettings = { + INFOPLIST_FILE = Client/Info.plist; OTHER_LDFLAGS = ( "$(inherited)", "-Xlinker", @@ -22269,6 +23426,7 @@ isa = XCBuildConfiguration; baseConfigurationReference = 2CBCAB0E2B88EEE40080AD68 /* EcosiaDebug.xcconfig */; buildSettings = { + INFOPLIST_FILE = Client/Info.plist; OTHER_LDFLAGS = ( "$(inherited)", "-Xlinker", @@ -22934,6 +24092,20 @@ productName = Sentry; }; /* End XCSwiftPackageProductDependency section */ + +/* Begin XCVersionGroup section */ + 2CD2656D2CFE382C00A040A7 /* SeedCounter.xcdatamodeld */ = { + isa = XCVersionGroup; + children = ( + 2CD265C42CFE382C00A040A7 /* SeedCounter.xcdatamodel */, + ); + currentVersion = 2CD265C42CFE382C00A040A7 /* SeedCounter.xcdatamodel */; + name = SeedCounter.xcdatamodeld; + path = "/Users/dariocarlomagno/Workspace/ecosia/ios-browser/Client/Ecosia/UI/NTP/ClimateImpactCounter/CoreData/SeedCounter.xcdatamodeld"; + sourceTree = ""; + versionGroupType = wrapper.xcdatamodel; + }; +/* End XCVersionGroup section */ }; rootObject = F84B21B61A090F8100AAB793 /* Project object */; } diff --git a/Client/Application/AppDelegate.swift b/Client/Application/AppDelegate.swift index 26ffc750f833..986fea36f2ce 100644 --- a/Client/Application/AppDelegate.swift +++ b/Client/Application/AppDelegate.swift @@ -11,6 +11,7 @@ import Common import TabDataStore // Ecosia: Import Core import Core +// Ecosia: Import Ecosia Framework import Ecosia class AppDelegate: UIResponder, UIApplicationDelegate { diff --git a/Client/Configuration/Ecosia.ShareTo.xcconfig b/Client/Configuration/Ecosia.ShareTo.xcconfig index 9591255634c9..8d92c0357c42 100644 --- a/Client/Configuration/Ecosia.ShareTo.xcconfig +++ b/Client/Configuration/Ecosia.ShareTo.xcconfig @@ -5,6 +5,6 @@ #include "Ecosia.xcconfig" PROVISIONING_PROFILE_SPECIFIER = match AdHoc com.ecosia.ecosiaapp.ShareTo -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/AppExtensions/Ecosia.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/AppExtensions/Ecosia.entitlements MOZ_BUNDLE_ID = com.ecosia.ecosiaapp PRODUCT_BUNDLE_IDENTIFIER = $(MOZ_BUNDLE_ID).$(PRODUCT_NAME) diff --git a/Client/Configuration/Ecosia.WidgetKit.xcconfig b/Client/Configuration/Ecosia.WidgetKit.xcconfig index 51b6520c29cb..d35b0b3061ac 100644 --- a/Client/Configuration/Ecosia.WidgetKit.xcconfig +++ b/Client/Configuration/Ecosia.WidgetKit.xcconfig @@ -6,6 +6,6 @@ ECOSIA_PRODUCT_NAME = WidgetKit PROVISIONING_PROFILE_SPECIFIER = match AdHoc com.ecosia.ecosiaapp.WidgetKit -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/AppExtensions/Ecosia.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/AppExtensions/Ecosia.entitlements MOZ_BUNDLE_ID = com.ecosia.ecosiaapp PRODUCT_BUNDLE_IDENTIFIER = $(MOZ_BUNDLE_ID).$(ECOSIA_PRODUCT_NAME) diff --git a/Client/Configuration/Ecosia.xcconfig b/Client/Configuration/Ecosia.xcconfig index 5764bbf47b42..e37b8da43b03 100644 --- a/Client/Configuration/Ecosia.xcconfig +++ b/Client/Configuration/Ecosia.xcconfig @@ -8,7 +8,7 @@ MOZ_BUNDLE_DISPLAY_NAME = Ecosia MOZ_BUNDLE_ID = com.ecosia.ecosiaapp -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/Ecosia.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/Ecosia.entitlements OTHER_SWIFT_FLAGS = $(OTHER_SWIFT_FLAGS_common) -DMOZ_CHANNEL_RELEASE MOZ_INTERNAL_URL_SCHEME = ecosia DEVELOPMENT_TEAM = 33YMRSYD2L diff --git a/Client/Configuration/EcosiaBeta.ShareTo.xcconfig b/Client/Configuration/EcosiaBeta.ShareTo.xcconfig index 8fe469541dc8..c67747edf897 100644 --- a/Client/Configuration/EcosiaBeta.ShareTo.xcconfig +++ b/Client/Configuration/EcosiaBeta.ShareTo.xcconfig @@ -6,5 +6,5 @@ PROVISIONING_PROFILE_SPECIFIER = match AdHoc com.ecosia.ecosiaapp.firefox.ShareTo PRODUCT_BUNDLE_IDENTIFIER = $(MOZ_BUNDLE_ID).$(PRODUCT_NAME) -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements MOZ_BUNDLE_ID = com.ecosia.ecosiaapp.firefox diff --git a/Client/Configuration/EcosiaBeta.WidgetKit.xcconfig b/Client/Configuration/EcosiaBeta.WidgetKit.xcconfig index 0b7ed6352bd6..07a3b69401de 100644 --- a/Client/Configuration/EcosiaBeta.WidgetKit.xcconfig +++ b/Client/Configuration/EcosiaBeta.WidgetKit.xcconfig @@ -6,5 +6,5 @@ ECOSIA_PRODUCT_NAME = WidgetKit PROVISIONING_PROFILE_SPECIFIER = match AdHoc com.ecosia.ecosiaapp.firefox.WidgetKit -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements PRODUCT_BUNDLE_IDENTIFIER = $(MOZ_BUNDLE_ID).$(ECOSIA_PRODUCT_NAME) diff --git a/Client/Configuration/EcosiaBeta.xcconfig b/Client/Configuration/EcosiaBeta.xcconfig index f1ef06bfde39..79d580484b96 100644 --- a/Client/Configuration/EcosiaBeta.xcconfig +++ b/Client/Configuration/EcosiaBeta.xcconfig @@ -10,7 +10,7 @@ MOZ_BUNDLE_DISPLAY_NAME = Ecosia Beta MOZ_BUNDLE_ID = com.ecosia.ecosiaapp.firefox -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/EcosiaBeta.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/EcosiaBeta.entitlements OTHER_SWIFT_FLAGS = $(OTHER_SWIFT_FLAGS_common) -DMOZ_CHANNEL_BETA MOZ_INTERNAL_URL_SCHEME = ecosia DEVELOPMENT_TEAM = 33YMRSYD2L diff --git a/Client/Configuration/EcosiaBetaDebug.ShareTo.xcconfig b/Client/Configuration/EcosiaBetaDebug.ShareTo.xcconfig index 651cc6e72cb8..84e0889a17ed 100644 --- a/Client/Configuration/EcosiaBetaDebug.ShareTo.xcconfig +++ b/Client/Configuration/EcosiaBetaDebug.ShareTo.xcconfig @@ -5,6 +5,6 @@ #include "EcosiaBetaDebug.xcconfig" PROVISIONING_PROFILE_SPECIFIER = match Development com.ecosia.ecosiaapp.firefox.ShareTo -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements MOZ_BUNDLE_ID = com.ecosia.ecosiaapp.firefox PRODUCT_BUNDLE_IDENTIFIER = $(MOZ_BUNDLE_ID).$(PRODUCT_NAME) diff --git a/Client/Configuration/EcosiaBetaDebug.WidgetKit.xcconfig b/Client/Configuration/EcosiaBetaDebug.WidgetKit.xcconfig index 0f0f76cb8d93..933452864191 100644 --- a/Client/Configuration/EcosiaBetaDebug.WidgetKit.xcconfig +++ b/Client/Configuration/EcosiaBetaDebug.WidgetKit.xcconfig @@ -6,5 +6,5 @@ ECOSIA_PRODUCT_NAME = WidgetKit PROVISIONING_PROFILE_SPECIFIER = match Development com.ecosia.ecosiaapp.firefox.WidgetKit -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements PRODUCT_BUNDLE_IDENTIFIER = $(MOZ_BUNDLE_ID).$(ECOSIA_PRODUCT_NAME) diff --git a/Client/Configuration/EcosiaBetaDebug.xcconfig b/Client/Configuration/EcosiaBetaDebug.xcconfig index 5be6da645a84..336bd8b33139 100644 --- a/Client/Configuration/EcosiaBetaDebug.xcconfig +++ b/Client/Configuration/EcosiaBetaDebug.xcconfig @@ -14,7 +14,7 @@ MOZ_BUNDLE_ID = com.ecosia.ecosiaapp.firefox INCLUDE_SETTINGS_BUNDLE = YES LEANPLUM_ENVIRONMENT = development MOZ_TODAY_WIDGET_SEARCH_DISPLAY_NAME = Ecosia - Search -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/EcosiaBeta.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/EcosiaBeta.entitlements OTHER_SWIFT_FLAGS = $(OTHER_SWIFT_FLAGS_common) -DMOZ_CHANNEL_FENNEC MOZ_INTERNAL_URL_SCHEME = ecosia OTHER_LDFLAGS = -ObjC -lxml2 -fprofile-instr-generate diff --git a/Client/Configuration/EcosiaDebug.ShareTo.xcconfig b/Client/Configuration/EcosiaDebug.ShareTo.xcconfig index 91a515e4ad6c..9422367b8577 100644 --- a/Client/Configuration/EcosiaDebug.ShareTo.xcconfig +++ b/Client/Configuration/EcosiaDebug.ShareTo.xcconfig @@ -3,6 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. PROVISIONING_PROFILE_SPECIFIER = match Development com.ecosia.ecosiaapp.ShareTo -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/AppExtensions/Ecosia.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/AppExtensions/Ecosia.entitlements MOZ_BUNDLE_ID = com.ecosia.ecosiaapp PRODUCT_BUNDLE_IDENTIFIER = $(MOZ_BUNDLE_ID).$(PRODUCT_NAME) diff --git a/Client/Configuration/EcosiaDebug.WidgetKit.xcconfig b/Client/Configuration/EcosiaDebug.WidgetKit.xcconfig index b02d283b8b50..3c7c79d3ea9e 100644 --- a/Client/Configuration/EcosiaDebug.WidgetKit.xcconfig +++ b/Client/Configuration/EcosiaDebug.WidgetKit.xcconfig @@ -6,5 +6,5 @@ ECOSIA_PRODUCT_NAME = WidgetKit PROVISIONING_PROFILE_SPECIFIER = match Development com.ecosia.ecosiaapp.WidgetKit -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/AppExtensions/Ecosia.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/AppExtensions/Ecosia.entitlements PRODUCT_BUNDLE_IDENTIFIER = $(MOZ_BUNDLE_ID).$(ECOSIA_PRODUCT_NAME) diff --git a/Client/Configuration/EcosiaDebug.xcconfig b/Client/Configuration/EcosiaDebug.xcconfig index a26937361b9d..eacb6ca54948 100644 --- a/Client/Configuration/EcosiaDebug.xcconfig +++ b/Client/Configuration/EcosiaDebug.xcconfig @@ -15,7 +15,7 @@ MOZ_BUNDLE_ID = com.ecosia.ecosiaapp INCLUDE_SETTINGS_BUNDLE = YES LEANPLUM_ENVIRONMENT = development MOZ_TODAY_WIDGET_SEARCH_DISPLAY_NAME = Ecosia - Search -CODE_SIGN_ENTITLEMENTS = Client/Ecosia/Entitlements/Ecosia.entitlements +CODE_SIGN_ENTITLEMENTS = Ecosia/Entitlements/Ecosia.entitlements OTHER_SWIFT_FLAGS = $(OTHER_SWIFT_FLAGS_common) -DMOZ_CHANNEL_FENNEC MOZ_INTERNAL_URL_SCHEME = ecosia OTHER_LDFLAGS = -ObjC -lxml2 -fprofile-instr-generate diff --git a/Client/Coordinators/LaunchView/LaunchScreenViewController.swift b/Client/Coordinators/LaunchView/LaunchScreenViewController.swift index 409eb9cffbb9..3570c781ecb1 100644 --- a/Client/Coordinators/LaunchView/LaunchScreenViewController.swift +++ b/Client/Coordinators/LaunchView/LaunchScreenViewController.swift @@ -4,6 +4,8 @@ import Common import Foundation +// Ecosia: Import Ecosia Framework +import Ecosia class LaunchScreenViewController: UIViewController, LaunchFinishedLoadingDelegate { // Ecosia: Custom launch screen diff --git a/Client/Ecosia/Extensions/Toolbar+URLBar/ConnectionStatusImage.swift b/Client/Ecosia/Extensions/Toolbar+URLBar/ConnectionStatusImage.swift index f0b58927d67b..f10587ebfd63 100644 --- a/Client/Ecosia/Extensions/Toolbar+URLBar/ConnectionStatusImage.swift +++ b/Client/Ecosia/Extensions/Toolbar+URLBar/ConnectionStatusImage.swift @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/ -import Foundation +import UIKit struct ConnectionStatusImage { diff --git a/Client/Ecosia/Extensions/UIImage+Ecosia.swift b/Client/Ecosia/Extensions/UIImage+Ecosia.swift new file mode 100644 index 000000000000..bafb63b3c673 --- /dev/null +++ b/Client/Ecosia/Extensions/UIImage+Ecosia.swift @@ -0,0 +1,12 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Foundation + +extension UIImage { + convenience init?(themed name: String) { + let suffix = LegacyThemeManager.instance.current.isDark ? "Dark" : "" + self.init(named: name + suffix) + } +} diff --git a/Client/Ecosia/UI/EcosiaPrimaryButton.swift b/Client/Ecosia/UI/EcosiaPrimaryButton.swift new file mode 100644 index 000000000000..ba561a397107 --- /dev/null +++ b/Client/Ecosia/UI/EcosiaPrimaryButton.swift @@ -0,0 +1,31 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import UIKit + +class EcosiaPrimaryButton: UIButton { + override var isSelected: Bool { + get { + return super.isSelected + } + set { + super.isSelected = newValue + update() + } + } + + override var isHighlighted: Bool { + get { + return super.isHighlighted + } + set { + super.isHighlighted = newValue + update() + } + } + + private func update() { + backgroundColor = (isSelected || isHighlighted) ? .legacyTheme.ecosia.primaryButtonActive : .legacyTheme.ecosia.primaryButton + } +} diff --git a/Client/Ecosia/UI/Theme/EcosiaTheme.swift b/Client/Ecosia/UI/Theme/EcosiaTheme.swift index bfec7cb8629e..ea9f3f1f3470 100644 --- a/Client/Ecosia/UI/Theme/EcosiaTheme.swift +++ b/Client/Ecosia/UI/Theme/EcosiaTheme.swift @@ -5,13 +5,7 @@ import UIKit import Common -extension LegacyTheme { - var isDark: Bool { - return type(of: self) == DarkTheme.self - } -} - -class EcosiaTheme { +public class EcosiaTheme { var primaryBrand: UIColor { .Light.Brand.primary} var secondaryBrand: UIColor { UIColor.Photon.Grey60 } var border: UIColor { .Light.border } @@ -93,7 +87,7 @@ class EcosiaTheme { var peach: UIColor { .init(rgb: 0xFFE6BF) } } -final class DarkEcosiaTheme: EcosiaTheme { +public final class DarkEcosiaTheme: EcosiaTheme { override var primaryBrand: UIColor { .Dark.Brand.primary} override var secondaryBrand: UIColor { .white } override var border: UIColor { .Dark.border } @@ -176,36 +170,3 @@ final class DarkEcosiaTheme: EcosiaTheme { override var homePanelBackground: UIColor { return .Dark.Background.secondary } override var peach: UIColor { .init(rgb: 0xCC7722) } } - -extension UIImage { - convenience init?(themed name: String) { - let suffix = LegacyThemeManager.instance.current.isDark ? "Dark" : "" - self.init(named: name + suffix) - } -} - -class EcosiaPrimaryButton: UIButton { - override var isSelected: Bool { - get { - return super.isSelected - } - set { - super.isSelected = newValue - update() - } - } - - override var isHighlighted: Bool { - get { - return super.isHighlighted - } - set { - super.isHighlighted = newValue - update() - } - } - - private func update() { - backgroundColor = (isSelected || isHighlighted) ? .legacyTheme.ecosia.primaryButtonActive : .legacyTheme.ecosia.primaryButton - } -} diff --git a/Client/Frontend/Theme/LegacyThemeManager/LegacyDarkTheme.swift b/Client/Frontend/Theme/LegacyThemeManager/LegacyDarkTheme.swift index 352e62a521c8..c5142616697b 100644 --- a/Client/Frontend/Theme/LegacyThemeManager/LegacyDarkTheme.swift +++ b/Client/Frontend/Theme/LegacyThemeManager/LegacyDarkTheme.swift @@ -3,6 +3,8 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit +// Ecosia: import Ecosia Framework +import Ecosia private class DarkBrowserColor: BrowserColor { override var background: UIColor { return UIColor.Photon.DarkGrey60 } diff --git a/Client/Frontend/Theme/LegacyThemeManager/LegacyTheme.swift b/Client/Frontend/Theme/LegacyThemeManager/LegacyTheme.swift index 3f0f4fc19d6e..d633ca83c6ac 100644 --- a/Client/Frontend/Theme/LegacyThemeManager/LegacyTheme.swift +++ b/Client/Frontend/Theme/LegacyThemeManager/LegacyTheme.swift @@ -5,6 +5,8 @@ import Common import UIKit import Shared +// Ecosia: import Ecosia Framework +import Ecosia protocol PrivateModeUI { func applyUIMode(isPrivate: Bool, theme: Theme) @@ -61,3 +63,10 @@ class LegacyNormalTheme: LegacyTheme { // Ecosia: Adapt theme var ecosia: EcosiaTheme { return EcosiaTheme() } } + +// Ecosia: Add `isDark` extension as previously part of the `EcosiaTheme` class +extension LegacyTheme { + var isDark: Bool { + return type(of: self) == DarkTheme.self + } +} diff --git a/Ecosia/Analytics/Analytics.swift b/Ecosia/Analytics/Analytics.swift index 30fe0db5879e..e0755e81c666 100644 --- a/Ecosia/Analytics/Analytics.swift +++ b/Ecosia/Analytics/Analytics.swift @@ -39,7 +39,7 @@ open class Analytics { self.notificationCenter = notificationCenter } - private func track(_ event: Event) { + private func track(_ event: SnowplowTracker.Event) { guard User.shared.sendAnonymousUsageData else { return } _ = tracker.track(event) } diff --git a/Client/Ecosia/Entitlements/AppExtensions/Ecosia.entitlements b/Ecosia/Entitlements/AppExtensions/Ecosia.entitlements similarity index 100% rename from Client/Ecosia/Entitlements/AppExtensions/Ecosia.entitlements rename to Ecosia/Entitlements/AppExtensions/Ecosia.entitlements diff --git a/Client/Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements b/Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements similarity index 100% rename from Client/Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements rename to Ecosia/Entitlements/AppExtensions/EcosiaBeta.entitlements diff --git a/Client/Ecosia/Entitlements/Ecosia.entitlements b/Ecosia/Entitlements/Ecosia.entitlements similarity index 100% rename from Client/Ecosia/Entitlements/Ecosia.entitlements rename to Ecosia/Entitlements/Ecosia.entitlements diff --git a/Client/Ecosia/Entitlements/EcosiaBeta.entitlements b/Ecosia/Entitlements/EcosiaBeta.entitlements similarity index 100% rename from Client/Ecosia/Entitlements/EcosiaBeta.entitlements rename to Ecosia/Entitlements/EcosiaBeta.entitlements diff --git a/Ecosia/Extensions/AppInfo+Ecosia.swift b/Ecosia/Extensions/AppInfo+Ecosia.swift index d12dfe864db2..e699228c1285 100644 --- a/Ecosia/Extensions/AppInfo+Ecosia.swift +++ b/Ecosia/Extensions/AppInfo+Ecosia.swift @@ -17,7 +17,7 @@ extension AppInfo { /// Only available for iOS 14.3 and later (will return nil on earlier versions). /// Returns nil after the first time, so that no unwanted new token is generated. /// If an error is caught, it will return nil and retry next time it is fetched. - public static var adServicesAttributionToken: String? { + static var adServicesAttributionToken: String? { guard #available(iOS 14.3, *), !UserDefaults.standard.bool(forKey: hasAttributedAppleSearchDownloadKey) else { return nil diff --git a/Client/Ecosia/Extensions/DeviceInfo+Ecosia.swift b/Ecosia/Extensions/DeviceInfo+Ecosia.swift similarity index 99% rename from Client/Ecosia/Extensions/DeviceInfo+Ecosia.swift rename to Ecosia/Extensions/DeviceInfo+Ecosia.swift index 934e2c6a8f7e..6012a0569cd1 100644 --- a/Client/Ecosia/Extensions/DeviceInfo+Ecosia.swift +++ b/Ecosia/Extensions/DeviceInfo+Ecosia.swift @@ -5,6 +5,7 @@ import Foundation import Shared import Common +import UIKit extension DeviceInfo { diff --git a/Client/Ecosia/Fake/FakeNimbus.swift b/Ecosia/Fake/FakeNimbus.swift similarity index 100% rename from Client/Ecosia/Fake/FakeNimbus.swift rename to Ecosia/Fake/FakeNimbus.swift diff --git a/Client/Ecosia/Fake/FakeSentry.swift b/Ecosia/Fake/FakeSentry.swift similarity index 100% rename from Client/Ecosia/Fake/FakeSentry.swift rename to Ecosia/Fake/FakeSentry.swift diff --git a/Client/Ecosia/Fake/FakeTelemetry.swift b/Ecosia/Fake/FakeTelemetry.swift similarity index 100% rename from Client/Ecosia/Fake/FakeTelemetry.swift rename to Ecosia/Fake/FakeTelemetry.swift diff --git a/Client/Ecosia/FeatureManagement/FeatureManagement.swift b/Ecosia/FeatureManagement/FeatureManagement.swift similarity index 93% rename from Client/Ecosia/FeatureManagement/FeatureManagement.swift rename to Ecosia/FeatureManagement/FeatureManagement.swift index eb9d8a8fcf55..3b6431f0ef86 100644 --- a/Client/Ecosia/FeatureManagement/FeatureManagement.swift +++ b/Ecosia/FeatureManagement/FeatureManagement.swift @@ -6,7 +6,7 @@ import Foundation import Common import Core -struct FeatureManagement { +public struct FeatureManagement { // MARK: - Initialization @@ -15,7 +15,7 @@ struct FeatureManagement { // MARK: - Configuration /// Fetches the feature configuration asynchronously. - static func fetchConfiguration() async { + public static func fetchConfiguration() async { do { try await start() } catch { diff --git a/Client/Ecosia/L10N/Scripts/Clean.swift b/Ecosia/L10N/Scripts/Clean.swift similarity index 100% rename from Client/Ecosia/L10N/Scripts/Clean.swift rename to Ecosia/L10N/Scripts/Clean.swift diff --git a/Client/Ecosia/L10N/Scripts/Validate.swift b/Ecosia/L10N/Scripts/Validate.swift similarity index 100% rename from Client/Ecosia/L10N/Scripts/Validate.swift rename to Ecosia/L10N/Scripts/Validate.swift diff --git a/Client/Ecosia/L10N/String.swift b/Ecosia/L10N/String.swift similarity index 98% rename from Client/Ecosia/L10N/String.swift rename to Ecosia/L10N/String.swift index 0913a4c34657..3f967a2b510a 100644 --- a/Client/Ecosia/L10N/String.swift +++ b/Ecosia/L10N/String.swift @@ -6,19 +6,19 @@ import Foundation import Core extension String { - static func localized(_ key: Key) -> String { + public static func localized(_ key: Key) -> String { localized(key.rawValue) } - static func localized(_ string: String) -> String { + public static func localized(_ string: String) -> String { NSLocalizedString(string, tableName: "Ecosia", comment: "") } - static func localizedPlural(_ key: Key, num: Int) -> String { + public static func localizedPlural(_ key: Key, num: Int) -> String { String(format: NSLocalizedString(key.rawValue, tableName: "Plurals", comment: ""), num) } - enum Key: String { + public enum Key: String { case allRegions = "All regions" case autocomplete = "Autocomplete" case climateImpact = "Climate Impact" diff --git a/Client/Ecosia/L10N/de.lproj/Ecosia.strings b/Ecosia/L10N/de.lproj/Ecosia.strings similarity index 100% rename from Client/Ecosia/L10N/de.lproj/Ecosia.strings rename to Ecosia/L10N/de.lproj/Ecosia.strings diff --git a/Client/Ecosia/L10N/de.lproj/Plurals.stringsdict b/Ecosia/L10N/de.lproj/Plurals.stringsdict similarity index 100% rename from Client/Ecosia/L10N/de.lproj/Plurals.stringsdict rename to Ecosia/L10N/de.lproj/Plurals.stringsdict diff --git a/Client/Ecosia/L10N/en.lproj/Ecosia.strings b/Ecosia/L10N/en.lproj/Ecosia.strings similarity index 100% rename from Client/Ecosia/L10N/en.lproj/Ecosia.strings rename to Ecosia/L10N/en.lproj/Ecosia.strings diff --git a/Client/Ecosia/L10N/en.lproj/Plurals.stringsdict b/Ecosia/L10N/en.lproj/Plurals.stringsdict similarity index 100% rename from Client/Ecosia/L10N/en.lproj/Plurals.stringsdict rename to Ecosia/L10N/en.lproj/Plurals.stringsdict diff --git a/Client/Ecosia/L10N/es.lproj/Ecosia.strings b/Ecosia/L10N/es.lproj/Ecosia.strings similarity index 100% rename from Client/Ecosia/L10N/es.lproj/Ecosia.strings rename to Ecosia/L10N/es.lproj/Ecosia.strings diff --git a/Client/Ecosia/L10N/es.lproj/Plurals.stringsdict b/Ecosia/L10N/es.lproj/Plurals.stringsdict similarity index 100% rename from Client/Ecosia/L10N/es.lproj/Plurals.stringsdict rename to Ecosia/L10N/es.lproj/Plurals.stringsdict diff --git a/Client/Ecosia/L10N/fr.lproj/Ecosia.strings b/Ecosia/L10N/fr.lproj/Ecosia.strings similarity index 100% rename from Client/Ecosia/L10N/fr.lproj/Ecosia.strings rename to Ecosia/L10N/fr.lproj/Ecosia.strings diff --git a/Client/Ecosia/L10N/fr.lproj/Plurals.stringsdict b/Ecosia/L10N/fr.lproj/Plurals.stringsdict similarity index 100% rename from Client/Ecosia/L10N/fr.lproj/Plurals.stringsdict rename to Ecosia/L10N/fr.lproj/Plurals.stringsdict diff --git a/Client/Ecosia/L10N/it.lproj/Ecosia.strings b/Ecosia/L10N/it.lproj/Ecosia.strings similarity index 100% rename from Client/Ecosia/L10N/it.lproj/Ecosia.strings rename to Ecosia/L10N/it.lproj/Ecosia.strings diff --git a/Client/Ecosia/L10N/it.lproj/Plurals.stringsdict b/Ecosia/L10N/it.lproj/Plurals.stringsdict similarity index 100% rename from Client/Ecosia/L10N/it.lproj/Plurals.stringsdict rename to Ecosia/L10N/it.lproj/Plurals.stringsdict diff --git a/Client/Ecosia/L10N/nl.lproj/Ecosia.strings b/Ecosia/L10N/nl.lproj/Ecosia.strings similarity index 100% rename from Client/Ecosia/L10N/nl.lproj/Ecosia.strings rename to Ecosia/L10N/nl.lproj/Ecosia.strings diff --git a/Client/Ecosia/L10N/nl.lproj/Plurals.stringsdict b/Ecosia/L10N/nl.lproj/Plurals.stringsdict similarity index 100% rename from Client/Ecosia/L10N/nl.lproj/Plurals.stringsdict rename to Ecosia/L10N/nl.lproj/Plurals.stringsdict diff --git a/Client/Ecosia/LaunchScreen/EcosiaLaunchScreen.xib b/Ecosia/LaunchScreen/EcosiaLaunchScreen.xib similarity index 100% rename from Client/Ecosia/LaunchScreen/EcosiaLaunchScreen.xib rename to Ecosia/LaunchScreen/EcosiaLaunchScreen.xib diff --git a/Client/Ecosia/LaunchScreen/EcosiaLaunchScreenView.swift b/Ecosia/LaunchScreen/EcosiaLaunchScreenView.swift similarity index 86% rename from Client/Ecosia/LaunchScreen/EcosiaLaunchScreenView.swift rename to Ecosia/LaunchScreen/EcosiaLaunchScreenView.swift index 094e5e1a19b0..a17d3944d0c2 100644 --- a/Client/Ecosia/LaunchScreen/EcosiaLaunchScreenView.swift +++ b/Ecosia/LaunchScreen/EcosiaLaunchScreenView.swift @@ -5,10 +5,10 @@ import UIKit /// LaunchScreen is the LaunchScreen.xib we show at launch, but loaded programmatically -class EcosiaLaunchScreenView: UIView { +public class EcosiaLaunchScreenView: UIView { private static let viewName = "EcosiaLaunchScreen" - class func fromNib() -> UIView { + public class func fromNib() -> UIView { return Bundle.main.loadNibNamed(EcosiaLaunchScreenView.viewName, owner: nil, options: nil)![0] as! UIView diff --git a/Client/Ecosia/MMP/MMP.swift b/Ecosia/MMP/MMP.swift similarity index 92% rename from Client/Ecosia/MMP/MMP.swift rename to Ecosia/MMP/MMP.swift index 1234a10d7147..cbf3a8440838 100644 --- a/Client/Ecosia/MMP/MMP.swift +++ b/Ecosia/MMP/MMP.swift @@ -8,7 +8,7 @@ import Shared import AdServices import Common -struct MMP { +public struct MMP { private init() {} @@ -29,7 +29,7 @@ struct MMP { adServicesAttributionToken: AppInfo.adServicesAttributionToken) } - static func sendSession() { + public static func sendSession() { guard User.shared.sendAnonymousUsageData else { return } Task { @@ -42,7 +42,7 @@ struct MMP { } } - static func sendEvent(_ event: MMPEvent) { + public static func sendEvent(_ event: MMPEvent) { guard User.shared.sendAnonymousUsageData else { return } Task { @@ -55,7 +55,7 @@ struct MMP { } } - static func handleSearchEvent(_ count: Int) { + public static func handleSearchEvent(_ count: Int) { let eventMap: [Int: MMPEvent] = [1: .firstSearch, 5: .fifthSearch, 10: .tenthSearch] if let event = eventMap[count] { self.sendEvent(event) diff --git a/Ecosia/UI/NTP/ClimateImpactCounter/CoreData/SeedCounter.xcdatamodeld/SeedCounter.xcdatamodel/contents b/Ecosia/UI/NTP/ClimateImpactCounter/CoreData/SeedCounter.xcdatamodeld/SeedCounter.xcdatamodel/contents new file mode 100644 index 000000000000..f48c6ec4dcd0 --- /dev/null +++ b/Ecosia/UI/NTP/ClimateImpactCounter/CoreData/SeedCounter.xcdatamodeld/SeedCounter.xcdatamodel/contents @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Client/Ecosia/markets.json b/Ecosia/markets.json similarity index 100% rename from Client/Ecosia/markets.json rename to Ecosia/markets.json diff --git a/EcosiaTests/BrazeServiceTests.swift b/EcosiaTests/BrazeServiceTests.swift index 9f6128aa2e42..0d3b642ed12c 100644 --- a/EcosiaTests/BrazeServiceTests.swift +++ b/EcosiaTests/BrazeServiceTests.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import XCTest -@testable import Client +@testable import Ecosia final class BrazeServiceTests: XCTestCase { var brazeService: BrazeService! From 4abc85f6dba2d7e41ca1ef8bd9a091e89ca774a1 Mon Sep 17 00:00:00 2001 From: Dario Carlomagno Date: Wed, 4 Dec 2024 16:59:35 +0100 Subject: [PATCH 12/59] [MOB-3028] Add Bundle+Ecosia, move LaunchScreen to Client/Ecosia/UI --- Client.xcodeproj/project.pbxproj | 36 ++++++++++--------- .../UI}/LaunchScreen/EcosiaLaunchScreen.xib | 0 .../LaunchScreen/EcosiaLaunchScreenView.swift | 2 +- Ecosia/Extensions/Bundle+Ecosia.swift | 11 ++++++ .../SeedCounter.xcdatamodel/contents | 8 ----- 5 files changed, 32 insertions(+), 25 deletions(-) rename {Ecosia => Client/Ecosia/UI}/LaunchScreen/EcosiaLaunchScreen.xib (100%) rename {Ecosia => Client/Ecosia/UI}/LaunchScreen/EcosiaLaunchScreenView.swift (85%) create mode 100644 Ecosia/Extensions/Bundle+Ecosia.swift delete mode 100644 Ecosia/UI/NTP/ClimateImpactCounter/CoreData/SeedCounter.xcdatamodeld/SeedCounter.xcdatamodel/contents diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index 3de7dbd1d3cc..86292dae3080 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -233,6 +233,9 @@ 2C6C908F2C614A6C007D9B43 /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 2C6C908E2C614A6C007D9B43 /* SnapshotTesting */; }; 2C872A552B8CD58200B318A0 /* ContileProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A7A93ED2810ADF2005E7E1B /* ContileProviderTests.swift */; }; 2CABD7162C11C9CC00A0750F /* MozillaAppServices in Frameworks */ = {isa = PBXBuildFile; productRef = 2CABD7152C11C9CC00A0750F /* MozillaAppServices */; }; + 2CAF5AE32D00AAEE00D3DCDD /* Bundle+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AE22D00AAEE00D3DCDD /* Bundle+Ecosia.swift */; }; + 2CAF5AE72D00B1D300D3DCDD /* EcosiaLaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CAF5AE42D00B1D300D3DCDD /* EcosiaLaunchScreen.xib */; }; + 2CAF5AE82D00B1D300D3DCDD /* EcosiaLaunchScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AE52D00B1D300D3DCDD /* EcosiaLaunchScreenView.swift */; }; 2CCFB3D72C0FBEE800BEDCA0 /* TabToolbarHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D815A3A724A53F3200AAB221 /* TabToolbarHelperTests.swift */; }; 2CD262A92CFDC5EB00A040A7 /* EcosiaMockThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261842CFDC5E900A040A7 /* EcosiaMockThemeManager.swift */; }; 2CD262AA2CFDC5EB00A040A7 /* Welcome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261852CFDC5E900A040A7 /* Welcome.swift */; }; @@ -537,8 +540,6 @@ 2CD264A12CFDC76A00A040A7 /* Analytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263EC2CFDC76800A040A7 /* Analytics.swift */; }; 2CD264A22CFDC76A00A040A7 /* Analytics.Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263ED2CFDC76800A040A7 /* Analytics.Values.swift */; }; 2CD264A32CFDC76A00A040A7 /* Analytics+Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263EE2CFDC76800A040A7 /* Analytics+Configuration.swift */; }; - 2CD264A42CFDC76A00A040A7 /* EcosiaLaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263F02CFDC76800A040A7 /* EcosiaLaunchScreen.xib */; }; - 2CD264A52CFDC76A00A040A7 /* EcosiaLaunchScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263F12CFDC76800A040A7 /* EcosiaLaunchScreenView.swift */; }; 2CD264A92CFDC76A00A040A7 /* markets.json in Resources */ = {isa = PBXBuildFile; fileRef = 2CD263F72CFDC76900A040A7 /* markets.json */; }; 2CD264AC2CFDC76A00A040A7 /* FeatureManagement.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD263FE2CFDC76900A040A7 /* FeatureManagement.swift */; }; 2CD264AD2CFDC76A00A040A7 /* MMP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD264002CFDC76900A040A7 /* MMP.swift */; }; @@ -2673,6 +2674,9 @@ 2C97EC701E72C80E0092EC18 /* TopTabsTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopTabsTest.swift; sourceTree = ""; }; 2CA16FDD1E5F089100332277 /* SearchTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchTest.swift; sourceTree = ""; }; 2CAE4511992E91A32AB7D7C7 /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = th; path = th.lproj/Today.strings; sourceTree = ""; }; + 2CAF5AE22D00AAEE00D3DCDD /* Bundle+Ecosia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Ecosia.swift"; sourceTree = ""; }; + 2CAF5AE42D00B1D300D3DCDD /* EcosiaLaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EcosiaLaunchScreen.xib; sourceTree = ""; }; + 2CAF5AE52D00B1D300D3DCDD /* EcosiaLaunchScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaLaunchScreenView.swift; sourceTree = ""; }; 2CB1728B2C61336D008551E2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; 2CB1A6591FDEA8B60084E96D /* NewTabSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabSettings.swift; sourceTree = ""; }; 2CB56E3E1E926BFB00AF7586 /* ToolbarTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarTest.swift; sourceTree = ""; }; @@ -3004,8 +3008,6 @@ 2CD263EC2CFDC76800A040A7 /* Analytics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Analytics.swift; sourceTree = ""; }; 2CD263ED2CFDC76800A040A7 /* Analytics.Values.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Analytics.Values.swift; sourceTree = ""; }; 2CD263EE2CFDC76800A040A7 /* Analytics+Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Analytics+Configuration.swift"; sourceTree = ""; }; - 2CD263F02CFDC76800A040A7 /* EcosiaLaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EcosiaLaunchScreen.xib; sourceTree = ""; }; - 2CD263F12CFDC76800A040A7 /* EcosiaLaunchScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaLaunchScreenView.swift; sourceTree = ""; }; 2CD263F72CFDC76900A040A7 /* markets.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = markets.json; sourceTree = ""; }; 2CD263FE2CFDC76900A040A7 /* FeatureManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureManagement.swift; sourceTree = ""; }; 2CD264002CFDC76900A040A7 /* MMP.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MMP.swift; sourceTree = ""; }; @@ -8547,7 +8549,6 @@ 2CD263FF2CFDC76900A040A7 /* FeatureManagement */, 2CD263EB2CFDC76800A040A7 /* Helpers */, 2CD263E12CFDC76800A040A7 /* L10N */, - 2CD263F22CFDC76800A040A7 /* LaunchScreen */, 2CD263F72CFDC76900A040A7 /* markets.json */, 2CD264012CFDC76900A040A7 /* MMP */, 1229356C2CE78D0A00EC1297 /* Ecosia.h */, @@ -8995,6 +8996,15 @@ path = PersistedGenerated; sourceTree = ""; }; + 2CAF5AE62D00B1D300D3DCDD /* LaunchScreen */ = { + isa = PBXGroup; + children = ( + 2CAF5AE42D00B1D300D3DCDD /* EcosiaLaunchScreen.xib */, + 2CAF5AE52D00B1D300D3DCDD /* EcosiaLaunchScreenView.swift */, + ); + path = LaunchScreen; + sourceTree = ""; + }; 2CBCAAFA2B88EEE40080AD68 /* Configuration */ = { isa = PBXGroup; children = ( @@ -9476,15 +9486,6 @@ path = Analytics; sourceTree = ""; }; - 2CD263F22CFDC76800A040A7 /* LaunchScreen */ = { - isa = PBXGroup; - children = ( - 2CD263F02CFDC76800A040A7 /* EcosiaLaunchScreen.xib */, - 2CD263F12CFDC76800A040A7 /* EcosiaLaunchScreenView.swift */, - ); - path = LaunchScreen; - sourceTree = ""; - }; 2CD263FF2CFDC76900A040A7 /* FeatureManagement */ = { isa = PBXGroup; children = ( @@ -9786,6 +9787,7 @@ 2CD265C32CFE382C00A040A7 /* UI */ = { isa = PBXGroup; children = ( + 2CAF5AE62D00B1D300D3DCDD /* LaunchScreen */, 2CD265672CFE382C00A040A7 /* MultiplyImpact */, 2CD2659C2CFE382C00A040A7 /* NTP */, 2CD265A62CFE382C00A040A7 /* Onboarding */, @@ -9900,6 +9902,7 @@ children = ( 2CD2663D2CFF4ED000A040A7 /* DeviceInfo+Ecosia.swift */, 2CD2663B2CFE423D00A040A7 /* AppInfo+Ecosia.swift */, + 2CAF5AE22D00AAEE00D3DCDD /* Bundle+Ecosia.swift */, ); path = Extensions; sourceTree = ""; @@ -14007,7 +14010,6 @@ buildActionMask = 2147483647; files = ( 2CD264972CFDC76A00A040A7 /* Plurals.stringsdict in Resources */, - 2CD264A42CFDC76A00A040A7 /* EcosiaLaunchScreen.xib in Resources */, 2CD264982CFDC76A00A040A7 /* Plurals.stringsdict in Resources */, 2CD264992CFDC76A00A040A7 /* Plurals.stringsdict in Resources */, 2CD264922CFDC76A00A040A7 /* Ecosia.strings in Resources */, @@ -14397,6 +14399,7 @@ F35B8D2B1D6380EA008E3D61 /* SessionRestore.html in Resources */, 7B42406E1CA04CAC009B5C28 /* Menu.xcassets in Resources */, 4336FAD2264B169000A6B076 /* WebcompatAllFramesAtDocumentStart.js in Resources */, + 2CAF5AE72D00B1D300D3DCDD /* EcosiaLaunchScreen.xib in Resources */, 23BEA767251A99ED00A014BF /* NewYorkMedium-Bold.otf in Resources */, 3BC659591E5BA505006D560F /* bundle_sites.json in Resources */, E4CD9F541A71506400318571 /* Reader.html in Resources */, @@ -14646,7 +14649,6 @@ 2CD265012CFDC76A00A040A7 /* FakeTelemetry.swift in Sources */, 2CD2649B2CFDC76A00A040A7 /* AppVersionInfoProvider.swift in Sources */, 2CD266332CFE403800A040A7 /* BrazeIntegrationExperiment.swift in Sources */, - 2CD264A52CFDC76A00A040A7 /* EcosiaLaunchScreenView.swift in Sources */, 2CD2649F2CFDC76A00A040A7 /* Version.swift in Sources */, 2CD264A32CFDC76A00A040A7 /* Analytics+Configuration.swift in Sources */, 2CD2649D2CFDC76A00A040A7 /* EcosiaInstallType.swift in Sources */, @@ -14654,6 +14656,7 @@ 2CD265002CFDC76A00A040A7 /* FakeSentry.swift in Sources */, 2CD2649E2CFDC76A00A040A7 /* EcosiaInstallType+Extensions.swift in Sources */, 2CD264A22CFDC76A00A040A7 /* Analytics.Values.swift in Sources */, + 2CAF5AE32D00AAEE00D3DCDD /* Bundle+Ecosia.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -15702,6 +15705,7 @@ D5D237782640BBA600326204 /* ExperimentsSettingsViewController.swift in Sources */, 2CD266072CFE382C00A040A7 /* EcosiaNavigation.swift in Sources */, D3972BF31C22412B00035B87 /* ShareExtensionHelper.swift in Sources */, + 2CAF5AE82D00B1D300D3DCDD /* EcosiaLaunchScreenView.swift in Sources */, F35B8D2D1D6383E9008E3D61 /* SessionRestoreHelper.swift in Sources */, 8A19ACB62A3290F9001C2147 /* NotificationsSetting.swift in Sources */, 43D16B8229831E6A009F8279 /* CreditCardInputField.swift in Sources */, diff --git a/Ecosia/LaunchScreen/EcosiaLaunchScreen.xib b/Client/Ecosia/UI/LaunchScreen/EcosiaLaunchScreen.xib similarity index 100% rename from Ecosia/LaunchScreen/EcosiaLaunchScreen.xib rename to Client/Ecosia/UI/LaunchScreen/EcosiaLaunchScreen.xib diff --git a/Ecosia/LaunchScreen/EcosiaLaunchScreenView.swift b/Client/Ecosia/UI/LaunchScreen/EcosiaLaunchScreenView.swift similarity index 85% rename from Ecosia/LaunchScreen/EcosiaLaunchScreenView.swift rename to Client/Ecosia/UI/LaunchScreen/EcosiaLaunchScreenView.swift index a17d3944d0c2..d468aa5a0b05 100644 --- a/Ecosia/LaunchScreen/EcosiaLaunchScreenView.swift +++ b/Client/Ecosia/UI/LaunchScreen/EcosiaLaunchScreenView.swift @@ -4,7 +4,7 @@ import UIKit -/// LaunchScreen is the LaunchScreen.xib we show at launch, but loaded programmatically +/// LaunchScreen is the EcosiaLaunchScreen.xib we show at launch, but loaded programmatically public class EcosiaLaunchScreenView: UIView { private static let viewName = "EcosiaLaunchScreen" diff --git a/Ecosia/Extensions/Bundle+Ecosia.swift b/Ecosia/Extensions/Bundle+Ecosia.swift new file mode 100644 index 000000000000..4ef57f95f229 --- /dev/null +++ b/Ecosia/Extensions/Bundle+Ecosia.swift @@ -0,0 +1,11 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Foundation + +extension Bundle { + static var ecosia: Bundle { + Bundle(identifier: "com.ecosia.framework.Ecosia")! + } +} diff --git a/Ecosia/UI/NTP/ClimateImpactCounter/CoreData/SeedCounter.xcdatamodeld/SeedCounter.xcdatamodel/contents b/Ecosia/UI/NTP/ClimateImpactCounter/CoreData/SeedCounter.xcdatamodeld/SeedCounter.xcdatamodel/contents deleted file mode 100644 index f48c6ec4dcd0..000000000000 --- a/Ecosia/UI/NTP/ClimateImpactCounter/CoreData/SeedCounter.xcdatamodeld/SeedCounter.xcdatamodel/contents +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file From 6b0ffa773ec6572c74241f3525a9c91e0e9f0978 Mon Sep 17 00:00:00 2001 From: Dario Carlomagno Date: Wed, 4 Dec 2024 17:01:35 +0100 Subject: [PATCH 13/59] [MOB-3028] Update Info.plist to specify variables like other targets --- Client/Info.plist | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Client/Info.plist b/Client/Info.plist index f35c168b2570..207256a8dacb 100644 --- a/Client/Info.plist +++ b/Client/Info.plist @@ -15,6 +15,14 @@ BRAZE_API_KEY $(BRAZE_API_KEY) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(MARKETING_VERSION) CFBundleSignature ???? CFBundleURLTypes @@ -31,6 +39,8 @@ + CFBundleVersion + 1 CF_ACCESS_CLIENT_ID $(CF_ACCESS_CLIENT_ID) CF_ACCESS_CLIENT_SECRET @@ -148,6 +158,8 @@ UIFileSharingEnabled + UILaunchStoryboardName + EcosiaLaunchScreen.xib UIViewControllerBasedStatusBarAppearance UTImportedTypeDeclarations From 43d0467c253047908ae7fc1e6a29854809364bf5 Mon Sep 17 00:00:00 2001 From: Dario Carlomagno Date: Wed, 4 Dec 2024 17:04:44 +0100 Subject: [PATCH 14/59] [MOB-3028] Add comments to Info.plist --- Client/Info.plist | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Client/Info.plist b/Client/Info.plist index 207256a8dacb..4f44cc3ff7a1 100644 --- a/Client/Info.plist +++ b/Client/Info.plist @@ -15,6 +15,10 @@ BRAZE_API_KEY $(BRAZE_API_KEY) + CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -23,6 +27,14 @@ APPL CFBundleShortVersionString $(MARKETING_VERSION) + CFBundleVersion + 1 + UILaunchStoryboardName + EcosiaLaunchScreen.xib + CFBundleSignature ???? CFBundleURLTypes @@ -39,8 +51,6 @@ - CFBundleVersion - 1 CF_ACCESS_CLIENT_ID $(CF_ACCESS_CLIENT_ID) CF_ACCESS_CLIENT_SECRET @@ -158,8 +168,6 @@ UIFileSharingEnabled - UILaunchStoryboardName - EcosiaLaunchScreen.xib UIViewControllerBasedStatusBarAppearance UTImportedTypeDeclarations From f64e7ee43d23278f1a6dc543d597d27b47399fee Mon Sep 17 00:00:00 2001 From: Dario Carlomagno Date: Thu, 5 Dec 2024 11:45:58 +0100 Subject: [PATCH 15/59] [MOB-3028] Build succeed with Core as part of the main project --- .swiftlint.yml | 2 + .../BundleImageFetcher.swift | 8 +- Client.xcodeproj/project.pbxproj | 850 ++++++++++++++++-- .../xcshareddata/swiftpm/Package.resolved | 13 +- Client/Application/AppDelegate.swift | 2 - .../Browser/BrowserCoordinator.swift | 4 +- .../Coordinators/Scene/SceneCoordinator.swift | 4 +- .../Ecosia/Bookmarks/BookmarksExchange.swift | 9 +- .../Unleash/SeedCounterNTPExperiment.swift | 1 - .../BrowserCoordinator+Ecosia.swift | 1 - .../BrowserViewController+Ecosia.swift | 2 +- .../HomepageViewController+Ecosia.swift | 2 +- .../Ecosia/Settings/EcosiaDebugSettings.swift | 2 +- Client/Ecosia/Settings/EcosiaSettings.swift | 2 +- Client/Ecosia/UI/FilterController.swift | 2 +- Client/Ecosia/UI/LoadingScreen.swift | 2 +- Client/Ecosia/UI/MarketsController.swift | 1 - .../UI/MultiplyImpact/MultiplyImpact.swift | 2 +- .../NTP/AboutEcosia/AboutEcosiaSection.swift | 1 - .../NTPAboutEcosiaCellViewModel.swift | 2 +- .../NTPSeedCounterCell.swift | 2 +- .../SeedCounterHiddenSettings.swift | 2 +- .../CustomizableNTPSettingConfig.swift | 1 - .../UI/NTP/Impact/ClimateImpactInfo.swift | 1 - .../Ecosia/UI/NTP/Impact/NTPImpactCell.swift | 2 +- .../NTP/Impact/NTPImpactCellViewModel.swift | 2 +- .../NTP/Library/NTPLibaryCellViewModel.swift | 2 +- Client/Ecosia/UI/NTP/Logo/NTPLogoCell.swift | 2 +- Client/Ecosia/UI/NTP/NTPLayout.swift | 2 +- .../Ecosia/UI/NTP/NTPTooltip.Highlight.swift | 4 +- Client/Ecosia/UI/NTP/News/NTPNewsCell.swift | 2 +- .../UI/NTP/News/NTPNewsCellViewModel.swift | 2 +- .../Ecosia/UI/NTP/News/NewsController.swift | 1 - .../NTPConfigurableNudgeCardCell.swift | 2 +- Client/Ecosia/UI/Onboarding/Welcome.swift | 2 +- .../UI/Onboarding/WelcomeTour.Step.swift | 2 +- Client/Ecosia/UI/Onboarding/WelcomeTour.swift | 2 +- .../UI/Onboarding/WelcomeTourAction.swift | 2 +- .../Onboarding/WelcomeTourTransparent.swift | 2 +- .../WhatsNewLocalDataProvider.swift | 2 +- Client/Ecosia/UI/WhatsNew/WhatsNewCell.swift | 2 +- .../UI/WhatsNew/WhatsNewViewController.swift | 2 +- .../Views/BrowserViewController.swift | 4 +- .../Browser/MainMenuActionHelper.swift | 2 +- .../Browser/MetadataParserHelper.swift | 1 - .../Home/HomepageViewController.swift | 4 +- Client/Frontend/Home/HomepageViewModel.swift | 2 +- .../Home/TopSites/TopSitesViewModel.swift | 3 +- .../Library/Bookmarks/BookmarksPanel.swift | 2 +- .../Bookmarks/BookmarksPanelViewModel.swift | 9 +- .../HomePageSettingViewController.swift | 4 +- .../UserScriptManager.swift | 4 +- Client/IntroScreenManager.swift | 4 +- .../Legacy/LegacyTabManager.swift | 4 +- .../Analytics/Analytics+Configuration.swift | 1 - Ecosia/Analytics/Analytics.swift | 1 - Ecosia/Core/AdultFilter.swift | 8 + Ecosia/Core/AppDeviceInfo.swift | 44 + Ecosia/Core/Bookmarks/Bookmark.swift | 29 + Ecosia/Core/Bookmarks/BookmarkParser.swift | 94 ++ .../Core/Bookmarks/BookmarkSerializer.swift | 81 ++ Ecosia/Core/Bookmarks/Document+Safari.swift | 29 + Ecosia/Core/Bookmarks/String+CssQuery.swift | 11 + Ecosia/{ => Core}/Braze/APNConsent.swift | 0 Ecosia/{ => Core}/Braze/BrazeService.swift | 1 - Ecosia/Core/Bundle.swift | 7 + Ecosia/Core/CloudFlareKeyProvider.swift | 8 + Ecosia/Core/Cookie.swift | 182 ++++ Ecosia/Core/Date+TimestampProvider.swift | 7 + Ecosia/Core/Encodable+Dictionary.swift | 7 + .../Core/Environment/Environment.Auth.swift | 23 + Ecosia/Core/Environment/Environment.swift | 29 + Ecosia/Core/Environment/URLProvider.swift | 154 ++++ Ecosia/Core/EnvironmentFetcher.swift | 24 + Ecosia/Core/Favourites.swift | 13 + .../FeatureManagementSessionInitializer.swift | 6 + .../RefreshingRule/AppUpdateRule.swift | 14 + .../DeviceRegionChangeRule.swift | 14 + .../RefreshingRule/RefreshingRule.swift | 3 + .../TimeBasedRefreshingRule.swift | 16 + .../Unleash/Unleash+RefreshComponent.swift | 16 + .../Unleash/Unleash.Model.swift | 53 ++ .../FeatureManagement/Unleash/Unleash.swift | 153 ++++ ...hFeatureManagementSessionInitializer.swift | 52 ++ .../Unleash/UnleashRefreshConfigurator.swift | 27 + .../Unleash/UnleashStartRequest.swift | 22 + Ecosia/Core/FileManager.swift | 21 + Ecosia/Core/HTTPClient/HTTPClient.swift | 8 + Ecosia/Core/HTTPClient/HTTPMethod.swift | 6 + .../HTTPClient/Requestable/BaseRequest.swift | 49 + .../HTTPClient/Requestable/Requestable.swift | 20 + .../HTTPClient/URLSessionHTTPClient.swift | 11 + .../Core/HTTPClient/URLSessionProtocol.swift | 7 + Ecosia/Core/History.swift | 30 + Ecosia/Core/Images.swift | 63 ++ Ecosia/Core/Language.swift | 38 + Ecosia/Core/List.swift | 18 + Ecosia/Core/Local.swift | 88 ++ Ecosia/Core/Locale+Extensions.swift | 22 + Ecosia/{ => Core}/MMP/MMP.swift | 10 +- Ecosia/Core/MMP/MMPProvider.swift | 8 + Ecosia/Core/MMP/SKAdNetworkProtocol.swift | 35 + .../SingularConversionValueRequest.swift | 49 + .../SingularConversionValueResponse.swift | 17 + .../Service/SingularEventRequest.swift | 46 + .../Singular/Service/SingularReponse.swift | 15 + .../Singular/Service/SingularService.swift | 60 ++ .../SingularSessionInfoSendRequest.swift | 75 ++ Ecosia/Core/MMP/Singular/Singular.swift | 58 ++ .../Singular/SingularAdNetworkHelper.swift | 193 ++++ Ecosia/Core/MMP/Singular/SingularEvent.swift | 5 + Ecosia/Core/Market.swift | 24 + Ecosia/Core/News/News.swift | 79 ++ Ecosia/Core/News/NewsModel.swift | 19 + Ecosia/Core/ObjectPersister.swift | 6 + Ecosia/Core/Pages/Page.swift | 11 + Ecosia/Core/Pages/PageStore.swift | 60 ++ Ecosia/Core/Publisher.swift | 38 + .../Core/Referrals/ReferralClaimRequest.swift | 28 + .../Referrals/ReferralCreateCodeRequest.swift | 13 + .../ReferralRefreshCodeRequest.swift | 18 + Ecosia/Core/Referrals/Referrals.Model.swift | 58 ++ Ecosia/Core/Referrals/Referrals.swift | 178 ++++ Ecosia/Core/RegionLocatable.swift | 5 + Ecosia/Core/Scheme.swift | 33 + Ecosia/Core/SearchesCounter.swift | 16 + Ecosia/Core/Statistics/FinancialReports.swift | 42 + .../Statistics/InvestmentsProjection.swift | 23 + Ecosia/Core/Statistics/Statistics.swift | 75 ++ Ecosia/Core/Statistics/TreesProjection.swift | 22 + Ecosia/Core/Tabs/Tab.swift | 17 + Ecosia/Core/Tabs/Tabs.swift | 96 ++ Ecosia/Core/TimeInterval+Extensions.swift | 6 + Ecosia/Core/TimestampProvider.swift | 5 + Ecosia/Core/URL+Extensions.swift | 80 ++ Ecosia/Core/URLRequest+Extensions.swift | 18 + Ecosia/Core/User.swift | 269 ++++++ .../Core/UserDefaults+ObjectPersister.swift | 3 + .../APNConsentOnLaunchExperiment.swift | 1 - .../Unleash/BrazeIntegrationExperiment.swift | 1 - .../Unleash/NewsletterCardExperiment.swift | 1 - Ecosia/Extensions/DeviceInfo+Ecosia.swift | 3 +- .../FeatureManagement/FeatureManagement.swift | 1 - .../DefaultAppVersionInfoProvider.swift | 2 +- .../EcosiaInstallType+Extensions.swift | 2 +- .../Helpers/Version/Version+Extensions.swift | 2 +- Ecosia/L10N/String.swift | 1 - EcosiaTests/Core/BookmarkParserTests.swift | 37 + .../Core/BookmarkSerializerTests.swift | 27 + EcosiaTests/Core/BookmarkTests.swift | 20 + EcosiaTests/Core/CookieTests.swift | 250 ++++++ EcosiaTests/Core/FavouritesTests.swift | 38 + ...atureFlaggingSessionInitializerTests.swift | 41 + EcosiaTests/Core/FinancialReportsTests.swift | 40 + EcosiaTests/Core/HistoryTests.swift | 72 ++ EcosiaTests/Core/ImagesTests.swift | 38 + .../Core/InvestmentsProjectionTests.swift | 34 + EcosiaTests/Core/LanguageTests.swift | 18 + EcosiaTests/Core/ListTests.swift | 23 + EcosiaTests/Core/LocalTests.swift | 29 + EcosiaTests/Core/NewsTests.swift | 158 ++++ EcosiaTests/Core/PublishersTests.swift | 59 ++ EcosiaTests/Core/ReferralsModelTests.swift | 56 ++ EcosiaTests/Core/ReferralsTests.swift | 176 ++++ .../Bookmarks/export_bookmark_ecosia.html | 24 + .../import_input_bookmark_chrome.html | 21 + .../import_input_bookmark_firefox.html | 20 + .../import_input_bookmark_safari.html | 38 + .../import_output_bookmark_chrome.txt | 1 + .../import_output_bookmark_firefox.txt | 1 + .../import_output_bookmark_safari.txt | 1 + EcosiaTests/Core/Resources/notifications.json | 1 + EcosiaTests/Core/Resources/referrals.json | 4 + EcosiaTests/Core/SearchesCounterTests.swift | 37 + .../Core/SingularAdNetworkHelperTests.swift | 325 +++++++ EcosiaTests/Core/SingularServiceTests.swift | 200 +++++ EcosiaTests/Core/SingularTests.swift | 295 ++++++ EcosiaTests/Core/SnapshotsTests.swift | 94 ++ EcosiaTests/Core/StatisticsTests.swift | 41 + EcosiaTests/Core/TabsTests.swift | 221 +++++ EcosiaTests/Core/Tools/BookmarkFixtures.swift | 31 + EcosiaTests/Core/Tools/HTTPClientMock.swift | 16 + .../Core/Tools/MockTimestampProvider.swift | 11 + EcosiaTests/Core/Tools/MockURLSession.swift | 32 + .../Core/Tools/MockURLSessionProtocol.swift | 13 + EcosiaTests/Core/TreesProjectionTests.swift | 34 + .../ProductionURLProviderTests.swift | 22 + .../StagingURLProviderTests.swift | 22 + .../URLProviderTests.swift | 92 ++ EcosiaTests/Core/URLRequestTests.swift | 13 + EcosiaTests/Core/URLTests.swift | 179 ++++ ...ureManagementSessionInitializerTests.swift | 84 ++ .../UnleashRefreshConfiguratorTests.swift | 99 ++ EcosiaTests/Core/UnleashTests.swift | 257 ++++++ EcosiaTests/Core/UpgradeTests.swift | 45 + EcosiaTests/Core/UserStateTests.swift | 51 ++ EcosiaTests/Core/UserTests.swift | 370 ++++++++ EcosiaTests/Core/Versions/User5_3.swift | 27 + Shared/UserAgent.swift | 4 +- Storage/DefaultSuggestedSites.swift | 4 +- 200 files changed, 7997 insertions(+), 184 deletions(-) create mode 100644 Ecosia/Core/AdultFilter.swift create mode 100644 Ecosia/Core/AppDeviceInfo.swift create mode 100644 Ecosia/Core/Bookmarks/Bookmark.swift create mode 100644 Ecosia/Core/Bookmarks/BookmarkParser.swift create mode 100644 Ecosia/Core/Bookmarks/BookmarkSerializer.swift create mode 100644 Ecosia/Core/Bookmarks/Document+Safari.swift create mode 100644 Ecosia/Core/Bookmarks/String+CssQuery.swift rename Ecosia/{ => Core}/Braze/APNConsent.swift (100%) rename Ecosia/{ => Core}/Braze/BrazeService.swift (99%) create mode 100644 Ecosia/Core/Bundle.swift create mode 100644 Ecosia/Core/CloudFlareKeyProvider.swift create mode 100644 Ecosia/Core/Cookie.swift create mode 100644 Ecosia/Core/Date+TimestampProvider.swift create mode 100644 Ecosia/Core/Encodable+Dictionary.swift create mode 100644 Ecosia/Core/Environment/Environment.Auth.swift create mode 100644 Ecosia/Core/Environment/Environment.swift create mode 100644 Ecosia/Core/Environment/URLProvider.swift create mode 100644 Ecosia/Core/EnvironmentFetcher.swift create mode 100644 Ecosia/Core/Favourites.swift create mode 100644 Ecosia/Core/FeatureManagement/FeatureManagementSessionInitializer.swift create mode 100644 Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/AppUpdateRule.swift create mode 100644 Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/DeviceRegionChangeRule.swift create mode 100644 Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/RefreshingRule.swift create mode 100644 Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/TimeBasedRefreshingRule.swift create mode 100644 Ecosia/Core/FeatureManagement/Unleash/Unleash+RefreshComponent.swift create mode 100644 Ecosia/Core/FeatureManagement/Unleash/Unleash.Model.swift create mode 100644 Ecosia/Core/FeatureManagement/Unleash/Unleash.swift create mode 100644 Ecosia/Core/FeatureManagement/Unleash/UnleashFeatureManagementSessionInitializer.swift create mode 100644 Ecosia/Core/FeatureManagement/Unleash/UnleashRefreshConfigurator.swift create mode 100644 Ecosia/Core/FeatureManagement/Unleash/UnleashStartRequest.swift create mode 100644 Ecosia/Core/FileManager.swift create mode 100644 Ecosia/Core/HTTPClient/HTTPClient.swift create mode 100644 Ecosia/Core/HTTPClient/HTTPMethod.swift create mode 100644 Ecosia/Core/HTTPClient/Requestable/BaseRequest.swift create mode 100644 Ecosia/Core/HTTPClient/Requestable/Requestable.swift create mode 100644 Ecosia/Core/HTTPClient/URLSessionHTTPClient.swift create mode 100644 Ecosia/Core/HTTPClient/URLSessionProtocol.swift create mode 100644 Ecosia/Core/History.swift create mode 100644 Ecosia/Core/Images.swift create mode 100644 Ecosia/Core/Language.swift create mode 100644 Ecosia/Core/List.swift create mode 100644 Ecosia/Core/Local.swift create mode 100644 Ecosia/Core/Locale+Extensions.swift rename Ecosia/{ => Core}/MMP/MMP.swift (90%) create mode 100644 Ecosia/Core/MMP/MMPProvider.swift create mode 100644 Ecosia/Core/MMP/SKAdNetworkProtocol.swift create mode 100644 Ecosia/Core/MMP/Singular/Service/SingularConversionValueRequest.swift create mode 100644 Ecosia/Core/MMP/Singular/Service/SingularConversionValueResponse.swift create mode 100644 Ecosia/Core/MMP/Singular/Service/SingularEventRequest.swift create mode 100644 Ecosia/Core/MMP/Singular/Service/SingularReponse.swift create mode 100644 Ecosia/Core/MMP/Singular/Service/SingularService.swift create mode 100644 Ecosia/Core/MMP/Singular/Service/SingularSessionInfoSendRequest.swift create mode 100644 Ecosia/Core/MMP/Singular/Singular.swift create mode 100644 Ecosia/Core/MMP/Singular/SingularAdNetworkHelper.swift create mode 100644 Ecosia/Core/MMP/Singular/SingularEvent.swift create mode 100644 Ecosia/Core/Market.swift create mode 100644 Ecosia/Core/News/News.swift create mode 100644 Ecosia/Core/News/NewsModel.swift create mode 100644 Ecosia/Core/ObjectPersister.swift create mode 100644 Ecosia/Core/Pages/Page.swift create mode 100644 Ecosia/Core/Pages/PageStore.swift create mode 100644 Ecosia/Core/Publisher.swift create mode 100644 Ecosia/Core/Referrals/ReferralClaimRequest.swift create mode 100644 Ecosia/Core/Referrals/ReferralCreateCodeRequest.swift create mode 100644 Ecosia/Core/Referrals/ReferralRefreshCodeRequest.swift create mode 100644 Ecosia/Core/Referrals/Referrals.Model.swift create mode 100644 Ecosia/Core/Referrals/Referrals.swift create mode 100644 Ecosia/Core/RegionLocatable.swift create mode 100644 Ecosia/Core/Scheme.swift create mode 100644 Ecosia/Core/SearchesCounter.swift create mode 100644 Ecosia/Core/Statistics/FinancialReports.swift create mode 100644 Ecosia/Core/Statistics/InvestmentsProjection.swift create mode 100644 Ecosia/Core/Statistics/Statistics.swift create mode 100644 Ecosia/Core/Statistics/TreesProjection.swift create mode 100644 Ecosia/Core/Tabs/Tab.swift create mode 100644 Ecosia/Core/Tabs/Tabs.swift create mode 100644 Ecosia/Core/TimeInterval+Extensions.swift create mode 100644 Ecosia/Core/TimestampProvider.swift create mode 100644 Ecosia/Core/URL+Extensions.swift create mode 100644 Ecosia/Core/URLRequest+Extensions.swift create mode 100644 Ecosia/Core/User.swift create mode 100644 Ecosia/Core/UserDefaults+ObjectPersister.swift create mode 100644 EcosiaTests/Core/BookmarkParserTests.swift create mode 100644 EcosiaTests/Core/BookmarkSerializerTests.swift create mode 100644 EcosiaTests/Core/BookmarkTests.swift create mode 100644 EcosiaTests/Core/CookieTests.swift create mode 100644 EcosiaTests/Core/FavouritesTests.swift create mode 100644 EcosiaTests/Core/FeatureFlaggingSessionInitializerTests.swift create mode 100644 EcosiaTests/Core/FinancialReportsTests.swift create mode 100644 EcosiaTests/Core/HistoryTests.swift create mode 100644 EcosiaTests/Core/ImagesTests.swift create mode 100644 EcosiaTests/Core/InvestmentsProjectionTests.swift create mode 100644 EcosiaTests/Core/LanguageTests.swift create mode 100644 EcosiaTests/Core/ListTests.swift create mode 100644 EcosiaTests/Core/LocalTests.swift create mode 100644 EcosiaTests/Core/NewsTests.swift create mode 100644 EcosiaTests/Core/PublishersTests.swift create mode 100644 EcosiaTests/Core/ReferralsModelTests.swift create mode 100644 EcosiaTests/Core/ReferralsTests.swift create mode 100644 EcosiaTests/Core/Resources/Bookmarks/export_bookmark_ecosia.html create mode 100644 EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_chrome.html create mode 100644 EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_firefox.html create mode 100644 EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_safari.html create mode 100644 EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_chrome.txt create mode 100644 EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_firefox.txt create mode 100644 EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_safari.txt create mode 100644 EcosiaTests/Core/Resources/notifications.json create mode 100644 EcosiaTests/Core/Resources/referrals.json create mode 100644 EcosiaTests/Core/SearchesCounterTests.swift create mode 100644 EcosiaTests/Core/SingularAdNetworkHelperTests.swift create mode 100644 EcosiaTests/Core/SingularServiceTests.swift create mode 100644 EcosiaTests/Core/SingularTests.swift create mode 100644 EcosiaTests/Core/SnapshotsTests.swift create mode 100644 EcosiaTests/Core/StatisticsTests.swift create mode 100644 EcosiaTests/Core/TabsTests.swift create mode 100644 EcosiaTests/Core/Tools/BookmarkFixtures.swift create mode 100644 EcosiaTests/Core/Tools/HTTPClientMock.swift create mode 100644 EcosiaTests/Core/Tools/MockTimestampProvider.swift create mode 100644 EcosiaTests/Core/Tools/MockURLSession.swift create mode 100644 EcosiaTests/Core/Tools/MockURLSessionProtocol.swift create mode 100644 EcosiaTests/Core/TreesProjectionTests.swift create mode 100644 EcosiaTests/Core/URLProviderDependantTests/ProductionURLProviderTests.swift create mode 100644 EcosiaTests/Core/URLProviderDependantTests/StagingURLProviderTests.swift create mode 100644 EcosiaTests/Core/URLProviderDependantTests/URLProviderTests.swift create mode 100644 EcosiaTests/Core/URLRequestTests.swift create mode 100644 EcosiaTests/Core/URLTests.swift create mode 100644 EcosiaTests/Core/UnleashFeatureManagementSessionInitializerTests.swift create mode 100644 EcosiaTests/Core/UnleashRefreshConfiguratorTests.swift create mode 100644 EcosiaTests/Core/UnleashTests.swift create mode 100644 EcosiaTests/Core/UpgradeTests.swift create mode 100644 EcosiaTests/Core/UserStateTests.swift create mode 100644 EcosiaTests/Core/UserTests.swift create mode 100644 EcosiaTests/Core/Versions/User5_3.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 6faafcca32ee..65135ee0c641 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -151,6 +151,8 @@ excluded: # paths to ignore during linting. Takes precedence over `included`. - BrowserKit/.build/ # Ecosia: Exclude Swift Packages - SourcePackages + # Ecosia; Excluding Core's EcosiaTests as we have some force unwraps + - EcosiaTests/Core included: - /Users/vagrant/git diff --git a/BrowserKit/Sources/SiteImageView/ImageProcessing/BundleImageFetcher/BundleImageFetcher.swift b/BrowserKit/Sources/SiteImageView/ImageProcessing/BundleImageFetcher/BundleImageFetcher.swift index 227dc91e9a8c..e722dc3d7e71 100644 --- a/BrowserKit/Sources/SiteImageView/ImageProcessing/BundleImageFetcher/BundleImageFetcher.swift +++ b/BrowserKit/Sources/SiteImageView/ImageProcessing/BundleImageFetcher/BundleImageFetcher.swift @@ -4,8 +4,8 @@ import UIKit import Common -// Ecosia: Import Core -import Core +// Ecosia: Import Ecosia Framework +import Ecosia protocol BundleImageFetcher { /// Fetches from the bundle @@ -83,8 +83,8 @@ class DefaultBundleImageFetcher: BundleImageFetcher { into the BrowserKit package, this would have resulted into macking a lot of changes into accessors to be able to make our own file outside of the BrowserKit context. */ - let financialReportsURL = Environment.current.urlProvider.financialReports.absoluteString.replacingOccurrences(of: "https://", with: "") - let privacyURL = Environment.current.urlProvider.privacy.absoluteString.replacingOccurrences(of: "https://", with: "") + let financialReportsURL = Ecosia.Environment.current.urlProvider.financialReports.absoluteString.replacingOccurrences(of: "https://", with: "") + let privacyURL = Ecosia.Environment.current.urlProvider.privacy.absoluteString.replacingOccurrences(of: "https://", with: "") let urlMap = [ financialReportsURL: "blog.ecosia.finance", privacyURL: "privacy.ecosia" diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index 86292dae3080..8804cc32212b 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -32,10 +32,8 @@ 1229357F2CE78D0A00EC1297 /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; 122935802CE78D0A00EC1297 /* Ecosia.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 1229358D2CE78D5D00EC1297 /* BrazeServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126509882CDA31890011BA36 /* BrazeServiceTests.swift */; }; - 1229358F2CE78EC400EC1297 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 1229358E2CE78EC400EC1297 /* Core */; }; 122935912CE78ED500EC1297 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 122935902CE78ED500EC1297 /* BrazeKit */; }; 122935932CE78ED500EC1297 /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 122935922CE78ED500EC1297 /* BrazeUI */; }; - 122935A92CE79CC800EC1297 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288A2D861AB8B3260023ABC3 /* Shared.framework */; }; 122935B52CE79EF900EC1297 /* SnowplowTracker in Frameworks */ = {isa = PBXBuildFile; productRef = 122935B42CE79EF900EC1297 /* SnowplowTracker */; }; 126509852CD925B40011BA36 /* BrazeKit in Frameworks */ = {isa = PBXBuildFile; productRef = 126509842CD925B40011BA36 /* BrazeKit */; }; 126509872CD925B40011BA36 /* BrazeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 126509862CD925B40011BA36 /* BrazeUI */; }; @@ -208,9 +206,7 @@ 2C1298A62BF5EB1E005AE4E4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 2C1298A42BF5EB16005AE4E4 /* PrivacyInfo.xcprivacy */; }; 2C1298A72BF5EB1F005AE4E4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 2C1298A42BF5EB16005AE4E4 /* PrivacyInfo.xcprivacy */; }; 2C1298A82BF5EE23005AE4E4 /* libStorage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FCAE21A1ABB51F800877008 /* libStorage.a */; }; - 2C1298AC2BF5EE3E005AE4E4 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2C1298AB2BF5EE3E005AE4E4 /* Core */; }; 2C1298AF2BF602D3005AE4E4 /* DefaultSuggestedSites.swift in Sources */ = {isa = PBXBuildFile; fileRef = 394CF6CE1BAA493C00906917 /* DefaultSuggestedSites.swift */; }; - 2C1F23BD2B9F405E00186F55 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2C1F23BC2B9F405E00186F55 /* Core */; }; 2C49854E206173C800893DAE /* photon-colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C49854D206173C800893DAE /* photon-colors.swift */; }; 2C6189DE2B7B78ED006B70D7 /* LegacyTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9A179A20E69A7E00B12184 /* LegacyTheme.swift */; }; 2C6189E12B7B7922006B70D7 /* LegacyTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9A179A20E69A7E00B12184 /* LegacyTheme.swift */; }; @@ -228,7 +224,6 @@ 2C69DA7D2C6244BE00D7F69F /* MockTabDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A475E8C29DB888E009C13FD /* MockTabDataStore.swift */; }; 2C69DA7E2C6244C400D7F69F /* MockThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AA75A622A46272000533F8D /* MockThemeManager.swift */; }; 2C69DA7F2C62458300D7F69F /* RustMozillaAppServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43BE578A278BA4D900491291 /* RustMozillaAppServices.framework */; }; - 2C69DA812C62459200D7F69F /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2C69DA802C62459200D7F69F /* Core */; }; 2C69DA822C62459C00D7F69F /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 2CB1728B2C61336D008551E2 /* libz.tbd */; }; 2C6C908F2C614A6C007D9B43 /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 2C6C908E2C614A6C007D9B43 /* SnapshotTesting */; }; 2C872A552B8CD58200B318A0 /* ContileProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A7A93ED2810ADF2005E7E1B /* ContileProviderTests.swift */; }; @@ -236,6 +231,142 @@ 2CAF5AE32D00AAEE00D3DCDD /* Bundle+Ecosia.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AE22D00AAEE00D3DCDD /* Bundle+Ecosia.swift */; }; 2CAF5AE72D00B1D300D3DCDD /* EcosiaLaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2CAF5AE42D00B1D300D3DCDD /* EcosiaLaunchScreen.xib */; }; 2CAF5AE82D00B1D300D3DCDD /* EcosiaLaunchScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AE52D00B1D300D3DCDD /* EcosiaLaunchScreenView.swift */; }; + 2CAF5B4C2D00D16C00D3DCDD /* Bookmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AEA2D00D16700D3DCDD /* Bookmark.swift */; }; + 2CAF5B4D2D00D16C00D3DCDD /* BookmarkParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AEB2D00D16700D3DCDD /* BookmarkParser.swift */; }; + 2CAF5B4E2D00D16C00D3DCDD /* BookmarkSerializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AEC2D00D16700D3DCDD /* BookmarkSerializer.swift */; }; + 2CAF5B4F2D00D16C00D3DCDD /* Document+Safari.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AED2D00D16700D3DCDD /* Document+Safari.swift */; }; + 2CAF5B502D00D16C00D3DCDD /* String+CssQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AEE2D00D16700D3DCDD /* String+CssQuery.swift */; }; + 2CAF5B512D00D16C00D3DCDD /* BaseRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AF02D00D16700D3DCDD /* BaseRequest.swift */; }; + 2CAF5B522D00D16C00D3DCDD /* Requestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AF12D00D16700D3DCDD /* Requestable.swift */; }; + 2CAF5B532D00D16C00D3DCDD /* HTTPClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AF32D00D16700D3DCDD /* HTTPClient.swift */; }; + 2CAF5B542D00D16C00D3DCDD /* HTTPMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AF42D00D16700D3DCDD /* HTTPMethod.swift */; }; + 2CAF5B552D00D16C00D3DCDD /* URLSessionHTTPClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AF52D00D16700D3DCDD /* URLSessionHTTPClient.swift */; }; + 2CAF5B562D00D16C00D3DCDD /* URLSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AF62D00D16700D3DCDD /* URLSessionProtocol.swift */; }; + 2CAF5B572D00D16C00D3DCDD /* Cookie.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AF82D00D16700D3DCDD /* Cookie.swift */; }; + 2CAF5B582D00D16C00D3DCDD /* ReferralClaimRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AF92D00D16700D3DCDD /* ReferralClaimRequest.swift */; }; + 2CAF5B592D00D16C00D3DCDD /* ReferralCreateCodeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AFA2D00D16700D3DCDD /* ReferralCreateCodeRequest.swift */; }; + 2CAF5B5A2D00D16C00D3DCDD /* ReferralRefreshCodeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AFB2D00D16700D3DCDD /* ReferralRefreshCodeRequest.swift */; }; + 2CAF5B5B2D00D16C00D3DCDD /* Referrals.Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AFC2D00D16700D3DCDD /* Referrals.Model.swift */; }; + 2CAF5B5C2D00D16C00D3DCDD /* Referrals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AFD2D00D16700D3DCDD /* Referrals.swift */; }; + 2CAF5B5D2D00D16C00D3DCDD /* Scheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5AFF2D00D16700D3DCDD /* Scheme.swift */; }; + 2CAF5B5E2D00D16C00D3DCDD /* Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B002D00D16800D3DCDD /* Publisher.swift */; }; + 2CAF5B5F2D00D16C00D3DCDD /* TimestampProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B012D00D16800D3DCDD /* TimestampProvider.swift */; }; + 2CAF5B602D00D16C00D3DCDD /* SingularConversionValueRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B022D00D16800D3DCDD /* SingularConversionValueRequest.swift */; }; + 2CAF5B612D00D16C00D3DCDD /* SingularConversionValueResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B032D00D16800D3DCDD /* SingularConversionValueResponse.swift */; }; + 2CAF5B622D00D16C00D3DCDD /* SingularEventRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B042D00D16800D3DCDD /* SingularEventRequest.swift */; }; + 2CAF5B632D00D16C00D3DCDD /* SingularReponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B052D00D16800D3DCDD /* SingularReponse.swift */; }; + 2CAF5B642D00D16C00D3DCDD /* SingularService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B062D00D16800D3DCDD /* SingularService.swift */; }; + 2CAF5B652D00D16C00D3DCDD /* SingularSessionInfoSendRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B072D00D16800D3DCDD /* SingularSessionInfoSendRequest.swift */; }; + 2CAF5B662D00D16C00D3DCDD /* Singular.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B092D00D16800D3DCDD /* Singular.swift */; }; + 2CAF5B672D00D16C00D3DCDD /* SingularAdNetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B0A2D00D16800D3DCDD /* SingularAdNetworkHelper.swift */; }; + 2CAF5B682D00D16C00D3DCDD /* SingularEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B0B2D00D16800D3DCDD /* SingularEvent.swift */; }; + 2CAF5B6A2D00D16C00D3DCDD /* MMPProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B0E2D00D16800D3DCDD /* MMPProvider.swift */; }; + 2CAF5B6B2D00D16C00D3DCDD /* SKAdNetworkProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B0F2D00D16800D3DCDD /* SKAdNetworkProtocol.swift */; }; + 2CAF5B6C2D00D16C00D3DCDD /* AppDeviceInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B112D00D16800D3DCDD /* AppDeviceInfo.swift */; }; + 2CAF5B6D2D00D16C00D3DCDD /* Environment.Auth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B122D00D16800D3DCDD /* Environment.Auth.swift */; }; + 2CAF5B6E2D00D16C00D3DCDD /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B132D00D16800D3DCDD /* Environment.swift */; }; + 2CAF5B6F2D00D16C00D3DCDD /* URLProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B142D00D16800D3DCDD /* URLProvider.swift */; }; + 2CAF5B702D00D16C00D3DCDD /* TimeInterval+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B172D00D16800D3DCDD /* TimeInterval+Extensions.swift */; }; + 2CAF5B712D00D16C00D3DCDD /* History.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B182D00D16800D3DCDD /* History.swift */; }; + 2CAF5B722D00D16C00D3DCDD /* AppUpdateRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B192D00D16900D3DCDD /* AppUpdateRule.swift */; }; + 2CAF5B732D00D16C00D3DCDD /* DeviceRegionChangeRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B1A2D00D16900D3DCDD /* DeviceRegionChangeRule.swift */; }; + 2CAF5B742D00D16C00D3DCDD /* RefreshingRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B1B2D00D16900D3DCDD /* RefreshingRule.swift */; }; + 2CAF5B752D00D16C00D3DCDD /* TimeBasedRefreshingRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B1C2D00D16900D3DCDD /* TimeBasedRefreshingRule.swift */; }; + 2CAF5B762D00D16C00D3DCDD /* Unleash.Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B1F2D00D16900D3DCDD /* Unleash.Model.swift */; }; + 2CAF5B772D00D16C00D3DCDD /* Unleash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B202D00D16900D3DCDD /* Unleash.swift */; }; + 2CAF5B782D00D16C00D3DCDD /* Unleash+RefreshComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B212D00D16900D3DCDD /* Unleash+RefreshComponent.swift */; }; + 2CAF5B792D00D16C00D3DCDD /* UnleashFeatureManagementSessionInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B222D00D16900D3DCDD /* UnleashFeatureManagementSessionInitializer.swift */; }; + 2CAF5B7A2D00D16C00D3DCDD /* UnleashRefreshConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B232D00D16900D3DCDD /* UnleashRefreshConfigurator.swift */; }; + 2CAF5B7B2D00D16C00D3DCDD /* UnleashStartRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B242D00D16900D3DCDD /* UnleashStartRequest.swift */; }; + 2CAF5B7C2D00D16C00D3DCDD /* FeatureManagementSessionInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B262D00D16900D3DCDD /* FeatureManagementSessionInitializer.swift */; }; + 2CAF5B7D2D00D16C00D3DCDD /* Tab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B282D00D16900D3DCDD /* Tab.swift */; }; + 2CAF5B7E2D00D16C00D3DCDD /* Tabs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B292D00D16900D3DCDD /* Tabs.swift */; }; + 2CAF5B7F2D00D16C00D3DCDD /* News.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B2B2D00D16900D3DCDD /* News.swift */; }; + 2CAF5B802D00D16C00D3DCDD /* NewsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B2C2D00D16900D3DCDD /* NewsModel.swift */; }; + 2CAF5B812D00D16C00D3DCDD /* ObjectPersister.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B2E2D00D16900D3DCDD /* ObjectPersister.swift */; }; + 2CAF5B822D00D16C00D3DCDD /* Date+TimestampProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B2F2D00D16900D3DCDD /* Date+TimestampProvider.swift */; }; + 2CAF5B832D00D16C00D3DCDD /* Page.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B302D00D16900D3DCDD /* Page.swift */; }; + 2CAF5B842D00D16C00D3DCDD /* PageStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B312D00D16900D3DCDD /* PageStore.swift */; }; + 2CAF5B852D00D16C00D3DCDD /* URLRequest+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B332D00D16900D3DCDD /* URLRequest+Extensions.swift */; }; + 2CAF5B862D00D16C00D3DCDD /* Encodable+Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B342D00D16A00D3DCDD /* Encodable+Dictionary.swift */; }; + 2CAF5B872D00D16C00D3DCDD /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B352D00D16A00D3DCDD /* User.swift */; }; + 2CAF5B882D00D16C00D3DCDD /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B362D00D16A00D3DCDD /* URL+Extensions.swift */; }; + 2CAF5B892D00D16C00D3DCDD /* FinancialReports.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B372D00D16A00D3DCDD /* FinancialReports.swift */; }; + 2CAF5B8A2D00D16C00D3DCDD /* InvestmentsProjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B382D00D16A00D3DCDD /* InvestmentsProjection.swift */; }; + 2CAF5B8B2D00D16C00D3DCDD /* Statistics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B392D00D16A00D3DCDD /* Statistics.swift */; }; + 2CAF5B8C2D00D16C00D3DCDD /* TreesProjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B3A2D00D16A00D3DCDD /* TreesProjection.swift */; }; + 2CAF5B8D2D00D16C00D3DCDD /* EnvironmentFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B3C2D00D16A00D3DCDD /* EnvironmentFetcher.swift */; }; + 2CAF5B8E2D00D16C00D3DCDD /* Local.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B3E2D00D16A00D3DCDD /* Local.swift */; }; + 2CAF5B8F2D00D16C00D3DCDD /* Language.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B3F2D00D16B00D3DCDD /* Language.swift */; }; + 2CAF5B902D00D16C00D3DCDD /* Favourites.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B402D00D16B00D3DCDD /* Favourites.swift */; }; + 2CAF5B912D00D16C00D3DCDD /* List.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B412D00D16B00D3DCDD /* List.swift */; }; + 2CAF5B922D00D16C00D3DCDD /* AdultFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B422D00D16B00D3DCDD /* AdultFilter.swift */; }; + 2CAF5B932D00D16C00D3DCDD /* Images.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B432D00D16B00D3DCDD /* Images.swift */; }; + 2CAF5B942D00D16C00D3DCDD /* UserDefaults+ObjectPersister.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B442D00D16B00D3DCDD /* UserDefaults+ObjectPersister.swift */; }; + 2CAF5B952D00D16C00D3DCDD /* SearchesCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B452D00D16B00D3DCDD /* SearchesCounter.swift */; }; + 2CAF5B962D00D16C00D3DCDD /* FileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B462D00D16C00D3DCDD /* FileManager.swift */; }; + 2CAF5B972D00D16C00D3DCDD /* Market.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B472D00D16C00D3DCDD /* Market.swift */; }; + 2CAF5B982D00D16C00D3DCDD /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B482D00D16C00D3DCDD /* Bundle.swift */; }; + 2CAF5B992D00D16C00D3DCDD /* RegionLocatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B492D00D16C00D3DCDD /* RegionLocatable.swift */; }; + 2CAF5B9A2D00D16C00D3DCDD /* CloudFlareKeyProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B4A2D00D16C00D3DCDD /* CloudFlareKeyProvider.swift */; }; + 2CAF5B9B2D00D16C00D3DCDD /* Locale+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B4B2D00D16C00D3DCDD /* Locale+Extensions.swift */; }; + 2CAF5BD52D00D1AB00D3DCDD /* User5_3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B9D2D00D1A600D3DCDD /* User5_3.swift */; }; + 2CAF5BD62D00D1AB00D3DCDD /* BookmarkFixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5B9F2D00D1A600D3DCDD /* BookmarkFixtures.swift */; }; + 2CAF5BD72D00D1AB00D3DCDD /* HTTPClientMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BA02D00D1A600D3DCDD /* HTTPClientMock.swift */; }; + 2CAF5BD82D00D1AB00D3DCDD /* MockTimestampProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BA12D00D1A600D3DCDD /* MockTimestampProvider.swift */; }; + 2CAF5BD92D00D1AB00D3DCDD /* MockURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BA22D00D1A600D3DCDD /* MockURLSession.swift */; }; + 2CAF5BDA2D00D1AB00D3DCDD /* MockURLSessionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BA32D00D1A600D3DCDD /* MockURLSessionProtocol.swift */; }; + 2CAF5BDB2D00D1AB00D3DCDD /* ListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BA52D00D1A600D3DCDD /* ListTests.swift */; }; + 2CAF5BDC2D00D1AB00D3DCDD /* URLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BA62D00D1A600D3DCDD /* URLTests.swift */; }; + 2CAF5BDD2D00D1AB00D3DCDD /* FeatureFlaggingSessionInitializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BA72D00D1A700D3DCDD /* FeatureFlaggingSessionInitializerTests.swift */; }; + 2CAF5BDE2D00D1AB00D3DCDD /* export_bookmark_ecosia.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CAF5BA82D00D1A700D3DCDD /* export_bookmark_ecosia.html */; }; + 2CAF5BDF2D00D1AB00D3DCDD /* import_input_bookmark_chrome.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CAF5BA92D00D1A700D3DCDD /* import_input_bookmark_chrome.html */; }; + 2CAF5BE02D00D1AB00D3DCDD /* import_input_bookmark_firefox.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CAF5BAA2D00D1A700D3DCDD /* import_input_bookmark_firefox.html */; }; + 2CAF5BE12D00D1AB00D3DCDD /* import_input_bookmark_safari.html in Resources */ = {isa = PBXBuildFile; fileRef = 2CAF5BAB2D00D1A700D3DCDD /* import_input_bookmark_safari.html */; }; + 2CAF5BE22D00D1AB00D3DCDD /* import_output_bookmark_chrome.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CAF5BAC2D00D1A700D3DCDD /* import_output_bookmark_chrome.txt */; }; + 2CAF5BE32D00D1AB00D3DCDD /* import_output_bookmark_firefox.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CAF5BAD2D00D1A700D3DCDD /* import_output_bookmark_firefox.txt */; }; + 2CAF5BE42D00D1AB00D3DCDD /* import_output_bookmark_safari.txt in Resources */ = {isa = PBXBuildFile; fileRef = 2CAF5BAE2D00D1A700D3DCDD /* import_output_bookmark_safari.txt */; }; + 2CAF5BE52D00D1AB00D3DCDD /* notifications.json in Resources */ = {isa = PBXBuildFile; fileRef = 2CAF5BB02D00D1A700D3DCDD /* notifications.json */; }; + 2CAF5BE62D00D1AB00D3DCDD /* referrals.json in Resources */ = {isa = PBXBuildFile; fileRef = 2CAF5BB12D00D1A700D3DCDD /* referrals.json */; }; + 2CAF5BE72D00D1AB00D3DCDD /* SingularTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BB32D00D1A700D3DCDD /* SingularTests.swift */; }; + 2CAF5BE82D00D1AB00D3DCDD /* SingularServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BB42D00D1A700D3DCDD /* SingularServiceTests.swift */; }; + 2CAF5BE92D00D1AB00D3DCDD /* UpgradeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BB52D00D1A700D3DCDD /* UpgradeTests.swift */; }; + 2CAF5BEA2D00D1AB00D3DCDD /* UnleashFeatureManagementSessionInitializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BB62D00D1A700D3DCDD /* UnleashFeatureManagementSessionInitializerTests.swift */; }; + 2CAF5BEB2D00D1AB00D3DCDD /* BookmarkParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BB72D00D1A700D3DCDD /* BookmarkParserTests.swift */; }; + 2CAF5BEC2D00D1AB00D3DCDD /* NewsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BB82D00D1A700D3DCDD /* NewsTests.swift */; }; + 2CAF5BED2D00D1AB00D3DCDD /* BookmarkSerializerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BB92D00D1A800D3DCDD /* BookmarkSerializerTests.swift */; }; + 2CAF5BEE2D00D1AB00D3DCDD /* ImagesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BBA2D00D1A800D3DCDD /* ImagesTests.swift */; }; + 2CAF5BEF2D00D1AB00D3DCDD /* StatisticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BBB2D00D1A800D3DCDD /* StatisticsTests.swift */; }; + 2CAF5BF02D00D1AB00D3DCDD /* ReferralsModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BBC2D00D1A800D3DCDD /* ReferralsModelTests.swift */; }; + 2CAF5BF12D00D1AB00D3DCDD /* HistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BBD2D00D1A800D3DCDD /* HistoryTests.swift */; }; + 2CAF5BF22D00D1AB00D3DCDD /* BookmarkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BBE2D00D1A800D3DCDD /* BookmarkTests.swift */; }; + 2CAF5BF32D00D1AB00D3DCDD /* SnapshotsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BBF2D00D1A800D3DCDD /* SnapshotsTests.swift */; }; + 2CAF5BF42D00D1AB00D3DCDD /* LocalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC02D00D1A800D3DCDD /* LocalTests.swift */; }; + 2CAF5BF52D00D1AB00D3DCDD /* SingularAdNetworkHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC12D00D1A900D3DCDD /* SingularAdNetworkHelperTests.swift */; }; + 2CAF5BF62D00D1AB00D3DCDD /* TabsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC22D00D1A900D3DCDD /* TabsTests.swift */; }; + 2CAF5BF72D00D1AB00D3DCDD /* TreesProjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC32D00D1A900D3DCDD /* TreesProjectionTests.swift */; }; + 2CAF5BF82D00D1AB00D3DCDD /* UnleashTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC42D00D1A900D3DCDD /* UnleashTests.swift */; }; + 2CAF5BF92D00D1AB00D3DCDD /* ProductionURLProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC52D00D1A900D3DCDD /* ProductionURLProviderTests.swift */; }; + 2CAF5BFA2D00D1AB00D3DCDD /* StagingURLProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC62D00D1A900D3DCDD /* StagingURLProviderTests.swift */; }; + 2CAF5BFB2D00D1AB00D3DCDD /* URLProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC72D00D1A900D3DCDD /* URLProviderTests.swift */; }; + 2CAF5BFC2D00D1AB00D3DCDD /* UserStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC92D00D1A900D3DCDD /* UserStateTests.swift */; }; + 2CAF5BFD2D00D1AB00D3DCDD /* SearchesCounterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BCA2D00D1A900D3DCDD /* SearchesCounterTests.swift */; }; + 2CAF5BFE2D00D1AB00D3DCDD /* ReferralsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BCB2D00D1AA00D3DCDD /* ReferralsTests.swift */; }; + 2CAF5BFF2D00D1AB00D3DCDD /* FinancialReportsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BCC2D00D1AA00D3DCDD /* FinancialReportsTests.swift */; }; + 2CAF5C002D00D1AB00D3DCDD /* CookieTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BCD2D00D1AA00D3DCDD /* CookieTests.swift */; }; + 2CAF5C012D00D1AB00D3DCDD /* InvestmentsProjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BCE2D00D1AA00D3DCDD /* InvestmentsProjectionTests.swift */; }; + 2CAF5C022D00D1AB00D3DCDD /* PublishersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BCF2D00D1AA00D3DCDD /* PublishersTests.swift */; }; + 2CAF5C032D00D1AB00D3DCDD /* UnleashRefreshConfiguratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BD02D00D1AA00D3DCDD /* UnleashRefreshConfiguratorTests.swift */; }; + 2CAF5C042D00D1AB00D3DCDD /* UserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BD12D00D1AA00D3DCDD /* UserTests.swift */; }; + 2CAF5C052D00D1AB00D3DCDD /* LanguageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BD22D00D1AA00D3DCDD /* LanguageTests.swift */; }; + 2CAF5C062D00D1AB00D3DCDD /* FavouritesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BD32D00D1AB00D3DCDD /* FavouritesTests.swift */; }; + 2CAF5C072D00D1AB00D3DCDD /* URLRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BD42D00D1AB00D3DCDD /* URLRequestTests.swift */; }; + 2CAF5C162D01B2E200D3DCDD /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; + 2CAF5C172D01B2E200D3DCDD /* Ecosia.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 2CAF5C1D2D01B40B00D3DCDD /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = 2CAF5C1C2D01B40B00D3DCDD /* SwiftSoup */; }; + 2CAF5C1F2D01B44400D3DCDD /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 2CAF5C1E2D01B44400D3DCDD /* Sentry */; }; + 2CAF5C212D01B5F300D3DCDD /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 2CAF5C202D01B5F300D3DCDD /* Common */; }; + 2CAF5C222D01B62900D3DCDD /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; 2CCFB3D72C0FBEE800BEDCA0 /* TabToolbarHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D815A3A724A53F3200AAB221 /* TabToolbarHelperTests.swift */; }; 2CD262A92CFDC5EB00A040A7 /* EcosiaMockThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261842CFDC5E900A040A7 /* EcosiaMockThemeManager.swift */; }; 2CD262AA2CFDC5EB00A040A7 /* Welcome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261852CFDC5E900A040A7 /* Welcome.swift */; }; @@ -663,10 +794,6 @@ 2CD266512CFF56CB00A040A7 /* ConnectionStatusImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2664E2CFF56CB00A040A7 /* ConnectionStatusImage.swift */; }; 2CD266522CFF56CB00A040A7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2664F2CFF56CB00A040A7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift */; }; 2CD266552CFF56EA00A040A7 /* WebsiteConnectionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD266532CFF56EA00A040A7 /* WebsiteConnectionStatus.swift */; }; - 2CE294472B7CDD56006C22B2 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE294462B7CDD56006C22B2 /* Core */; }; - 2CE294492B7CDD78006C22B2 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE294482B7CDD78006C22B2 /* Core */; }; - 2CE2E24D2B9B1FCB00973C16 /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2CE2E24C2B9B1FCB00973C16 /* Core */; }; - 2CF4DA632BB31970001C340A /* Core in Frameworks */ = {isa = PBXBuildFile; productRef = 2CF4DA622BB31970001C340A /* Core */; }; 2F13E79B1AC0C02700D75081 /* StringExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F13E79A1AC0C02700D75081 /* StringExtensionsTests.swift */; }; 2F44FA1B1A9D426A00FD20CC /* TestHashExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F44FA1A1A9D426A00FD20CC /* TestHashExtensions.swift */; }; 2F44FB2C1A9D5D8500FD20CC /* Library.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F84B22261A09127C00AAB793 /* Library.xcassets */; }; @@ -1947,6 +2074,13 @@ remoteGlobalIDString = F84B21BD1A090F8100AAB793; remoteInfo = Client; }; + 2CAF5C182D01B2E200D3DCDD /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F84B21B61A090F8100AAB793 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 122935692CE78D0A00EC1297; + remoteInfo = Ecosia; + }; 2F11EE4F1ABCAE910083902D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = F84B21B61A090F8100AAB793 /* Project object */; @@ -2121,12 +2255,13 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; - 4368F838279665E00013419B /* Embed Frameworks */ = { + 2CAF5C1A2D01B2E200D3DCDD /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( + 2CAF5C172D01B2E200D3DCDD /* Ecosia.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -2677,6 +2812,136 @@ 2CAF5AE22D00AAEE00D3DCDD /* Bundle+Ecosia.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Ecosia.swift"; sourceTree = ""; }; 2CAF5AE42D00B1D300D3DCDD /* EcosiaLaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EcosiaLaunchScreen.xib; sourceTree = ""; }; 2CAF5AE52D00B1D300D3DCDD /* EcosiaLaunchScreenView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaLaunchScreenView.swift; sourceTree = ""; }; + 2CAF5AEA2D00D16700D3DCDD /* Bookmark.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bookmark.swift; sourceTree = ""; }; + 2CAF5AEB2D00D16700D3DCDD /* BookmarkParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkParser.swift; sourceTree = ""; }; + 2CAF5AEC2D00D16700D3DCDD /* BookmarkSerializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkSerializer.swift; sourceTree = ""; }; + 2CAF5AED2D00D16700D3DCDD /* Document+Safari.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Document+Safari.swift"; sourceTree = ""; }; + 2CAF5AEE2D00D16700D3DCDD /* String+CssQuery.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+CssQuery.swift"; sourceTree = ""; }; + 2CAF5AF02D00D16700D3DCDD /* BaseRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseRequest.swift; sourceTree = ""; }; + 2CAF5AF12D00D16700D3DCDD /* Requestable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Requestable.swift; sourceTree = ""; }; + 2CAF5AF32D00D16700D3DCDD /* HTTPClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPClient.swift; sourceTree = ""; }; + 2CAF5AF42D00D16700D3DCDD /* HTTPMethod.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPMethod.swift; sourceTree = ""; }; + 2CAF5AF52D00D16700D3DCDD /* URLSessionHTTPClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSessionHTTPClient.swift; sourceTree = ""; }; + 2CAF5AF62D00D16700D3DCDD /* URLSessionProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSessionProtocol.swift; sourceTree = ""; }; + 2CAF5AF82D00D16700D3DCDD /* Cookie.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cookie.swift; sourceTree = ""; }; + 2CAF5AF92D00D16700D3DCDD /* ReferralClaimRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReferralClaimRequest.swift; sourceTree = ""; }; + 2CAF5AFA2D00D16700D3DCDD /* ReferralCreateCodeRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReferralCreateCodeRequest.swift; sourceTree = ""; }; + 2CAF5AFB2D00D16700D3DCDD /* ReferralRefreshCodeRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReferralRefreshCodeRequest.swift; sourceTree = ""; }; + 2CAF5AFC2D00D16700D3DCDD /* Referrals.Model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Referrals.Model.swift; sourceTree = ""; }; + 2CAF5AFD2D00D16700D3DCDD /* Referrals.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Referrals.swift; sourceTree = ""; }; + 2CAF5AFF2D00D16700D3DCDD /* Scheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Scheme.swift; sourceTree = ""; }; + 2CAF5B002D00D16800D3DCDD /* Publisher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Publisher.swift; sourceTree = ""; }; + 2CAF5B012D00D16800D3DCDD /* TimestampProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimestampProvider.swift; sourceTree = ""; }; + 2CAF5B022D00D16800D3DCDD /* SingularConversionValueRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingularConversionValueRequest.swift; sourceTree = ""; }; + 2CAF5B032D00D16800D3DCDD /* SingularConversionValueResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingularConversionValueResponse.swift; sourceTree = ""; }; + 2CAF5B042D00D16800D3DCDD /* SingularEventRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingularEventRequest.swift; sourceTree = ""; }; + 2CAF5B052D00D16800D3DCDD /* SingularReponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingularReponse.swift; sourceTree = ""; }; + 2CAF5B062D00D16800D3DCDD /* SingularService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingularService.swift; sourceTree = ""; }; + 2CAF5B072D00D16800D3DCDD /* SingularSessionInfoSendRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingularSessionInfoSendRequest.swift; sourceTree = ""; }; + 2CAF5B092D00D16800D3DCDD /* Singular.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Singular.swift; sourceTree = ""; }; + 2CAF5B0A2D00D16800D3DCDD /* SingularAdNetworkHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingularAdNetworkHelper.swift; sourceTree = ""; }; + 2CAF5B0B2D00D16800D3DCDD /* SingularEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingularEvent.swift; sourceTree = ""; }; + 2CAF5B0E2D00D16800D3DCDD /* MMPProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MMPProvider.swift; sourceTree = ""; }; + 2CAF5B0F2D00D16800D3DCDD /* SKAdNetworkProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SKAdNetworkProtocol.swift; sourceTree = ""; }; + 2CAF5B112D00D16800D3DCDD /* AppDeviceInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDeviceInfo.swift; sourceTree = ""; }; + 2CAF5B122D00D16800D3DCDD /* Environment.Auth.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Environment.Auth.swift; sourceTree = ""; }; + 2CAF5B132D00D16800D3DCDD /* Environment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Environment.swift; sourceTree = ""; }; + 2CAF5B142D00D16800D3DCDD /* URLProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLProvider.swift; sourceTree = ""; }; + 2CAF5B172D00D16800D3DCDD /* TimeInterval+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TimeInterval+Extensions.swift"; sourceTree = ""; }; + 2CAF5B182D00D16800D3DCDD /* History.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = History.swift; sourceTree = ""; }; + 2CAF5B192D00D16900D3DCDD /* AppUpdateRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppUpdateRule.swift; sourceTree = ""; }; + 2CAF5B1A2D00D16900D3DCDD /* DeviceRegionChangeRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceRegionChangeRule.swift; sourceTree = ""; }; + 2CAF5B1B2D00D16900D3DCDD /* RefreshingRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshingRule.swift; sourceTree = ""; }; + 2CAF5B1C2D00D16900D3DCDD /* TimeBasedRefreshingRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeBasedRefreshingRule.swift; sourceTree = ""; }; + 2CAF5B1F2D00D16900D3DCDD /* Unleash.Model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Unleash.Model.swift; sourceTree = ""; }; + 2CAF5B202D00D16900D3DCDD /* Unleash.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Unleash.swift; sourceTree = ""; }; + 2CAF5B212D00D16900D3DCDD /* Unleash+RefreshComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Unleash+RefreshComponent.swift"; sourceTree = ""; }; + 2CAF5B222D00D16900D3DCDD /* UnleashFeatureManagementSessionInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnleashFeatureManagementSessionInitializer.swift; sourceTree = ""; }; + 2CAF5B232D00D16900D3DCDD /* UnleashRefreshConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnleashRefreshConfigurator.swift; sourceTree = ""; }; + 2CAF5B242D00D16900D3DCDD /* UnleashStartRequest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnleashStartRequest.swift; sourceTree = ""; }; + 2CAF5B262D00D16900D3DCDD /* FeatureManagementSessionInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureManagementSessionInitializer.swift; sourceTree = ""; }; + 2CAF5B282D00D16900D3DCDD /* Tab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tab.swift; sourceTree = ""; }; + 2CAF5B292D00D16900D3DCDD /* Tabs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tabs.swift; sourceTree = ""; }; + 2CAF5B2B2D00D16900D3DCDD /* News.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = News.swift; sourceTree = ""; }; + 2CAF5B2C2D00D16900D3DCDD /* NewsModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsModel.swift; sourceTree = ""; }; + 2CAF5B2E2D00D16900D3DCDD /* ObjectPersister.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectPersister.swift; sourceTree = ""; }; + 2CAF5B2F2D00D16900D3DCDD /* Date+TimestampProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Date+TimestampProvider.swift"; sourceTree = ""; }; + 2CAF5B302D00D16900D3DCDD /* Page.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Page.swift; sourceTree = ""; }; + 2CAF5B312D00D16900D3DCDD /* PageStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageStore.swift; sourceTree = ""; }; + 2CAF5B332D00D16900D3DCDD /* URLRequest+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URLRequest+Extensions.swift"; sourceTree = ""; }; + 2CAF5B342D00D16A00D3DCDD /* Encodable+Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Encodable+Dictionary.swift"; sourceTree = ""; }; + 2CAF5B352D00D16A00D3DCDD /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + 2CAF5B362D00D16A00D3DCDD /* URL+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URL+Extensions.swift"; sourceTree = ""; }; + 2CAF5B372D00D16A00D3DCDD /* FinancialReports.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FinancialReports.swift; sourceTree = ""; }; + 2CAF5B382D00D16A00D3DCDD /* InvestmentsProjection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InvestmentsProjection.swift; sourceTree = ""; }; + 2CAF5B392D00D16A00D3DCDD /* Statistics.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Statistics.swift; sourceTree = ""; }; + 2CAF5B3A2D00D16A00D3DCDD /* TreesProjection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TreesProjection.swift; sourceTree = ""; }; + 2CAF5B3C2D00D16A00D3DCDD /* EnvironmentFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentFetcher.swift; sourceTree = ""; }; + 2CAF5B3E2D00D16A00D3DCDD /* Local.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Local.swift; sourceTree = ""; }; + 2CAF5B3F2D00D16B00D3DCDD /* Language.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Language.swift; sourceTree = ""; }; + 2CAF5B402D00D16B00D3DCDD /* Favourites.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Favourites.swift; sourceTree = ""; }; + 2CAF5B412D00D16B00D3DCDD /* List.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = List.swift; sourceTree = ""; }; + 2CAF5B422D00D16B00D3DCDD /* AdultFilter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdultFilter.swift; sourceTree = ""; }; + 2CAF5B432D00D16B00D3DCDD /* Images.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Images.swift; sourceTree = ""; }; + 2CAF5B442D00D16B00D3DCDD /* UserDefaults+ObjectPersister.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserDefaults+ObjectPersister.swift"; sourceTree = ""; }; + 2CAF5B452D00D16B00D3DCDD /* SearchesCounter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchesCounter.swift; sourceTree = ""; }; + 2CAF5B462D00D16C00D3DCDD /* FileManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileManager.swift; sourceTree = ""; }; + 2CAF5B472D00D16C00D3DCDD /* Market.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Market.swift; sourceTree = ""; }; + 2CAF5B482D00D16C00D3DCDD /* Bundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bundle.swift; sourceTree = ""; }; + 2CAF5B492D00D16C00D3DCDD /* RegionLocatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RegionLocatable.swift; sourceTree = ""; }; + 2CAF5B4A2D00D16C00D3DCDD /* CloudFlareKeyProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudFlareKeyProvider.swift; sourceTree = ""; }; + 2CAF5B4B2D00D16C00D3DCDD /* Locale+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Locale+Extensions.swift"; sourceTree = ""; }; + 2CAF5B9D2D00D1A600D3DCDD /* User5_3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User5_3.swift; sourceTree = ""; }; + 2CAF5B9F2D00D1A600D3DCDD /* BookmarkFixtures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkFixtures.swift; sourceTree = ""; }; + 2CAF5BA02D00D1A600D3DCDD /* HTTPClientMock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPClientMock.swift; sourceTree = ""; }; + 2CAF5BA12D00D1A600D3DCDD /* MockTimestampProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockTimestampProvider.swift; sourceTree = ""; }; + 2CAF5BA22D00D1A600D3DCDD /* MockURLSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockURLSession.swift; sourceTree = ""; }; + 2CAF5BA32D00D1A600D3DCDD /* MockURLSessionProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockURLSessionProtocol.swift; sourceTree = ""; }; + 2CAF5BA52D00D1A600D3DCDD /* ListTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTests.swift; sourceTree = ""; }; + 2CAF5BA62D00D1A600D3DCDD /* URLTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLTests.swift; sourceTree = ""; }; + 2CAF5BA72D00D1A700D3DCDD /* FeatureFlaggingSessionInitializerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureFlaggingSessionInitializerTests.swift; sourceTree = ""; }; + 2CAF5BA82D00D1A700D3DCDD /* export_bookmark_ecosia.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = export_bookmark_ecosia.html; sourceTree = ""; }; + 2CAF5BA92D00D1A700D3DCDD /* import_input_bookmark_chrome.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = import_input_bookmark_chrome.html; sourceTree = ""; }; + 2CAF5BAA2D00D1A700D3DCDD /* import_input_bookmark_firefox.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = import_input_bookmark_firefox.html; sourceTree = ""; }; + 2CAF5BAB2D00D1A700D3DCDD /* import_input_bookmark_safari.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = import_input_bookmark_safari.html; sourceTree = ""; }; + 2CAF5BAC2D00D1A700D3DCDD /* import_output_bookmark_chrome.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = import_output_bookmark_chrome.txt; sourceTree = ""; }; + 2CAF5BAD2D00D1A700D3DCDD /* import_output_bookmark_firefox.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = import_output_bookmark_firefox.txt; sourceTree = ""; }; + 2CAF5BAE2D00D1A700D3DCDD /* import_output_bookmark_safari.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = import_output_bookmark_safari.txt; sourceTree = ""; }; + 2CAF5BB02D00D1A700D3DCDD /* notifications.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = notifications.json; sourceTree = ""; }; + 2CAF5BB12D00D1A700D3DCDD /* referrals.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = referrals.json; sourceTree = ""; }; + 2CAF5BB32D00D1A700D3DCDD /* SingularTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingularTests.swift; sourceTree = ""; }; + 2CAF5BB42D00D1A700D3DCDD /* SingularServiceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingularServiceTests.swift; sourceTree = ""; }; + 2CAF5BB52D00D1A700D3DCDD /* UpgradeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpgradeTests.swift; sourceTree = ""; }; + 2CAF5BB62D00D1A700D3DCDD /* UnleashFeatureManagementSessionInitializerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnleashFeatureManagementSessionInitializerTests.swift; sourceTree = ""; }; + 2CAF5BB72D00D1A700D3DCDD /* BookmarkParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkParserTests.swift; sourceTree = ""; }; + 2CAF5BB82D00D1A700D3DCDD /* NewsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsTests.swift; sourceTree = ""; }; + 2CAF5BB92D00D1A800D3DCDD /* BookmarkSerializerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkSerializerTests.swift; sourceTree = ""; }; + 2CAF5BBA2D00D1A800D3DCDD /* ImagesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagesTests.swift; sourceTree = ""; }; + 2CAF5BBB2D00D1A800D3DCDD /* StatisticsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatisticsTests.swift; sourceTree = ""; }; + 2CAF5BBC2D00D1A800D3DCDD /* ReferralsModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReferralsModelTests.swift; sourceTree = ""; }; + 2CAF5BBD2D00D1A800D3DCDD /* HistoryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HistoryTests.swift; sourceTree = ""; }; + 2CAF5BBE2D00D1A800D3DCDD /* BookmarkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkTests.swift; sourceTree = ""; }; + 2CAF5BBF2D00D1A800D3DCDD /* SnapshotsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotsTests.swift; sourceTree = ""; }; + 2CAF5BC02D00D1A800D3DCDD /* LocalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalTests.swift; sourceTree = ""; }; + 2CAF5BC12D00D1A900D3DCDD /* SingularAdNetworkHelperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SingularAdNetworkHelperTests.swift; sourceTree = ""; }; + 2CAF5BC22D00D1A900D3DCDD /* TabsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabsTests.swift; sourceTree = ""; }; + 2CAF5BC32D00D1A900D3DCDD /* TreesProjectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TreesProjectionTests.swift; sourceTree = ""; }; + 2CAF5BC42D00D1A900D3DCDD /* UnleashTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnleashTests.swift; sourceTree = ""; }; + 2CAF5BC52D00D1A900D3DCDD /* ProductionURLProviderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductionURLProviderTests.swift; sourceTree = ""; }; + 2CAF5BC62D00D1A900D3DCDD /* StagingURLProviderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StagingURLProviderTests.swift; sourceTree = ""; }; + 2CAF5BC72D00D1A900D3DCDD /* URLProviderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLProviderTests.swift; sourceTree = ""; }; + 2CAF5BC92D00D1A900D3DCDD /* UserStateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserStateTests.swift; sourceTree = ""; }; + 2CAF5BCA2D00D1A900D3DCDD /* SearchesCounterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchesCounterTests.swift; sourceTree = ""; }; + 2CAF5BCB2D00D1AA00D3DCDD /* ReferralsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReferralsTests.swift; sourceTree = ""; }; + 2CAF5BCC2D00D1AA00D3DCDD /* FinancialReportsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FinancialReportsTests.swift; sourceTree = ""; }; + 2CAF5BCD2D00D1AA00D3DCDD /* CookieTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CookieTests.swift; sourceTree = ""; }; + 2CAF5BCE2D00D1AA00D3DCDD /* InvestmentsProjectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InvestmentsProjectionTests.swift; sourceTree = ""; }; + 2CAF5BCF2D00D1AA00D3DCDD /* PublishersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublishersTests.swift; sourceTree = ""; }; + 2CAF5BD02D00D1AA00D3DCDD /* UnleashRefreshConfiguratorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnleashRefreshConfiguratorTests.swift; sourceTree = ""; }; + 2CAF5BD12D00D1AA00D3DCDD /* UserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserTests.swift; sourceTree = ""; }; + 2CAF5BD22D00D1AA00D3DCDD /* LanguageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LanguageTests.swift; sourceTree = ""; }; + 2CAF5BD32D00D1AB00D3DCDD /* FavouritesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FavouritesTests.swift; sourceTree = ""; }; + 2CAF5BD42D00D1AB00D3DCDD /* URLRequestTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLRequestTests.swift; sourceTree = ""; }; 2CB1728B2C61336D008551E2 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.5.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; 2CB1A6591FDEA8B60084E96D /* NewTabSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewTabSettings.swift; sourceTree = ""; }; 2CB56E3E1E926BFB00AF7586 /* ToolbarTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarTest.swift; sourceTree = ""; }; @@ -8297,7 +8562,6 @@ 43A878FE27AC39D30071C372 /* RustMozillaAppServices.framework in Frameworks */, 5A87148A292EA1520039A5BD /* Fuzi in Frameworks */, 433F87D02788ECDD00693368 /* GCDWebServers in Frameworks */, - 2CE294492B7CDD78006C22B2 /* Core in Frameworks */, 5A70EF10295DFD4900790249 /* Common in Frameworks */, 5A68F0AB2AF2E5E00089AC62 /* TabDataStore in Frameworks */, C8CC4F8725253E79003FDE1F /* WidgetKit.framework in Frameworks */, @@ -8311,11 +8575,12 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 122935A92CE79CC800EC1297 /* Shared.framework in Frameworks */, + 2CAF5C1F2D01B44400D3DCDD /* Sentry in Frameworks */, 122935B52CE79EF900EC1297 /* SnowplowTracker in Frameworks */, + 2CAF5C1D2D01B40B00D3DCDD /* SwiftSoup in Frameworks */, 122935932CE78ED500EC1297 /* BrazeUI in Frameworks */, 122935912CE78ED500EC1297 /* BrazeKit in Frameworks */, - 1229358F2CE78EC400EC1297 /* Core in Frameworks */, + 2CAF5C212D01B5F300D3DCDD /* Common in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -8336,7 +8601,6 @@ C820439A2523DC4500740B71 /* libStorage.a in Frameworks */, 5A70EF12295DFD6400790249 /* Common in Frameworks */, D09A0CDC1FAA24CC009A0273 /* libAccount.a in Frameworks */, - 2C1298AC2BF5EE3E005AE4E4 /* Core in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -8354,9 +8618,9 @@ buildActionMask = 2147483647; files = ( 43A878FD27AB4A110071C372 /* RustMozillaAppServices.framework in Frameworks */, + 2CAF5C162D01B2E200D3DCDD /* Ecosia.framework in Frameworks */, 8A88815C2B2103AD009635AE /* WebEngine in Frameworks */, 8A88815A2B20FFE0009635AE /* GCDWebServers in Frameworks */, - 2CE2E24D2B9B1FCB00973C16 /* Core in Frameworks */, 5A9FF8492942454600DF9FBB /* Common in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -8391,7 +8655,6 @@ 435C85F02788F4D00072B526 /* Glean in Frameworks */, 433F87CE2788EAB600693368 /* GCDWebServers in Frameworks */, 5A06135A29D6052E008F3D38 /* TabDataStore in Frameworks */, - 2CE294472B7CDD56006C22B2 /* Core in Frameworks */, 216A0D762A40E7AB008077BA /* Redux in Frameworks */, 7B8A47F61D01D3B400C07734 /* PassKit.framework in Frameworks */, 5A8FD0EC293A7D5E00333AA7 /* SnapKit in Frameworks */, @@ -8404,7 +8667,6 @@ files = ( 2C69DA822C62459C00D7F69F /* libz.tbd in Frameworks */, 2C69DA7F2C62458300D7F69F /* RustMozillaAppServices.framework in Frameworks */, - 2C69DA812C62459200D7F69F /* Core in Frameworks */, 2C6C908F2C614A6C007D9B43 /* SnapshotTesting in Frameworks */, 2C69DA7B2C6225C400D7F69F /* Common in Frameworks */, ); @@ -8432,6 +8694,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2CAF5C222D01B62900D3DCDD /* Ecosia.framework in Frameworks */, 43BE5809278BA9D700491291 /* RustMozillaAppServices.framework in Frameworks */, 8A88815E2B21071E009635AE /* GCDWebServers in Frameworks */, 5A37861429A2BFB9006B3A34 /* Common in Frameworks */, @@ -8484,7 +8747,6 @@ buildActionMask = 2147483647; files = ( 43F93C2827A8683E009833D9 /* RustMozillaAppServices.framework in Frameworks */, - 2C1F23BD2B9F405E00186F55 /* Core in Frameworks */, 8A8BAE142B21110000D774EB /* GCDWebServers in Frameworks */, E6231C081B90A71E005ABB0D /* libz.tbd in Frameworks */, ); @@ -8500,7 +8762,6 @@ C82043AF2523DC9600740B71 /* Sync.framework in Frameworks */, 2C1298A82BF5EE23005AE4E4 /* libStorage.a in Frameworks */, 5A70EF14295DFD7C00790249 /* Common in Frameworks */, - 2CF4DA632BB31970001C340A /* Core in Frameworks */, C877039625222FDC006E38EB /* Shared.framework in Frameworks */, 0B75AEA91AC20FB20015E5DC /* ImageIO.framework in Frameworks */, ); @@ -8539,18 +8800,17 @@ 1229356B2CE78D0A00EC1297 /* Ecosia */ = { isa = PBXGroup; children = ( + 2CAF5AE92D00D14300D3DCDD /* Core */, 2CD2663A2CFE421C00A040A7 /* Extensions */, 2CD266312CFE403800A040A7 /* Experiments */, 2CD263EF2CFDC76800A040A7 /* Analytics */, 2CD264082CFDC76900A040A7 /* Auth */, - 2CD263C22CFDC76800A040A7 /* Braze */, 2CD264072CFDC76900A040A7 /* Entitlements */, 2CD264752CFDC76A00A040A7 /* Fake */, 2CD263FF2CFDC76900A040A7 /* FeatureManagement */, 2CD263EB2CFDC76800A040A7 /* Helpers */, 2CD263E12CFDC76800A040A7 /* L10N */, 2CD263F72CFDC76900A040A7 /* markets.json */, - 2CD264012CFDC76900A040A7 /* MMP */, 1229356C2CE78D0A00EC1297 /* Ecosia.h */, 1229359D2CE792B700EC1297 /* README.md */, 12E604442CECADDA009A7BEC /* Info.plist */, @@ -8561,6 +8821,7 @@ 122935792CE78D0A00EC1297 /* EcosiaTests */ = { isa = PBXGroup; children = ( + 2CAF5B9C2D00D18300D3DCDD /* Core */, 2CD262A82CFDC5EB00A040A7 /* Analytics */, 2CD262A22CFDC5EA00A040A7 /* ClimateImpactCounter */, 2CD262982CFDC5EA00A040A7 /* IntegrationTests */, @@ -9005,6 +9266,336 @@ path = LaunchScreen; sourceTree = ""; }; + 2CAF5AE92D00D14300D3DCDD /* Core */ = { + isa = PBXGroup; + children = ( + 2CAF5B422D00D16B00D3DCDD /* AdultFilter.swift */, + 2CAF5B112D00D16800D3DCDD /* AppDeviceInfo.swift */, + 2CAF5B3D2D00D16A00D3DCDD /* Auth */, + 2CAF5AEF2D00D16700D3DCDD /* Bookmarks */, + 2CAF5B482D00D16C00D3DCDD /* Bundle.swift */, + 2CAF5B4A2D00D16C00D3DCDD /* CloudFlareKeyProvider.swift */, + 2CAF5AF82D00D16700D3DCDD /* Cookie.swift */, + 2CAF5B2F2D00D16900D3DCDD /* Date+TimestampProvider.swift */, + 2CAF5B342D00D16A00D3DCDD /* Encodable+Dictionary.swift */, + 2CAF5B152D00D16800D3DCDD /* Environment */, + 2CAF5B3C2D00D16A00D3DCDD /* EnvironmentFetcher.swift */, + 2CAF5B402D00D16B00D3DCDD /* Favourites.swift */, + 2CAF5B272D00D16900D3DCDD /* FeatureManagement */, + 2CAF5B462D00D16C00D3DCDD /* FileManager.swift */, + 2CAF5B182D00D16800D3DCDD /* History.swift */, + 2CAF5AF72D00D16700D3DCDD /* HTTPClient */, + 2CAF5B432D00D16B00D3DCDD /* Images.swift */, + 2CAF5B3F2D00D16B00D3DCDD /* Language.swift */, + 2CAF5B412D00D16B00D3DCDD /* List.swift */, + 2CAF5B3E2D00D16A00D3DCDD /* Local.swift */, + 2CAF5B4B2D00D16C00D3DCDD /* Locale+Extensions.swift */, + 2CAF5B472D00D16C00D3DCDD /* Market.swift */, + 2CAF5B102D00D16800D3DCDD /* MMP */, + 2CAF5B2D2D00D16900D3DCDD /* News */, + 2CAF5B2E2D00D16900D3DCDD /* ObjectPersister.swift */, + 2CAF5B162D00D16800D3DCDD /* OptInReminder */, + 2CAF5B322D00D16900D3DCDD /* Pages */, + 2CAF5B002D00D16800D3DCDD /* Publisher.swift */, + 2CAF5AFE2D00D16700D3DCDD /* Referrals */, + 2CAF5B492D00D16C00D3DCDD /* RegionLocatable.swift */, + 2CAF5AFF2D00D16700D3DCDD /* Scheme.swift */, + 2CAF5B452D00D16B00D3DCDD /* SearchesCounter.swift */, + 2CAF5B3B2D00D16A00D3DCDD /* Statistics */, + 2CAF5B2A2D00D16900D3DCDD /* Tabs */, + 2CAF5B172D00D16800D3DCDD /* TimeInterval+Extensions.swift */, + 2CAF5B012D00D16800D3DCDD /* TimestampProvider.swift */, + 2CAF5B362D00D16A00D3DCDD /* URL+Extensions.swift */, + 2CAF5B332D00D16900D3DCDD /* URLRequest+Extensions.swift */, + 2CAF5B352D00D16A00D3DCDD /* User.swift */, + 2CAF5B442D00D16B00D3DCDD /* UserDefaults+ObjectPersister.swift */, + 2CD263C22CFDC76800A040A7 /* Braze */, + ); + path = Core; + sourceTree = ""; + }; + 2CAF5AEF2D00D16700D3DCDD /* Bookmarks */ = { + isa = PBXGroup; + children = ( + 2CAF5AEA2D00D16700D3DCDD /* Bookmark.swift */, + 2CAF5AEB2D00D16700D3DCDD /* BookmarkParser.swift */, + 2CAF5AEC2D00D16700D3DCDD /* BookmarkSerializer.swift */, + 2CAF5AED2D00D16700D3DCDD /* Document+Safari.swift */, + 2CAF5AEE2D00D16700D3DCDD /* String+CssQuery.swift */, + ); + path = Bookmarks; + sourceTree = ""; + }; + 2CAF5AF22D00D16700D3DCDD /* Requestable */ = { + isa = PBXGroup; + children = ( + 2CAF5AF02D00D16700D3DCDD /* BaseRequest.swift */, + 2CAF5AF12D00D16700D3DCDD /* Requestable.swift */, + ); + path = Requestable; + sourceTree = ""; + }; + 2CAF5AF72D00D16700D3DCDD /* HTTPClient */ = { + isa = PBXGroup; + children = ( + 2CAF5AF22D00D16700D3DCDD /* Requestable */, + 2CAF5AF32D00D16700D3DCDD /* HTTPClient.swift */, + 2CAF5AF42D00D16700D3DCDD /* HTTPMethod.swift */, + 2CAF5AF52D00D16700D3DCDD /* URLSessionHTTPClient.swift */, + 2CAF5AF62D00D16700D3DCDD /* URLSessionProtocol.swift */, + ); + path = HTTPClient; + sourceTree = ""; + }; + 2CAF5AFE2D00D16700D3DCDD /* Referrals */ = { + isa = PBXGroup; + children = ( + 2CAF5AF92D00D16700D3DCDD /* ReferralClaimRequest.swift */, + 2CAF5AFA2D00D16700D3DCDD /* ReferralCreateCodeRequest.swift */, + 2CAF5AFB2D00D16700D3DCDD /* ReferralRefreshCodeRequest.swift */, + 2CAF5AFC2D00D16700D3DCDD /* Referrals.Model.swift */, + 2CAF5AFD2D00D16700D3DCDD /* Referrals.swift */, + ); + path = Referrals; + sourceTree = ""; + }; + 2CAF5B082D00D16800D3DCDD /* Service */ = { + isa = PBXGroup; + children = ( + 2CAF5B022D00D16800D3DCDD /* SingularConversionValueRequest.swift */, + 2CAF5B032D00D16800D3DCDD /* SingularConversionValueResponse.swift */, + 2CAF5B042D00D16800D3DCDD /* SingularEventRequest.swift */, + 2CAF5B052D00D16800D3DCDD /* SingularReponse.swift */, + 2CAF5B062D00D16800D3DCDD /* SingularService.swift */, + 2CAF5B072D00D16800D3DCDD /* SingularSessionInfoSendRequest.swift */, + ); + path = Service; + sourceTree = ""; + }; + 2CAF5B0C2D00D16800D3DCDD /* Singular */ = { + isa = PBXGroup; + children = ( + 2CAF5B082D00D16800D3DCDD /* Service */, + 2CAF5B092D00D16800D3DCDD /* Singular.swift */, + 2CAF5B0A2D00D16800D3DCDD /* SingularAdNetworkHelper.swift */, + 2CAF5B0B2D00D16800D3DCDD /* SingularEvent.swift */, + ); + path = Singular; + sourceTree = ""; + }; + 2CAF5B102D00D16800D3DCDD /* MMP */ = { + isa = PBXGroup; + children = ( + 2CD264002CFDC76900A040A7 /* MMP.swift */, + 2CAF5B0C2D00D16800D3DCDD /* Singular */, + 2CAF5B0E2D00D16800D3DCDD /* MMPProvider.swift */, + 2CAF5B0F2D00D16800D3DCDD /* SKAdNetworkProtocol.swift */, + ); + path = MMP; + sourceTree = ""; + }; + 2CAF5B152D00D16800D3DCDD /* Environment */ = { + isa = PBXGroup; + children = ( + 2CAF5B122D00D16800D3DCDD /* Environment.Auth.swift */, + 2CAF5B132D00D16800D3DCDD /* Environment.swift */, + 2CAF5B142D00D16800D3DCDD /* URLProvider.swift */, + ); + path = Environment; + sourceTree = ""; + }; + 2CAF5B162D00D16800D3DCDD /* OptInReminder */ = { + isa = PBXGroup; + children = ( + ); + path = OptInReminder; + sourceTree = ""; + }; + 2CAF5B1D2D00D16900D3DCDD /* RefreshingRule */ = { + isa = PBXGroup; + children = ( + 2CAF5B192D00D16900D3DCDD /* AppUpdateRule.swift */, + 2CAF5B1A2D00D16900D3DCDD /* DeviceRegionChangeRule.swift */, + 2CAF5B1B2D00D16900D3DCDD /* RefreshingRule.swift */, + 2CAF5B1C2D00D16900D3DCDD /* TimeBasedRefreshingRule.swift */, + ); + path = RefreshingRule; + sourceTree = ""; + }; + 2CAF5B1E2D00D16900D3DCDD /* RefreshingComponent */ = { + isa = PBXGroup; + children = ( + 2CAF5B1D2D00D16900D3DCDD /* RefreshingRule */, + ); + path = RefreshingComponent; + sourceTree = ""; + }; + 2CAF5B252D00D16900D3DCDD /* Unleash */ = { + isa = PBXGroup; + children = ( + 2CAF5B1E2D00D16900D3DCDD /* RefreshingComponent */, + 2CAF5B1F2D00D16900D3DCDD /* Unleash.Model.swift */, + 2CAF5B202D00D16900D3DCDD /* Unleash.swift */, + 2CAF5B212D00D16900D3DCDD /* Unleash+RefreshComponent.swift */, + 2CAF5B222D00D16900D3DCDD /* UnleashFeatureManagementSessionInitializer.swift */, + 2CAF5B232D00D16900D3DCDD /* UnleashRefreshConfigurator.swift */, + 2CAF5B242D00D16900D3DCDD /* UnleashStartRequest.swift */, + ); + path = Unleash; + sourceTree = ""; + }; + 2CAF5B272D00D16900D3DCDD /* FeatureManagement */ = { + isa = PBXGroup; + children = ( + 2CAF5B252D00D16900D3DCDD /* Unleash */, + 2CAF5B262D00D16900D3DCDD /* FeatureManagementSessionInitializer.swift */, + ); + path = FeatureManagement; + sourceTree = ""; + }; + 2CAF5B2A2D00D16900D3DCDD /* Tabs */ = { + isa = PBXGroup; + children = ( + 2CAF5B282D00D16900D3DCDD /* Tab.swift */, + 2CAF5B292D00D16900D3DCDD /* Tabs.swift */, + ); + path = Tabs; + sourceTree = ""; + }; + 2CAF5B2D2D00D16900D3DCDD /* News */ = { + isa = PBXGroup; + children = ( + 2CAF5B2B2D00D16900D3DCDD /* News.swift */, + 2CAF5B2C2D00D16900D3DCDD /* NewsModel.swift */, + ); + path = News; + sourceTree = ""; + }; + 2CAF5B322D00D16900D3DCDD /* Pages */ = { + isa = PBXGroup; + children = ( + 2CAF5B302D00D16900D3DCDD /* Page.swift */, + 2CAF5B312D00D16900D3DCDD /* PageStore.swift */, + ); + path = Pages; + sourceTree = ""; + }; + 2CAF5B3B2D00D16A00D3DCDD /* Statistics */ = { + isa = PBXGroup; + children = ( + 2CAF5B372D00D16A00D3DCDD /* FinancialReports.swift */, + 2CAF5B382D00D16A00D3DCDD /* InvestmentsProjection.swift */, + 2CAF5B392D00D16A00D3DCDD /* Statistics.swift */, + 2CAF5B3A2D00D16A00D3DCDD /* TreesProjection.swift */, + ); + path = Statistics; + sourceTree = ""; + }; + 2CAF5B3D2D00D16A00D3DCDD /* Auth */ = { + isa = PBXGroup; + children = ( + ); + path = Auth; + sourceTree = ""; + }; + 2CAF5B9C2D00D18300D3DCDD /* Core */ = { + isa = PBXGroup; + children = ( + 2CAF5BB72D00D1A700D3DCDD /* BookmarkParserTests.swift */, + 2CAF5BB92D00D1A800D3DCDD /* BookmarkSerializerTests.swift */, + 2CAF5BBE2D00D1A800D3DCDD /* BookmarkTests.swift */, + 2CAF5BCD2D00D1AA00D3DCDD /* CookieTests.swift */, + 2CAF5BD32D00D1AB00D3DCDD /* FavouritesTests.swift */, + 2CAF5BA72D00D1A700D3DCDD /* FeatureFlaggingSessionInitializerTests.swift */, + 2CAF5BCC2D00D1AA00D3DCDD /* FinancialReportsTests.swift */, + 2CAF5BBD2D00D1A800D3DCDD /* HistoryTests.swift */, + 2CAF5BBA2D00D1A800D3DCDD /* ImagesTests.swift */, + 2CAF5BCE2D00D1AA00D3DCDD /* InvestmentsProjectionTests.swift */, + 2CAF5BD22D00D1AA00D3DCDD /* LanguageTests.swift */, + 2CAF5BA52D00D1A600D3DCDD /* ListTests.swift */, + 2CAF5BC02D00D1A800D3DCDD /* LocalTests.swift */, + 2CAF5BB82D00D1A700D3DCDD /* NewsTests.swift */, + 2CAF5BCF2D00D1AA00D3DCDD /* PublishersTests.swift */, + 2CAF5BBC2D00D1A800D3DCDD /* ReferralsModelTests.swift */, + 2CAF5BCB2D00D1AA00D3DCDD /* ReferralsTests.swift */, + 2CAF5BB22D00D1A700D3DCDD /* Resources */, + 2CAF5BCA2D00D1A900D3DCDD /* SearchesCounterTests.swift */, + 2CAF5BC12D00D1A900D3DCDD /* SingularAdNetworkHelperTests.swift */, + 2CAF5BB42D00D1A700D3DCDD /* SingularServiceTests.swift */, + 2CAF5BB32D00D1A700D3DCDD /* SingularTests.swift */, + 2CAF5BBF2D00D1A800D3DCDD /* SnapshotsTests.swift */, + 2CAF5BBB2D00D1A800D3DCDD /* StatisticsTests.swift */, + 2CAF5BC22D00D1A900D3DCDD /* TabsTests.swift */, + 2CAF5BA42D00D1A600D3DCDD /* Tools */, + 2CAF5BC32D00D1A900D3DCDD /* TreesProjectionTests.swift */, + 2CAF5BB62D00D1A700D3DCDD /* UnleashFeatureManagementSessionInitializerTests.swift */, + 2CAF5BD02D00D1AA00D3DCDD /* UnleashRefreshConfiguratorTests.swift */, + 2CAF5BC42D00D1A900D3DCDD /* UnleashTests.swift */, + 2CAF5BB52D00D1A700D3DCDD /* UpgradeTests.swift */, + 2CAF5BC82D00D1A900D3DCDD /* URLProviderDependantTests */, + 2CAF5BD42D00D1AB00D3DCDD /* URLRequestTests.swift */, + 2CAF5BA62D00D1A600D3DCDD /* URLTests.swift */, + 2CAF5BC92D00D1A900D3DCDD /* UserStateTests.swift */, + 2CAF5BD12D00D1AA00D3DCDD /* UserTests.swift */, + 2CAF5B9E2D00D1A600D3DCDD /* Versions */, + ); + path = Core; + sourceTree = ""; + }; + 2CAF5B9E2D00D1A600D3DCDD /* Versions */ = { + isa = PBXGroup; + children = ( + 2CAF5B9D2D00D1A600D3DCDD /* User5_3.swift */, + ); + path = Versions; + sourceTree = ""; + }; + 2CAF5BA42D00D1A600D3DCDD /* Tools */ = { + isa = PBXGroup; + children = ( + 2CAF5B9F2D00D1A600D3DCDD /* BookmarkFixtures.swift */, + 2CAF5BA02D00D1A600D3DCDD /* HTTPClientMock.swift */, + 2CAF5BA12D00D1A600D3DCDD /* MockTimestampProvider.swift */, + 2CAF5BA22D00D1A600D3DCDD /* MockURLSession.swift */, + 2CAF5BA32D00D1A600D3DCDD /* MockURLSessionProtocol.swift */, + ); + path = Tools; + sourceTree = ""; + }; + 2CAF5BAF2D00D1A700D3DCDD /* Bookmarks */ = { + isa = PBXGroup; + children = ( + 2CAF5BA82D00D1A700D3DCDD /* export_bookmark_ecosia.html */, + 2CAF5BA92D00D1A700D3DCDD /* import_input_bookmark_chrome.html */, + 2CAF5BAA2D00D1A700D3DCDD /* import_input_bookmark_firefox.html */, + 2CAF5BAB2D00D1A700D3DCDD /* import_input_bookmark_safari.html */, + 2CAF5BAC2D00D1A700D3DCDD /* import_output_bookmark_chrome.txt */, + 2CAF5BAD2D00D1A700D3DCDD /* import_output_bookmark_firefox.txt */, + 2CAF5BAE2D00D1A700D3DCDD /* import_output_bookmark_safari.txt */, + ); + path = Bookmarks; + sourceTree = ""; + }; + 2CAF5BB22D00D1A700D3DCDD /* Resources */ = { + isa = PBXGroup; + children = ( + 2CAF5BAF2D00D1A700D3DCDD /* Bookmarks */, + 2CAF5BB02D00D1A700D3DCDD /* notifications.json */, + 2CAF5BB12D00D1A700D3DCDD /* referrals.json */, + ); + path = Resources; + sourceTree = ""; + }; + 2CAF5BC82D00D1A900D3DCDD /* URLProviderDependantTests */ = { + isa = PBXGroup; + children = ( + 2CAF5BC52D00D1A900D3DCDD /* ProductionURLProviderTests.swift */, + 2CAF5BC62D00D1A900D3DCDD /* StagingURLProviderTests.swift */, + 2CAF5BC72D00D1A900D3DCDD /* URLProviderTests.swift */, + ); + path = URLProviderDependantTests; + sourceTree = ""; + }; 2CBCAAFA2B88EEE40080AD68 /* Configuration */ = { isa = PBXGroup; children = ( @@ -9494,14 +10085,6 @@ path = FeatureManagement; sourceTree = ""; }; - 2CD264012CFDC76900A040A7 /* MMP */ = { - isa = PBXGroup; - children = ( - 2CD264002CFDC76900A040A7 /* MMP.swift */, - ); - path = MMP; - sourceTree = ""; - }; 2CD264042CFDC76900A040A7 /* AppExtensions */ = { isa = PBXGroup; children = ( @@ -13290,7 +13873,6 @@ 5A70EF0F295DFD4900790249 /* Common */, 5A5AB97F296CA03500485E06 /* SiteImageView */, 5A68F0AA2AF2E5E00089AC62 /* TabDataStore */, - 2CE294482B7CDD78006C22B2 /* Core */, ); productName = WidgetKitExtension; productReference = 047F9B2724E1FE1C00CD7DF7 /* WidgetKitExtension.appex */; @@ -13311,10 +13893,12 @@ ); name = Ecosia; packageProductDependencies = ( - 1229358E2CE78EC400EC1297 /* Core */, 122935902CE78ED500EC1297 /* BrazeKit */, 122935922CE78ED500EC1297 /* BrazeUI */, 122935B42CE79EF900EC1297 /* SnowplowTracker */, + 2CAF5C1C2D01B40B00D3DCDD /* SwiftSoup */, + 2CAF5C1E2D01B44400D3DCDD /* Sentry */, + 2CAF5C202D01B5F300D3DCDD /* Common */, ); productName = Ecosia; productReference = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; @@ -13358,7 +13942,6 @@ packageProductDependencies = ( 5A87148B292EA1640039A5BD /* Fuzi */, 5A70EF11295DFD6400790249 /* Common */, - 2C1298AB2BF5EE3E005AE4E4 /* Core */, ); productName = Sync; productReference = 2827315E1ABC9BE600AA1954 /* Sync.framework */; @@ -13392,18 +13975,18 @@ 288A2D811AB8B3260023ABC3 /* Sources */, 288A2D821AB8B3260023ABC3 /* Frameworks */, 288A2D841AB8B3260023ABC3 /* Resources */, - 4368F838279665E00013419B /* Embed Frameworks */, + 2CAF5C1A2D01B2E200D3DCDD /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( + 2CAF5C192D01B2E200D3DCDD /* PBXTargetDependency */, ); name = Shared; packageProductDependencies = ( 5A9FF8482942454600DF9FBB /* Common */, 8A8881592B20FFE0009635AE /* GCDWebServers */, 8A88815B2B2103AD009635AE /* WebEngine */, - 2CE2E24C2B9B1FCB00973C16 /* Core */, ); productName = Shared; productReference = 288A2D861AB8B3260023ABC3 /* Shared.framework */; @@ -13426,7 +14009,6 @@ packageProductDependencies = ( 2C6C908E2C614A6C007D9B43 /* SnapshotTesting */, 2C69DA7A2C6225C400D7F69F /* Common */, - 2C69DA802C62459200D7F69F /* Core */, ); productName = EcosiaSnapshotTests; productReference = 2C6C90822C614A16007D9B43 /* EcosiaSnapshotTests.xctest */; @@ -13649,7 +14231,6 @@ 216A0D752A40E7AB008077BA /* Redux */, 8AF2D0FB2A5F272A00C7DD69 /* ComponentLibrary */, 2C6189F02B7B7D5D006B70D7 /* SnowplowTracker */, - 2CE294462B7CDD56006C22B2 /* Core */, 126509842CD925B40011BA36 /* BrazeKit */, 126509862CD925B40011BA36 /* BrazeUI */, ); @@ -13674,7 +14255,6 @@ name = ClientTests; packageProductDependencies = ( 8A8BAE132B21110000D774EB /* GCDWebServers */, - 2C1F23BC2B9F405E00186F55 /* Core */, ); productName = ClientTests; productReference = F84B21D31A090F8100AAB793 /* ClientTests.xctest */; @@ -13701,7 +14281,6 @@ 5A87148D292EA3270039A5BD /* Fuzi */, 5A8FD0ED293A7D6D00333AA7 /* SnapKit */, 5A70EF13295DFD7C00790249 /* Common */, - 2CF4DA622BB31970001C340A /* Core */, ); productName = ShareToFirefox; productReference = F84B22491A0920C600AAB793 /* ShareTo.appex */; @@ -13960,11 +14539,11 @@ 43AFC0E027967BFA0039DDF4 /* XCRemoteSwiftPackageReference "Fuzi" */, 43C6A47D27A0679300C79856 /* XCRemoteSwiftPackageReference "MappaMundi" */, 5A37861729A2C337006B3A34 /* XCRemoteSwiftPackageReference "sentry-cocoa" */, - 2C61887D2B7A89E4006B70D7 /* XCRemoteSwiftPackageReference "ios-core" */, 2C6189EF2B7B7D48006B70D7 /* XCRemoteSwiftPackageReference "snowplow-ios-tracker" */, 2CCFB3D82C0FC4DC00BEDCA0 /* XCRemoteSwiftPackageReference "rust-components-swift" */, 2CB172802C612D68008551E2 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, 126509832CD925B30011BA36 /* XCRemoteSwiftPackageReference "braze-swift-sdk" */, + 2CAF5C1B2D01B3E200D3DCDD /* XCRemoteSwiftPackageReference "SwiftSoup" */, ); productRefGroup = F84B21BF1A090F8100AAB793 /* Products */; projectDirPath = ""; @@ -14043,6 +14622,7 @@ 2CD2635C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png in Resources */, 2CD2639A2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png in Resources */, 2CD2632F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, + 2CAF5BE02D00D1AB00D3DCDD /* import_input_bookmark_firefox.html in Resources */, 2CD2632E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, 2CD262C22CFDC5EB00A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_es.1.png in Resources */, 2CD263122CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png in Resources */, @@ -14062,6 +14642,7 @@ 2CD2638F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, 2CD263742CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png in Resources */, 2CD2633F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, + 2CAF5BE62D00D1AB00D3DCDD /* referrals.json in Resources */, 2CD2639B2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png in Resources */, 2CD263662CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */, 2CD262B42CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png in Resources */, @@ -14119,6 +14700,8 @@ 2CD263082CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, 2CD263572CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, 2CD262AE2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png in Resources */, + 2CAF5BDF2D00D1AB00D3DCDD /* import_input_bookmark_chrome.html in Resources */, + 2CAF5BE22D00D1AB00D3DCDD /* import_output_bookmark_chrome.txt in Resources */, 2CD2631F2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png in Resources */, 2CD263132CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, 2CD262E42CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_es.1.png in Resources */, @@ -14181,6 +14764,8 @@ 2CD2636B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, 2CD262DD2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, 2CD262E82CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png in Resources */, + 2CAF5BE12D00D1AB00D3DCDD /* import_input_bookmark_safari.html in Resources */, + 2CAF5BE32D00D1AB00D3DCDD /* import_output_bookmark_firefox.txt in Resources */, 2CD2634A2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png in Resources */, 2CD263832CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png in Resources */, 2CD2634D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png in Resources */, @@ -14268,11 +14853,14 @@ 2CD2630F2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png in Resources */, 2CD2638B2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, 2CD262CD2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png in Resources */, + 2CAF5BE42D00D1AB00D3DCDD /* import_output_bookmark_safari.txt in Resources */, 2CD263192CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, 2CD263532CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png in Resources */, 2CD263642CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */, + 2CAF5BE52D00D1AB00D3DCDD /* notifications.json in Resources */, 2CD263042CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */, 2CD262FE2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png in Resources */, + 2CAF5BDE2D00D1AB00D3DCDD /* export_bookmark_ecosia.html in Resources */, 2CD262B92CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png in Resources */, 2CD263322CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png in Resources */, 2CD263872CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png in Resources */, @@ -14634,29 +15222,108 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2CAF5B8C2D00D16C00D3DCDD /* TreesProjection.swift in Sources */, 2CD264FF2CFDC76A00A040A7 /* FakeNimbus.swift in Sources */, + 2CAF5B882D00D16C00D3DCDD /* URL+Extensions.swift in Sources */, + 2CAF5B902D00D16C00D3DCDD /* Favourites.swift in Sources */, + 2CAF5B822D00D16C00D3DCDD /* Date+TimestampProvider.swift in Sources */, + 2CAF5B8A2D00D16C00D3DCDD /* InvestmentsProjection.swift in Sources */, + 2CAF5B762D00D16C00D3DCDD /* Unleash.Model.swift in Sources */, + 2CAF5B852D00D16C00D3DCDD /* URLRequest+Extensions.swift in Sources */, + 2CAF5B752D00D16C00D3DCDD /* TimeBasedRefreshingRule.swift in Sources */, + 2CAF5B842D00D16C00D3DCDD /* PageStore.swift in Sources */, + 2CAF5B812D00D16C00D3DCDD /* ObjectPersister.swift in Sources */, + 2CAF5B832D00D16C00D3DCDD /* Page.swift in Sources */, + 2CAF5B792D00D16C00D3DCDD /* UnleashFeatureManagementSessionInitializer.swift in Sources */, + 2CAF5B982D00D16C00D3DCDD /* Bundle.swift in Sources */, 2CD264AD2CFDC76A00A040A7 /* MMP.swift in Sources */, + 2CAF5B7E2D00D16C00D3DCDD /* Tabs.swift in Sources */, 2CD2648A2CFDC76A00A040A7 /* BrazeService.swift in Sources */, 2CD264AC2CFDC76A00A040A7 /* FeatureManagement.swift in Sources */, + 2CAF5B9B2D00D16C00D3DCDD /* Locale+Extensions.swift in Sources */, + 2CAF5B802D00D16C00D3DCDD /* NewsModel.swift in Sources */, + 2CAF5B922D00D16C00D3DCDD /* AdultFilter.swift in Sources */, + 2CAF5B532D00D16C00D3DCDD /* HTTPClient.swift in Sources */, + 2CAF5B892D00D16C00D3DCDD /* FinancialReports.swift in Sources */, 2CD264A02CFDC76A00A040A7 /* Version+Extensions.swift in Sources */, + 2CAF5B5E2D00D16C00D3DCDD /* Publisher.swift in Sources */, + 2CAF5B702D00D16C00D3DCDD /* TimeInterval+Extensions.swift in Sources */, + 2CAF5B592D00D16C00D3DCDD /* ReferralCreateCodeRequest.swift in Sources */, + 2CAF5B862D00D16C00D3DCDD /* Encodable+Dictionary.swift in Sources */, 2CD2663E2CFF4ED000A040A7 /* DeviceInfo+Ecosia.swift in Sources */, + 2CAF5B5A2D00D16C00D3DCDD /* ReferralRefreshCodeRequest.swift in Sources */, 2CD266322CFE403800A040A7 /* APNConsentOnLaunchExperiment.swift in Sources */, + 2CAF5B562D00D16C00D3DCDD /* URLSessionProtocol.swift in Sources */, + 2CAF5B912D00D16C00D3DCDD /* List.swift in Sources */, + 2CAF5B962D00D16C00D3DCDD /* FileManager.swift in Sources */, + 2CAF5B4E2D00D16C00D3DCDD /* BookmarkSerializer.swift in Sources */, + 2CAF5B8D2D00D16C00D3DCDD /* EnvironmentFetcher.swift in Sources */, + 2CAF5B7F2D00D16C00D3DCDD /* News.swift in Sources */, + 2CAF5B6A2D00D16C00D3DCDD /* MMPProvider.swift in Sources */, + 2CAF5B6B2D00D16C00D3DCDD /* SKAdNetworkProtocol.swift in Sources */, + 2CAF5B652D00D16C00D3DCDD /* SingularSessionInfoSendRequest.swift in Sources */, + 2CAF5B6D2D00D16C00D3DCDD /* Environment.Auth.swift in Sources */, + 2CAF5B722D00D16C00D3DCDD /* AppUpdateRule.swift in Sources */, + 2CAF5B732D00D16C00D3DCDD /* DeviceRegionChangeRule.swift in Sources */, + 2CAF5B742D00D16C00D3DCDD /* RefreshingRule.swift in Sources */, 2CD264A12CFDC76A00A040A7 /* Analytics.swift in Sources */, + 2CAF5B872D00D16C00D3DCDD /* User.swift in Sources */, + 2CAF5B582D00D16C00D3DCDD /* ReferralClaimRequest.swift in Sources */, 2CD2649C2CFDC76A00A040A7 /* DefaultAppVersionInfoProvider.swift in Sources */, + 2CAF5B9A2D00D16C00D3DCDD /* CloudFlareKeyProvider.swift in Sources */, + 2CAF5B6C2D00D16C00D3DCDD /* AppDeviceInfo.swift in Sources */, + 2CAF5B6F2D00D16C00D3DCDD /* URLProvider.swift in Sources */, + 2CAF5B682D00D16C00D3DCDD /* SingularEvent.swift in Sources */, + 2CAF5B572D00D16C00D3DCDD /* Cookie.swift in Sources */, + 2CAF5B952D00D16C00D3DCDD /* SearchesCounter.swift in Sources */, + 2CAF5B4F2D00D16C00D3DCDD /* Document+Safari.swift in Sources */, + 2CAF5B542D00D16C00D3DCDD /* HTTPMethod.swift in Sources */, + 2CAF5B942D00D16C00D3DCDD /* UserDefaults+ObjectPersister.swift in Sources */, 2CD2649A2CFDC76A00A040A7 /* String.swift in Sources */, + 2CAF5B7D2D00D16C00D3DCDD /* Tab.swift in Sources */, 2CD2663C2CFE423D00A040A7 /* AppInfo+Ecosia.swift in Sources */, + 2CAF5B4D2D00D16C00D3DCDD /* BookmarkParser.swift in Sources */, 2CD266352CFE403800A040A7 /* OnboardingRemoveExperiment.swift in Sources */, + 2CAF5B712D00D16C00D3DCDD /* History.swift in Sources */, + 2CAF5B7B2D00D16C00D3DCDD /* UnleashStartRequest.swift in Sources */, + 2CAF5B662D00D16C00D3DCDD /* Singular.swift in Sources */, + 2CAF5B552D00D16C00D3DCDD /* URLSessionHTTPClient.swift in Sources */, + 2CAF5B6E2D00D16C00D3DCDD /* Environment.swift in Sources */, + 2CAF5B522D00D16C00D3DCDD /* Requestable.swift in Sources */, + 2CAF5B992D00D16C00D3DCDD /* RegionLocatable.swift in Sources */, + 2CAF5B632D00D16C00D3DCDD /* SingularReponse.swift in Sources */, + 2CAF5B5D2D00D16C00D3DCDD /* Scheme.swift in Sources */, + 2CAF5B512D00D16C00D3DCDD /* BaseRequest.swift in Sources */, + 2CAF5B772D00D16C00D3DCDD /* Unleash.swift in Sources */, + 2CAF5B622D00D16C00D3DCDD /* SingularEventRequest.swift in Sources */, + 2CAF5B7A2D00D16C00D3DCDD /* UnleashRefreshConfigurator.swift in Sources */, + 2CAF5B5F2D00D16C00D3DCDD /* TimestampProvider.swift in Sources */, 2CD265012CFDC76A00A040A7 /* FakeTelemetry.swift in Sources */, + 2CAF5B5B2D00D16C00D3DCDD /* Referrals.Model.swift in Sources */, 2CD2649B2CFDC76A00A040A7 /* AppVersionInfoProvider.swift in Sources */, 2CD266332CFE403800A040A7 /* BrazeIntegrationExperiment.swift in Sources */, 2CD2649F2CFDC76A00A040A7 /* Version.swift in Sources */, 2CD264A32CFDC76A00A040A7 /* Analytics+Configuration.swift in Sources */, + 2CAF5B8F2D00D16C00D3DCDD /* Language.swift in Sources */, 2CD2649D2CFDC76A00A040A7 /* EcosiaInstallType.swift in Sources */, + 2CAF5B5C2D00D16C00D3DCDD /* Referrals.swift in Sources */, + 2CAF5B642D00D16C00D3DCDD /* SingularService.swift in Sources */, + 2CAF5B602D00D16C00D3DCDD /* SingularConversionValueRequest.swift in Sources */, + 2CAF5B7C2D00D16C00D3DCDD /* FeatureManagementSessionInitializer.swift in Sources */, + 2CAF5B782D00D16C00D3DCDD /* Unleash+RefreshComponent.swift in Sources */, + 2CAF5B502D00D16C00D3DCDD /* String+CssQuery.swift in Sources */, + 2CAF5B612D00D16C00D3DCDD /* SingularConversionValueResponse.swift in Sources */, + 2CAF5B8E2D00D16C00D3DCDD /* Local.swift in Sources */, + 2CAF5B972D00D16C00D3DCDD /* Market.swift in Sources */, 2CD266342CFE403800A040A7 /* NewsletterCardExperiment.swift in Sources */, + 2CAF5B932D00D16C00D3DCDD /* Images.swift in Sources */, 2CD265002CFDC76A00A040A7 /* FakeSentry.swift in Sources */, 2CD2649E2CFDC76A00A040A7 /* EcosiaInstallType+Extensions.swift in Sources */, + 2CAF5B8B2D00D16C00D3DCDD /* Statistics.swift in Sources */, 2CD264A22CFDC76A00A040A7 /* Analytics.Values.swift in Sources */, 2CAF5AE32D00AAEE00D3DCDD /* Bundle+Ecosia.swift in Sources */, + 2CAF5B672D00D16C00D3DCDD /* SingularAdNetworkHelper.swift in Sources */, + 2CAF5B4C2D00D16C00D3DCDD /* Bookmark.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -14666,32 +15333,74 @@ files = ( 2CD263A92CFDC5EB00A040A7 /* LocaleRetriever.swift in Sources */, 2CD263BF2CFDC5EB00A040A7 /* AnalyticsSpyTests.swift in Sources */, + 2CAF5BF12D00D1AB00D3DCDD /* HistoryTests.swift in Sources */, + 2CAF5BF32D00D1AB00D3DCDD /* SnapshotsTests.swift in Sources */, + 2CAF5BDA2D00D1AB00D3DCDD /* MockURLSessionProtocol.swift in Sources */, + 2CAF5BE82D00D1AB00D3DCDD /* SingularServiceTests.swift in Sources */, 2CD263C02CFDC5EB00A040A7 /* AnalyticsTests.swift in Sources */, + 2CAF5BF02D00D1AB00D3DCDD /* ReferralsModelTests.swift in Sources */, + 2CAF5C022D00D1AB00D3DCDD /* PublishersTests.swift in Sources */, + 2CAF5C062D00D1AB00D3DCDD /* FavouritesTests.swift in Sources */, + 2CAF5BD92D00D1AB00D3DCDD /* MockURLSession.swift in Sources */, + 2CAF5BEB2D00D1AB00D3DCDD /* BookmarkParserTests.swift in Sources */, + 2CAF5BD52D00D1AB00D3DCDD /* User5_3.swift in Sources */, 2CD263A52CFDC5EB00A040A7 /* OnboardingTests.swift in Sources */, + 2CAF5BE92D00D1AB00D3DCDD /* UpgradeTests.swift in Sources */, + 2CAF5BDC2D00D1AB00D3DCDD /* URLTests.swift in Sources */, + 2CAF5C032D00D1AB00D3DCDD /* UnleashRefreshConfiguratorTests.swift in Sources */, 2CD263AC2CFDC5EB00A040A7 /* SnapshotBaseTests.swift in Sources */, 2CD263B32CFDC5EB00A040A7 /* AppDelegateFeatureManagementIntegrationTests.swift in Sources */, 1229358D2CE78D5D00EC1297 /* BrazeServiceTests.swift in Sources */, + 2CAF5BFE2D00D1AB00D3DCDD /* ReferralsTests.swift in Sources */, 2CD263AE2CFDC5EB00A040A7 /* String+Extension.swift in Sources */, + 2CAF5BED2D00D1AB00D3DCDD /* BookmarkSerializerTests.swift in Sources */, 2CD262AA2CFDC5EB00A040A7 /* Welcome.swift in Sources */, 2CD263B52CFDC5EB00A040A7 /* EcosiaPerformanceTestHistory.swift in Sources */, + 2CAF5C012D00D1AB00D3DCDD /* InvestmentsProjectionTests.swift in Sources */, + 2CAF5BDB2D00D1AB00D3DCDD /* ListTests.swift in Sources */, 2CD263B72CFDC5EB00A040A7 /* PrivateModeButtonTests.swift in Sources */, + 2CAF5C042D00D1AB00D3DCDD /* UserTests.swift in Sources */, + 2CAF5C002D00D1AB00D3DCDD /* CookieTests.swift in Sources */, + 2CAF5BEA2D00D1AB00D3DCDD /* UnleashFeatureManagementSessionInitializerTests.swift in Sources */, + 2CAF5BF72D00D1AB00D3DCDD /* TreesProjectionTests.swift in Sources */, 2CD263BE2CFDC5EB00A040A7 /* EcosiaPageActionMenuCellTests.swift in Sources */, 2CD263B62CFDC5EB00A040A7 /* MockAppVersionInfoProvider.swift in Sources */, 2CD263B42CFDC5EB00A040A7 /* EcosiaInstallTypeTests.swift in Sources */, + 2CAF5BF22D00D1AB00D3DCDD /* BookmarkTests.swift in Sources */, + 2CAF5BEE2D00D1AB00D3DCDD /* ImagesTests.swift in Sources */, 2CD263AF2CFDC5EB00A040A7 /* VersionTests.swift in Sources */, + 2CAF5BE72D00D1AB00D3DCDD /* SingularTests.swift in Sources */, + 2CAF5BFB2D00D1AB00D3DCDD /* URLProviderTests.swift in Sources */, + 2CAF5BEC2D00D1AB00D3DCDD /* NewsTests.swift in Sources */, 2CD263BD2CFDC5EB00A040A7 /* EcosiaOverlayModeManagerTests.swift in Sources */, + 2CAF5BD62D00D1AB00D3DCDD /* BookmarkFixtures.swift in Sources */, 2CD263BB2CFDC5EB00A040A7 /* UserDefaultsSeedProgressManagerTests.swift in Sources */, 2CD263B22CFDC5EB00A040A7 /* WhatsNewLocalDataProviderTests.swift in Sources */, + 2CAF5BFF2D00D1AB00D3DCDD /* FinancialReportsTests.swift in Sources */, 2CD263A62CFDC5EB00A040A7 /* DeviceType.swift in Sources */, 2CD263AA2CFDC5EB00A040A7 /* LocalizationOverrideTestingBundle.swift in Sources */, + 2CAF5BFA2D00D1AB00D3DCDD /* StagingURLProviderTests.swift in Sources */, + 2CAF5BEF2D00D1AB00D3DCDD /* StatisticsTests.swift in Sources */, + 2CAF5BF62D00D1AB00D3DCDD /* TabsTests.swift in Sources */, + 2CAF5BF82D00D1AB00D3DCDD /* UnleashTests.swift in Sources */, + 2CAF5BDD2D00D1AB00D3DCDD /* FeatureFlaggingSessionInitializerTests.swift in Sources */, + 2CAF5BF52D00D1AB00D3DCDD /* SingularAdNetworkHelperTests.swift in Sources */, 2CD263B82CFDC5EB00A040A7 /* EcosiaNTPTooltipHighlightTests.swift in Sources */, 2CD262DB2CFDC5EB00A040A7 /* NTPComponentTests.swift in Sources */, + 2CAF5BF42D00D1AB00D3DCDD /* LocalTests.swift in Sources */, + 2CAF5BD72D00D1AB00D3DCDD /* HTTPClientMock.swift in Sources */, + 2CAF5BFD2D00D1AB00D3DCDD /* SearchesCounterTests.swift in Sources */, 2CD262DC2CFDC5EB00A040A7 /* NTPTests.swift in Sources */, 2CD263B92CFDC5EB00A040A7 /* EcosiaHomeViewModelTests.swift in Sources */, 2CD263BC2CFDC5EB00A040A7 /* EcosiaTopSitesHelperTests.swift in Sources */, + 2CAF5C052D00D1AB00D3DCDD /* LanguageTests.swift in Sources */, 2CD263BA2CFDC5EB00A040A7 /* UnleashUserDefaultsSeedProgressManagerTests.swift in Sources */, 2CD263AD2CFDC5EB00A040A7 /* SnapshotTestHelper.swift in Sources */, 2CD262A92CFDC5EB00A040A7 /* EcosiaMockThemeManager.swift in Sources */, + 2CAF5BF92D00D1AB00D3DCDD /* ProductionURLProviderTests.swift in Sources */, + 2CAF5BD82D00D1AB00D3DCDD /* MockTimestampProvider.swift in Sources */, + 2CAF5BFC2D00D1AB00D3DCDD /* UserStateTests.swift in Sources */, + 2CAF5C072D00D1AB00D3DCDD /* URLRequestTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -16136,6 +16845,11 @@ target = F84B21BD1A090F8100AAB793 /* Client */; targetProxy = 2C6C90862C614A17007D9B43 /* PBXContainerItemProxy */; }; + 2CAF5C192D01B2E200D3DCDD /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 122935692CE78D0A00EC1297 /* Ecosia */; + targetProxy = 2CAF5C182D01B2E200D3DCDD /* PBXContainerItemProxy */; + }; 2F11EE501ABCAE910083902D /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 288A2D851AB8B3260023ABC3 /* Shared */; @@ -23761,14 +24475,6 @@ version = 2.0.0; }; }; - 2C61887D2B7A89E4006B70D7 /* XCRemoteSwiftPackageReference "ios-core" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ecosia/ios-core.git"; - requirement = { - branch = main; - kind = branch; - }; - }; 2C6189EF2B7B7D48006B70D7 /* XCRemoteSwiftPackageReference "snowplow-ios-tracker" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/snowplow/snowplow-ios-tracker.git"; @@ -23777,6 +24483,14 @@ minimumVersion = 6.0.8; }; }; + 2CAF5C1B2D01B3E200D3DCDD /* XCRemoteSwiftPackageReference "SwiftSoup" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/scinfu/SwiftSoup"; + requirement = { + kind = exactVersion; + version = 2.5.3; + }; + }; 2CB172802C612D68008551E2 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/pointfreeco/swift-snapshot-testing"; @@ -23860,11 +24574,6 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 1229358E2CE78EC400EC1297 /* Core */ = { - isa = XCSwiftPackageProductDependency; - package = 2C61887D2B7A89E4006B70D7 /* XCRemoteSwiftPackageReference "ios-core" */; - productName = Core; - }; 122935902CE78ED500EC1297 /* BrazeKit */ = { isa = XCSwiftPackageProductDependency; package = 126509832CD925B30011BA36 /* XCRemoteSwiftPackageReference "braze-swift-sdk" */; @@ -23899,16 +24608,6 @@ isa = XCSwiftPackageProductDependency; productName = Redux; }; - 2C1298AB2BF5EE3E005AE4E4 /* Core */ = { - isa = XCSwiftPackageProductDependency; - package = 2C61887D2B7A89E4006B70D7 /* XCRemoteSwiftPackageReference "ios-core" */; - productName = Core; - }; - 2C1F23BC2B9F405E00186F55 /* Core */ = { - isa = XCSwiftPackageProductDependency; - package = 2C61887D2B7A89E4006B70D7 /* XCRemoteSwiftPackageReference "ios-core" */; - productName = Core; - }; 2C6189F02B7B7D5D006B70D7 /* SnowplowTracker */ = { isa = XCSwiftPackageProductDependency; package = 2C6189EF2B7B7D48006B70D7 /* XCRemoteSwiftPackageReference "snowplow-ios-tracker" */; @@ -23918,11 +24617,6 @@ isa = XCSwiftPackageProductDependency; productName = Common; }; - 2C69DA802C62459200D7F69F /* Core */ = { - isa = XCSwiftPackageProductDependency; - package = 2C61887D2B7A89E4006B70D7 /* XCRemoteSwiftPackageReference "ios-core" */; - productName = Core; - }; 2C6C908E2C614A6C007D9B43 /* SnapshotTesting */ = { isa = XCSwiftPackageProductDependency; package = 2CB172802C612D68008551E2 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */; @@ -23933,25 +24627,19 @@ package = 2CCFB3D82C0FC4DC00BEDCA0 /* XCRemoteSwiftPackageReference "rust-components-swift" */; productName = MozillaAppServices; }; - 2CE294462B7CDD56006C22B2 /* Core */ = { + 2CAF5C1C2D01B40B00D3DCDD /* SwiftSoup */ = { isa = XCSwiftPackageProductDependency; - package = 2C61887D2B7A89E4006B70D7 /* XCRemoteSwiftPackageReference "ios-core" */; - productName = Core; + package = 2CAF5C1B2D01B3E200D3DCDD /* XCRemoteSwiftPackageReference "SwiftSoup" */; + productName = SwiftSoup; }; - 2CE294482B7CDD78006C22B2 /* Core */ = { + 2CAF5C1E2D01B44400D3DCDD /* Sentry */ = { isa = XCSwiftPackageProductDependency; - package = 2C61887D2B7A89E4006B70D7 /* XCRemoteSwiftPackageReference "ios-core" */; - productName = Core; - }; - 2CE2E24C2B9B1FCB00973C16 /* Core */ = { - isa = XCSwiftPackageProductDependency; - package = 2C61887D2B7A89E4006B70D7 /* XCRemoteSwiftPackageReference "ios-core" */; - productName = Core; + package = 5A37861729A2C337006B3A34 /* XCRemoteSwiftPackageReference "sentry-cocoa" */; + productName = Sentry; }; - 2CF4DA622BB31970001C340A /* Core */ = { + 2CAF5C202D01B5F300D3DCDD /* Common */ = { isa = XCSwiftPackageProductDependency; - package = 2C61887D2B7A89E4006B70D7 /* XCRemoteSwiftPackageReference "ios-core" */; - productName = Core; + productName = Common; }; 432BD0232790EBD000A0F3C3 /* Adjust */ = { isa = XCSwiftPackageProductDependency; diff --git a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e3a327699c4d..61205b01dacf 100644 --- a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -63,15 +63,6 @@ "version" : "56.0.0" } }, - { - "identity" : "ios-core", - "kind" : "remoteSourceControl", - "location" : "https://github.com/ecosia/ios-core.git", - "state" : { - "branch" : "main", - "revision" : "55fd76f4646b925b39168a1158396f36c6fd6f6f" - } - }, { "identity" : "ios_sdk", "kind" : "remoteSourceControl", @@ -176,8 +167,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/scinfu/SwiftSoup", "state" : { - "branch" : "2.5.3", - "revision" : "f707b8680cddb96dc1855632340a572ef37bbb98" + "revision" : "f707b8680cddb96dc1855632340a572ef37bbb98", + "version" : "2.5.3" } }, { diff --git a/Client/Application/AppDelegate.swift b/Client/Application/AppDelegate.swift index 986fea36f2ce..b9258945faf0 100644 --- a/Client/Application/AppDelegate.swift +++ b/Client/Application/AppDelegate.swift @@ -9,8 +9,6 @@ import UIKit import Common // Ecosia: remove Glean dependency // import Glean import TabDataStore -// Ecosia: Import Core -import Core // Ecosia: Import Ecosia Framework import Ecosia diff --git a/Client/Coordinators/Browser/BrowserCoordinator.swift b/Client/Coordinators/Browser/BrowserCoordinator.swift index 5ac413853e5f..a028221125cb 100644 --- a/Client/Coordinators/Browser/BrowserCoordinator.swift +++ b/Client/Coordinators/Browser/BrowserCoordinator.swift @@ -9,10 +9,8 @@ import Shared import Storage import Redux import TabDataStore -// Ecosia: Import Core -import Core +// Ecosia: Import Ecosia Framework import Ecosia - class BrowserCoordinator: BaseCoordinator, LaunchCoordinatorDelegate, BrowserDelegate, diff --git a/Client/Coordinators/Scene/SceneCoordinator.swift b/Client/Coordinators/Scene/SceneCoordinator.swift index 3b6f2f979d94..c7424b526d2b 100644 --- a/Client/Coordinators/Scene/SceneCoordinator.swift +++ b/Client/Coordinators/Scene/SceneCoordinator.swift @@ -6,8 +6,8 @@ import Common import UIKit import Shared import Storage -// Ecosia: Import Core -import Core +// Ecosia: Import Ecosia Framework +import Ecosia /// Each scene has it's own scene coordinator, which is the root coordinator for a scene. class SceneCoordinator: BaseCoordinator, LaunchCoordinatorDelegate, LaunchFinishedLoadingDelegate { diff --git a/Client/Ecosia/Bookmarks/BookmarksExchange.swift b/Client/Ecosia/Bookmarks/BookmarksExchange.swift index 7e5d71377f5f..b1bc4ba75f04 100644 --- a/Client/Ecosia/Bookmarks/BookmarksExchange.swift +++ b/Client/Ecosia/Bookmarks/BookmarksExchange.swift @@ -3,13 +3,12 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core import Shared import Storage import Ecosia protocol BookmarksExchangable { - func export(bookmarks: [Core.BookmarkItem], in viewController: UIViewController, barButtonItem: UIBarButtonItem) async throws + func export(bookmarks: [Ecosia.BookmarkItem], in viewController: UIViewController, barButtonItem: UIBarButtonItem) async throws func `import`(from fileURL: URL, in viewController: UIViewController) async throws } @@ -32,7 +31,7 @@ final class BookmarksExchange: BookmarksExchangable { } @MainActor - func export(bookmarks: [Core.BookmarkItem], in viewController: UIViewController, barButtonItem: UIBarButtonItem) async throws { + func export(bookmarks: [Ecosia.BookmarkItem], in viewController: UIViewController, barButtonItem: UIBarButtonItem) async throws { guard let view = viewController.view else { return } let activityIndicator = UIActivityIndicatorView(style: .medium) @@ -100,7 +99,7 @@ final class BookmarksExchange: BookmarksExchangable { } private func importBookmarks( - _ bookmarks: [Core.BookmarkItem], + _ bookmarks: [Ecosia.BookmarkItem], viewController: UIViewController, toast: SimpleToast ) async throws { @@ -146,7 +145,7 @@ final class BookmarksExchange: BookmarksExchangable { } } - private func processBookmarks(_ bookmarks: [Core.BookmarkItem], parentGUID: GUID) async throws { + private func processBookmarks(_ bookmarks: [Ecosia.BookmarkItem], parentGUID: GUID) async throws { for bookmark in bookmarks { switch bookmark { case let .folder(title, children, _): diff --git a/Client/Ecosia/Experiments/Unleash/SeedCounterNTPExperiment.swift b/Client/Ecosia/Experiments/Unleash/SeedCounterNTPExperiment.swift index e1d429d8b8c7..d729804d1a76 100644 --- a/Client/Ecosia/Experiments/Unleash/SeedCounterNTPExperiment.swift +++ b/Client/Ecosia/Experiments/Unleash/SeedCounterNTPExperiment.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core import Ecosia struct SeedCounterNTPExperiment { diff --git a/Client/Ecosia/Extensions/BrowserCoordinator+Ecosia.swift b/Client/Ecosia/Extensions/BrowserCoordinator+Ecosia.swift index 467108a2bde9..d86d4279128b 100644 --- a/Client/Ecosia/Extensions/BrowserCoordinator+Ecosia.swift +++ b/Client/Ecosia/Extensions/BrowserCoordinator+Ecosia.swift @@ -4,6 +4,5 @@ import Foundation import Shared -import Core extension BrowserCoordinator { } diff --git a/Client/Ecosia/Extensions/BrowserViewController+Ecosia.swift b/Client/Ecosia/Extensions/BrowserViewController+Ecosia.swift index 48186962cab2..a0ebe4447920 100644 --- a/Client/Ecosia/Extensions/BrowserViewController+Ecosia.swift +++ b/Client/Ecosia/Extensions/BrowserViewController+Ecosia.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core + import Shared import Ecosia diff --git a/Client/Ecosia/Extensions/HomepageViewController+Ecosia.swift b/Client/Ecosia/Extensions/HomepageViewController+Ecosia.swift index 6eeb66f15bab..04353f6d16a0 100644 --- a/Client/Ecosia/Extensions/HomepageViewController+Ecosia.swift +++ b/Client/Ecosia/Extensions/HomepageViewController+Ecosia.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core + import Ecosia protocol HomepageViewControllerDelegate: AnyObject { diff --git a/Client/Ecosia/Settings/EcosiaDebugSettings.swift b/Client/Ecosia/Settings/EcosiaDebugSettings.swift index 8601c3be551d..acddd74c46cc 100644 --- a/Client/Ecosia/Settings/EcosiaDebugSettings.swift +++ b/Client/Ecosia/Settings/EcosiaDebugSettings.swift @@ -4,7 +4,7 @@ import Foundation import UIKit -import Core + import Shared import Common import Ecosia diff --git a/Client/Ecosia/Settings/EcosiaSettings.swift b/Client/Ecosia/Settings/EcosiaSettings.swift index b6d53ca087c0..d5b66f735776 100644 --- a/Client/Ecosia/Settings/EcosiaSettings.swift +++ b/Client/Ecosia/Settings/EcosiaSettings.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core + import Shared import Common import Ecosia diff --git a/Client/Ecosia/UI/FilterController.swift b/Client/Ecosia/UI/FilterController.swift index 5b253d17965a..d109e00c1c38 100644 --- a/Client/Ecosia/UI/FilterController.swift +++ b/Client/Ecosia/UI/FilterController.swift @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/ -import Core +import Ecosia import UIKit import Common diff --git a/Client/Ecosia/UI/LoadingScreen.swift b/Client/Ecosia/UI/LoadingScreen.swift index a87a04bd1329..210e362630c7 100644 --- a/Client/Ecosia/UI/LoadingScreen.swift +++ b/Client/Ecosia/UI/LoadingScreen.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core + import Ecosia final class LoadingScreen: UIViewController { diff --git a/Client/Ecosia/UI/MarketsController.swift b/Client/Ecosia/UI/MarketsController.swift index 9962a25f3ef7..8d5aa617586c 100644 --- a/Client/Ecosia/UI/MarketsController.swift +++ b/Client/Ecosia/UI/MarketsController.swift @@ -2,7 +2,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/ -import Core import UIKit import Common import Ecosia diff --git a/Client/Ecosia/UI/MultiplyImpact/MultiplyImpact.swift b/Client/Ecosia/UI/MultiplyImpact/MultiplyImpact.swift index a5e5c7d55b58..a951d24ef0f6 100644 --- a/Client/Ecosia/UI/MultiplyImpact/MultiplyImpact.swift +++ b/Client/Ecosia/UI/MultiplyImpact/MultiplyImpact.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core + import UniformTypeIdentifiers import MobileCoreServices import LinkPresentation diff --git a/Client/Ecosia/UI/NTP/AboutEcosia/AboutEcosiaSection.swift b/Client/Ecosia/UI/NTP/AboutEcosia/AboutEcosiaSection.swift index e78abdf1e492..db6df8d844ca 100644 --- a/Client/Ecosia/UI/NTP/AboutEcosia/AboutEcosiaSection.swift +++ b/Client/Ecosia/UI/NTP/AboutEcosia/AboutEcosiaSection.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core import Ecosia enum AboutEcosiaSection: Int, CaseIterable { diff --git a/Client/Ecosia/UI/NTP/AboutEcosia/NTPAboutEcosiaCellViewModel.swift b/Client/Ecosia/UI/NTP/AboutEcosia/NTPAboutEcosiaCellViewModel.swift index b2a93ce4ba46..abe87f3e319d 100644 --- a/Client/Ecosia/UI/NTP/AboutEcosia/NTPAboutEcosiaCellViewModel.swift +++ b/Client/Ecosia/UI/NTP/AboutEcosia/NTPAboutEcosiaCellViewModel.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core +import Ecosia import Common typealias NTPAboutEcosiaCellDelegate = SharedHomepageCellDelegate & SharedHomepageCellLayoutDelegate diff --git a/Client/Ecosia/UI/NTP/ClimateImpactCounter/NTPSeedCounterCell.swift b/Client/Ecosia/UI/NTP/ClimateImpactCounter/NTPSeedCounterCell.swift index e58f7ddf89a2..448d9413f421 100644 --- a/Client/Ecosia/UI/NTP/ClimateImpactCounter/NTPSeedCounterCell.swift +++ b/Client/Ecosia/UI/NTP/ClimateImpactCounter/NTPSeedCounterCell.swift @@ -4,7 +4,7 @@ import UIKit import SwiftUI -import Core + import Common protocol NTPSeedCounterDelegate: NSObjectProtocol { diff --git a/Client/Ecosia/UI/NTP/ClimateImpactCounter/SeedCounterHiddenSettings.swift b/Client/Ecosia/UI/NTP/ClimateImpactCounter/SeedCounterHiddenSettings.swift index f3a27d356c6f..1c19c3287282 100644 --- a/Client/Ecosia/UI/NTP/ClimateImpactCounter/SeedCounterHiddenSettings.swift +++ b/Client/Ecosia/UI/NTP/ClimateImpactCounter/SeedCounterHiddenSettings.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core +import Ecosia final class AddOneSeedSetting: HiddenSetting { diff --git a/Client/Ecosia/UI/NTP/Customization/CustomizableNTPSettingConfig.swift b/Client/Ecosia/UI/NTP/Customization/CustomizableNTPSettingConfig.swift index b6bffd706e80..33b7bb63fcbb 100644 --- a/Client/Ecosia/UI/NTP/Customization/CustomizableNTPSettingConfig.swift +++ b/Client/Ecosia/UI/NTP/Customization/CustomizableNTPSettingConfig.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core import Ecosia enum CustomizableNTPSettingConfig: CaseIterable { diff --git a/Client/Ecosia/UI/NTP/Impact/ClimateImpactInfo.swift b/Client/Ecosia/UI/NTP/Impact/ClimateImpactInfo.swift index cd586349cb7e..84ac8c5c6051 100644 --- a/Client/Ecosia/UI/NTP/Impact/ClimateImpactInfo.swift +++ b/Client/Ecosia/UI/NTP/Impact/ClimateImpactInfo.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core enum ClimateImpactInfo: Equatable { case referral(value: Int) diff --git a/Client/Ecosia/UI/NTP/Impact/NTPImpactCell.swift b/Client/Ecosia/UI/NTP/Impact/NTPImpactCell.swift index 98f1ecd8bd3f..30bc9f640919 100644 --- a/Client/Ecosia/UI/NTP/Impact/NTPImpactCell.swift +++ b/Client/Ecosia/UI/NTP/Impact/NTPImpactCell.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core + import Common final class NTPImpactCell: UICollectionViewCell, Themeable, ReusableCell { diff --git a/Client/Ecosia/UI/NTP/Impact/NTPImpactCellViewModel.swift b/Client/Ecosia/UI/NTP/Impact/NTPImpactCellViewModel.swift index 0e2a8ac15954..d23189f61977 100644 --- a/Client/Ecosia/UI/NTP/Impact/NTPImpactCellViewModel.swift +++ b/Client/Ecosia/UI/NTP/Impact/NTPImpactCellViewModel.swift @@ -4,7 +4,7 @@ import Foundation import Shared -import Core +import Ecosia import Common protocol NTPImpactCellDelegate: AnyObject { diff --git a/Client/Ecosia/UI/NTP/Library/NTPLibaryCellViewModel.swift b/Client/Ecosia/UI/NTP/Library/NTPLibaryCellViewModel.swift index 1371db0bd3bc..f6aa620c36bf 100644 --- a/Client/Ecosia/UI/NTP/Library/NTPLibaryCellViewModel.swift +++ b/Client/Ecosia/UI/NTP/Library/NTPLibaryCellViewModel.swift @@ -4,7 +4,7 @@ import Foundation import Shared -import Core + import Common protocol NTPLibraryDelegate: AnyObject { diff --git a/Client/Ecosia/UI/NTP/Logo/NTPLogoCell.swift b/Client/Ecosia/UI/NTP/Logo/NTPLogoCell.swift index e3116eb2d0c0..215d89ae6ca7 100644 --- a/Client/Ecosia/UI/NTP/Logo/NTPLogoCell.swift +++ b/Client/Ecosia/UI/NTP/Logo/NTPLogoCell.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core + import Common final class NTPLogoCell: UICollectionViewCell, ReusableCell, Themeable { diff --git a/Client/Ecosia/UI/NTP/NTPLayout.swift b/Client/Ecosia/UI/NTP/NTPLayout.swift index b094969c9a73..81fd8dcb2335 100644 --- a/Client/Ecosia/UI/NTP/NTPLayout.swift +++ b/Client/Ecosia/UI/NTP/NTPLayout.swift @@ -3,8 +3,8 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core import Shared +import Ecosia protocol NTPLayoutHighlightDataSource: AnyObject { func getSectionViewModel(shownSection: Int) -> HomepageViewModelProtocol? diff --git a/Client/Ecosia/UI/NTP/NTPTooltip.Highlight.swift b/Client/Ecosia/UI/NTP/NTPTooltip.Highlight.swift index 7ba0313b2e0c..0e7a2bf6114e 100644 --- a/Client/Ecosia/UI/NTP/NTPTooltip.Highlight.swift +++ b/Client/Ecosia/UI/NTP/NTPTooltip.Highlight.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core +import Ecosia extension NTPTooltip { enum Highlight { @@ -33,7 +33,7 @@ extension NTPTooltip { } } - class func highlight(for user: Core.User = User.shared) -> NTPTooltip.Highlight? { + class func highlight(for user: User = User.shared) -> NTPTooltip.Highlight? { guard !user.firstTime else { return nil } if user.referrals.isNewClaim { diff --git a/Client/Ecosia/UI/NTP/News/NTPNewsCell.swift b/Client/Ecosia/UI/NTP/News/NTPNewsCell.swift index 165fa90b8cf8..c0f204ee55cc 100644 --- a/Client/Ecosia/UI/NTP/News/NTPNewsCell.swift +++ b/Client/Ecosia/UI/NTP/News/NTPNewsCell.swift @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/ -import Core +import Ecosia import UIKit import Common diff --git a/Client/Ecosia/UI/NTP/News/NTPNewsCellViewModel.swift b/Client/Ecosia/UI/NTP/News/NTPNewsCellViewModel.swift index 3a8b44e0f309..b97c1eb570c9 100644 --- a/Client/Ecosia/UI/NTP/News/NTPNewsCellViewModel.swift +++ b/Client/Ecosia/UI/NTP/News/NTPNewsCellViewModel.swift @@ -4,7 +4,7 @@ import Foundation import Shared -import Core + import Common import Ecosia diff --git a/Client/Ecosia/UI/NTP/News/NewsController.swift b/Client/Ecosia/UI/NTP/News/NewsController.swift index ae1b6e5f5203..783b0b02cf84 100644 --- a/Client/Ecosia/UI/NTP/News/NewsController.swift +++ b/Client/Ecosia/UI/NTP/News/NewsController.swift @@ -2,7 +2,6 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/ -import Core import UIKit import Common import Ecosia diff --git a/Client/Ecosia/UI/NTP/NudgeCards/NTPConfigurableNudgeCardCell.swift b/Client/Ecosia/UI/NTP/NudgeCards/NTPConfigurableNudgeCardCell.swift index 55c3bf0242d2..4b99ddcf5e65 100644 --- a/Client/Ecosia/UI/NTP/NudgeCards/NTPConfigurableNudgeCardCell.swift +++ b/Client/Ecosia/UI/NTP/NudgeCards/NTPConfigurableNudgeCardCell.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core + import Common /// Reusable Nudge Card Cell that can be configured with any view model. diff --git a/Client/Ecosia/UI/Onboarding/Welcome.swift b/Client/Ecosia/UI/Onboarding/Welcome.swift index a0f1fade39a8..936cbba2f48c 100644 --- a/Client/Ecosia/UI/Onboarding/Welcome.swift +++ b/Client/Ecosia/UI/Onboarding/Welcome.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core + import Common import Ecosia diff --git a/Client/Ecosia/UI/Onboarding/WelcomeTour.Step.swift b/Client/Ecosia/UI/Onboarding/WelcomeTour.Step.swift index a54452291be4..7026c199d2b2 100644 --- a/Client/Ecosia/UI/Onboarding/WelcomeTour.Step.swift +++ b/Client/Ecosia/UI/Onboarding/WelcomeTour.Step.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core + import Ecosia extension WelcomeTour { diff --git a/Client/Ecosia/UI/Onboarding/WelcomeTour.swift b/Client/Ecosia/UI/Onboarding/WelcomeTour.swift index 16309ce5cbb2..6a574fe97112 100644 --- a/Client/Ecosia/UI/Onboarding/WelcomeTour.swift +++ b/Client/Ecosia/UI/Onboarding/WelcomeTour.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core + import Common import Ecosia diff --git a/Client/Ecosia/UI/Onboarding/WelcomeTourAction.swift b/Client/Ecosia/UI/Onboarding/WelcomeTourAction.swift index 218a7fb5bb0d..ca2ca96d3183 100644 --- a/Client/Ecosia/UI/Onboarding/WelcomeTourAction.swift +++ b/Client/Ecosia/UI/Onboarding/WelcomeTourAction.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core +import Ecosia import Common final class WelcomeTourAction: UIView, Themeable { diff --git a/Client/Ecosia/UI/Onboarding/WelcomeTourTransparent.swift b/Client/Ecosia/UI/Onboarding/WelcomeTourTransparent.swift index 7f4c6126be8f..70ae96504aa6 100644 --- a/Client/Ecosia/UI/Onboarding/WelcomeTourTransparent.swift +++ b/Client/Ecosia/UI/Onboarding/WelcomeTourTransparent.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core +import Ecosia import Common final class WelcomeTourTransparent: UIView, Themeable { diff --git a/Client/Ecosia/UI/WhatsNew/DataProvider/WhatsNewLocalDataProvider.swift b/Client/Ecosia/UI/WhatsNew/DataProvider/WhatsNewLocalDataProvider.swift index 481fbd1aef68..112e2924e4a6 100644 --- a/Client/Ecosia/UI/WhatsNew/DataProvider/WhatsNewLocalDataProvider.swift +++ b/Client/Ecosia/UI/WhatsNew/DataProvider/WhatsNewLocalDataProvider.swift @@ -4,7 +4,7 @@ import Foundation import Shared -import Core + import Common import Ecosia diff --git a/Client/Ecosia/UI/WhatsNew/WhatsNewCell.swift b/Client/Ecosia/UI/WhatsNew/WhatsNewCell.swift index 7db7adf5ca49..3e03d5e1ffb8 100644 --- a/Client/Ecosia/UI/WhatsNew/WhatsNewCell.swift +++ b/Client/Ecosia/UI/WhatsNew/WhatsNewCell.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core + import Common final class WhatsNewCell: UITableViewCell, Themeable { diff --git a/Client/Ecosia/UI/WhatsNew/WhatsNewViewController.swift b/Client/Ecosia/UI/WhatsNew/WhatsNewViewController.swift index 0c4190834f8f..1a1c287d1dff 100644 --- a/Client/Ecosia/UI/WhatsNew/WhatsNewViewController.swift +++ b/Client/Ecosia/UI/WhatsNew/WhatsNewViewController.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import UIKit -import Core +import Ecosia import Common protocol WhatsNewViewDelegate: AnyObject { diff --git a/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift b/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift index a697584d3820..d83d54b4d645 100644 --- a/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift +++ b/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift @@ -15,8 +15,8 @@ import Telemetry import Common import ComponentLibrary import Redux -// Ecosia: Import Core -import Core +// Ecosia: Import Ecosia Framework +import Ecosia class BrowserViewController: UIViewController, SearchBarLocationProvider, diff --git a/Client/Frontend/Browser/MainMenuActionHelper.swift b/Client/Frontend/Browser/MainMenuActionHelper.swift index 0fe3950c8523..e27c1df936b2 100644 --- a/Client/Frontend/Browser/MainMenuActionHelper.swift +++ b/Client/Frontend/Browser/MainMenuActionHelper.swift @@ -10,7 +10,7 @@ import Storage import UIKit import SwiftUI import Common -import Core + // Ecosia: Need SafariServices to enable "open in safari" action import SafariServices import Ecosia diff --git a/Client/Frontend/Browser/MetadataParserHelper.swift b/Client/Frontend/Browser/MetadataParserHelper.swift index f5d08b96768f..ad060ad2aa3e 100644 --- a/Client/Frontend/Browser/MetadataParserHelper.swift +++ b/Client/Frontend/Browser/MetadataParserHelper.swift @@ -7,7 +7,6 @@ import Shared import Storage import WebKit // Ecosia: -import Core class MetadataParserHelper: TabEventHandler { init() { diff --git a/Client/Frontend/Home/HomepageViewController.swift b/Client/Frontend/Home/HomepageViewController.swift index 4dd8af2d7645..fde6c78aea34 100644 --- a/Client/Frontend/Home/HomepageViewController.swift +++ b/Client/Frontend/Home/HomepageViewController.swift @@ -9,8 +9,8 @@ import Shared import Storage import Redux import UIKit -// Ecosia: Import Core -import Core +// Ecosia: Import Ecosia Framework +import Ecosia class HomepageViewController: UIViewController, diff --git a/Client/Frontend/Home/HomepageViewModel.swift b/Client/Frontend/Home/HomepageViewModel.swift index 8982fce938fe..873d3875d79f 100644 --- a/Client/Frontend/Home/HomepageViewModel.swift +++ b/Client/Frontend/Home/HomepageViewModel.swift @@ -5,7 +5,7 @@ import Common import MozillaAppServices import Shared -import Core + import Ecosia protocol HomepageViewModelDelegate: AnyObject { diff --git a/Client/Frontend/Home/TopSites/TopSitesViewModel.swift b/Client/Frontend/Home/TopSites/TopSitesViewModel.swift index 14820a21df86..7c4eb2e38d17 100644 --- a/Client/Frontend/Home/TopSites/TopSitesViewModel.swift +++ b/Client/Frontend/Home/TopSites/TopSitesViewModel.swift @@ -6,8 +6,7 @@ import Common import Foundation import Shared import Storage -// Ecosia: importing Core -import Core +// Ecosia: Import Ecosia Framework import Ecosia class TopSitesViewModel { diff --git a/Client/Frontend/Library/Bookmarks/BookmarksPanel.swift b/Client/Frontend/Library/Bookmarks/BookmarksPanel.swift index a4d98b052c54..f0287ef39d82 100644 --- a/Client/Frontend/Library/Bookmarks/BookmarksPanel.swift +++ b/Client/Frontend/Library/Bookmarks/BookmarksPanel.swift @@ -7,7 +7,7 @@ import UIKit import Storage import Shared import SiteImageView -import Core +// Ecosia: Import Ecosia Framework import Ecosia let LocalizedRootBookmarkFolderStrings = [ diff --git a/Client/Frontend/Library/Bookmarks/BookmarksPanelViewModel.swift b/Client/Frontend/Library/Bookmarks/BookmarksPanelViewModel.swift index 8dbdb8ce3b33..ef5dd50d9c35 100644 --- a/Client/Frontend/Library/Bookmarks/BookmarksPanelViewModel.swift +++ b/Client/Frontend/Library/Bookmarks/BookmarksPanelViewModel.swift @@ -6,7 +6,8 @@ import Foundation import Common import Storage import Shared -import Core +// Ecosia: Import Ecosia Framework +import Ecosia class BookmarksPanelViewModel: NSObject { enum BookmarksSection: Int, CaseIterable { @@ -205,7 +206,7 @@ extension BookmarksPanelViewModel { } // MARK: - Private - private func getBookmarksForExport() async throws -> [Core.BookmarkItem] { + private func getBookmarksForExport() async throws -> [Ecosia.BookmarkItem] { return try await withCheckedThrowingContinuation { [weak self] continuation in guard let self = self else { return continuation.resume(returning: []) @@ -222,7 +223,7 @@ extension BookmarksPanelViewModel { self.bookmarkFolder = mobileFolder let bookmarkNodes = mobileFolder.fxChildren ?? [] - let items: [Core.BookmarkItem] = bookmarkNodes + let items: [Ecosia.BookmarkItem] = bookmarkNodes .compactMap { $0 as? BookmarkNodeData } .compactMap { bookmarkNode in self.exportNode(bookmarkNode) @@ -233,7 +234,7 @@ extension BookmarksPanelViewModel { } } - private func exportNode(_ node: BookmarkNodeData) -> Core.BookmarkItem? { + private func exportNode(_ node: BookmarkNodeData) -> Ecosia.BookmarkItem? { if let folder = node as? BookmarkFolderData { return .folder(folder.title, folder.children?.compactMap { exportNode($0) } ?? [], .empty) } else if let bookmark = node as? BookmarkItemData { diff --git a/Client/Frontend/Settings/HomepageSettings/HomePageSettingViewController.swift b/Client/Frontend/Settings/HomepageSettings/HomePageSettingViewController.swift index e5cafe240159..b0b1f1f92764 100644 --- a/Client/Frontend/Settings/HomepageSettings/HomePageSettingViewController.swift +++ b/Client/Frontend/Settings/HomepageSettings/HomePageSettingViewController.swift @@ -5,8 +5,8 @@ import Foundation import Shared import Common -// Ecosia: import Core -import Core +// Ecosia: Import Ecosia Framework +import Ecosia class HomePageSettingViewController: SettingsTableViewController, FeatureFlaggable { // MARK: - Variables diff --git a/Client/Frontend/TabContentsScripts/UserScriptManager.swift b/Client/Frontend/TabContentsScripts/UserScriptManager.swift index 1684c7ff18f3..b90b5fcd594a 100644 --- a/Client/Frontend/TabContentsScripts/UserScriptManager.swift +++ b/Client/Frontend/TabContentsScripts/UserScriptManager.swift @@ -3,8 +3,8 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import WebKit -// Ecosia -import Core +// Ecosia: Import Ecosia Framework +import Ecosia class UserScriptManager: FeatureFlaggable { // Scripts can use this to verify the *app* (not JS on the web) is calling into them. diff --git a/Client/IntroScreenManager.swift b/Client/IntroScreenManager.swift index 7588290fbdea..3ff4453e050f 100644 --- a/Client/IntroScreenManager.swift +++ b/Client/IntroScreenManager.swift @@ -4,8 +4,8 @@ import Foundation import Shared -// Ecosia: Import Core -import Core +// Ecosia: Import Ecosia Framework +import Ecosia struct IntroScreenManager { var prefs: Prefs diff --git a/Client/TabManagement/Legacy/LegacyTabManager.swift b/Client/TabManagement/Legacy/LegacyTabManager.swift index 7bc87d1ab4d9..400a66834628 100644 --- a/Client/TabManagement/Legacy/LegacyTabManager.swift +++ b/Client/TabManagement/Legacy/LegacyTabManager.swift @@ -7,8 +7,8 @@ import Foundation import WebKit import Storage import Shared -// Ecosia -import Core +// Ecosia: Import Ecosia Framework +import Ecosia import Combine // MARK: - TabManagerDelegate diff --git a/Ecosia/Analytics/Analytics+Configuration.swift b/Ecosia/Analytics/Analytics+Configuration.swift index dccd31fc1f76..0954aae55621 100644 --- a/Ecosia/Analytics/Analytics+Configuration.swift +++ b/Ecosia/Analytics/Analytics+Configuration.swift @@ -4,7 +4,6 @@ import Foundation import SnowplowTracker -import Core extension Analytics { diff --git a/Ecosia/Analytics/Analytics.swift b/Ecosia/Analytics/Analytics.swift index e0755e81c666..c0509f64ab70 100644 --- a/Ecosia/Analytics/Analytics.swift +++ b/Ecosia/Analytics/Analytics.swift @@ -4,7 +4,6 @@ import Foundation import SnowplowTracker -import Core open class Analytics { static let installSchema = "iglu:org.ecosia/ios_install_event/jsonschema/1-0-0" diff --git a/Ecosia/Core/AdultFilter.swift b/Ecosia/Core/AdultFilter.swift new file mode 100644 index 000000000000..9f20b933841b --- /dev/null +++ b/Ecosia/Core/AdultFilter.swift @@ -0,0 +1,8 @@ +import Foundation + +public enum AdultFilter: String, Codable { + case + off = "n", + moderate = "i", + strict = "y" +} diff --git a/Ecosia/Core/AppDeviceInfo.swift b/Ecosia/Core/AppDeviceInfo.swift new file mode 100644 index 000000000000..1f8cba7b9a8a --- /dev/null +++ b/Ecosia/Core/AppDeviceInfo.swift @@ -0,0 +1,44 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Foundation + +public struct AppDeviceInfo: Equatable { + + public let platform: String + public let bundleId: String + public let osVersion: String + public let deviceManufacturer: String + public let deviceModel: String + public let locale: String + public let country: String? + public let deviceBuildVersion: String? + public let appVersion: String + public let installReceipt: String? + public let adServicesAttributionToken: String? + + public init(platform: String, + bundleId: String, + osVersion: String, + deviceManufacturer: String, + deviceModel: String, + locale: String, + country: String? = nil, + deviceBuildVersion: String? = nil, + appVersion: String, + installReceipt: String? = nil, + adServicesAttributionToken: String? = nil) { + self.platform = platform + self.bundleId = bundleId + self.osVersion = osVersion + self.deviceManufacturer = deviceManufacturer + self.deviceModel = deviceModel + self.locale = locale + self.country = country + self.deviceBuildVersion = deviceBuildVersion + self.appVersion = appVersion + self.installReceipt = installReceipt + self.adServicesAttributionToken = adServicesAttributionToken + } +} diff --git a/Ecosia/Core/Bookmarks/Bookmark.swift b/Ecosia/Core/Bookmarks/Bookmark.swift new file mode 100644 index 000000000000..b15d1f879f76 --- /dev/null +++ b/Ecosia/Core/Bookmarks/Bookmark.swift @@ -0,0 +1,29 @@ +import Foundation + +public typealias Title = String +public typealias Url = String + +public struct BookmarkMetadata: Equatable { + let addedAt: Date? + let modifiedAt: Date? + + public static var empty: BookmarkMetadata { + BookmarkMetadata(addedAt: nil, modifiedAt: nil) + } + + internal var stringValue: String { + var returnValue = "" + if let addedAt = addedAt { + returnValue += " \(String.addDate)=\"\(Int(addedAt.timeIntervalSince1970))\"" + } + if let modifiedAt = modifiedAt { + returnValue += " \(String.lastModified)=\"\(Int(modifiedAt.timeIntervalSince1970))\"" + } + return returnValue + } +} + +public enum BookmarkItem: Equatable { + case folder(Title, [BookmarkItem], BookmarkMetadata) + case bookmark(Title, Url, BookmarkMetadata) +} diff --git a/Ecosia/Core/Bookmarks/BookmarkParser.swift b/Ecosia/Core/Bookmarks/BookmarkParser.swift new file mode 100644 index 000000000000..56854049a421 --- /dev/null +++ b/Ecosia/Core/Bookmarks/BookmarkParser.swift @@ -0,0 +1,94 @@ +import Foundation +import SwiftSoup + +private typealias DateTag = String + +public enum BookmarkParserError: Error { + case noLeadingDL, noBody, cancelled +} + +public protocol BookmarkParseable { + func parseBookmarks() async throws -> [BookmarkItem] +} + +public class BookmarkParser: BookmarkParseable { + private let document: Document + private let dispatchQueue: DispatchQueue + + public init(html: String, dispatchQueue: DispatchQueue = .init(label: "org.ecosia.ios-core.bookmarks")) throws { + let document = try SwiftSoup.parse(html) + self.document = try document.normalizedDocumentIfRequired() + self.dispatchQueue = dispatchQueue + } + + public func parseBookmarks() async throws -> [BookmarkItem] { + try await withCheckedThrowingContinuation { continuation in + dispatchQueue.async { [weak self] in + guard let self = self else { + return continuation.resume(throwing: BookmarkParserError.cancelled) + } + do { + let result = try self.parse(element: try self.document.getLeadingDL()) + continuation.resume(with: .success(result)) + } catch { + continuation.resume(throwing: error) + } + } + } + } +} + +private extension BookmarkParser { + func parse(element: Element) throws -> [BookmarkItem] { + var items = [BookmarkItem]() + + let children = try element.getLeadingDL() + .children() + .filter({ try $0.select(.dt).hasText() }) /// only
is a valid bookmark/folder element + + for child in children { + let h3 = try child.select(.h3) + if let nextFolderItem = h3.first() { + guard let title = try? nextFolderItem.text() else { continue } + items.append(.folder(title, try parse(element: child), h3.extractBookmarkMetadata())) + continue /// item is a folder, don't process as bookmark + } + + let link = try child.select(.a) + let href = try link.attr(.href) + let title = try link.text() + + items.append(.bookmark(title, href, link.extractBookmarkMetadata())) + } + + return items + } +} + +private extension Elements { + func extractDate(_ tag: DateTag) -> Date? { + guard + let timeIntervalString = try? attr(tag), + let timeInterval = TimeInterval(timeIntervalString) + else { + return nil + } + return Date(timeIntervalSince1970: timeInterval) + } + + func extractBookmarkMetadata() -> BookmarkMetadata { + BookmarkMetadata( + addedAt: extractDate(.addDate), + modifiedAt: extractDate(.lastModified) + ) + } +} + +private extension Element { + func getLeadingDL() throws -> Element { + guard let leadingDL = try select(.dl).first() else { + throw BookmarkParserError.noLeadingDL + } + return leadingDL + } +} diff --git a/Ecosia/Core/Bookmarks/BookmarkSerializer.swift b/Ecosia/Core/Bookmarks/BookmarkSerializer.swift new file mode 100644 index 000000000000..2f5661980bde --- /dev/null +++ b/Ecosia/Core/Bookmarks/BookmarkSerializer.swift @@ -0,0 +1,81 @@ +import Foundation +import SwiftSoup + +public enum BookmarkSerializerError: Error { + case cancelled +} + +public protocol BookmarkSerializable { + func serializeBookmarks(_ bookmarks: [BookmarkItem]) async throws -> String +} + +public class BookmarkSerializer: BookmarkSerializable { + private let dispatchQueue: DispatchQueue + + public init(dispatchQueue: DispatchQueue = .init(label: "org.ecosia.ios-core.bookmarks")) { + self.dispatchQueue = dispatchQueue + } + + public func serializeBookmarks(_ bookmarks: [BookmarkItem]) async throws -> String { + try await withCheckedThrowingContinuation { continuation in + dispatchQueue.async { [weak self] in + guard let self = self else { + return continuation.resume(throwing: BookmarkSerializerError.cancelled) + } + /// The trailing open

tag is part of the Netscape Bookmark file syntax + var html = """ + + + Bookmarks +

Bookmarks

+

+ + """ + + for bookmark in bookmarks { + html += self.bookmarkBody(for: bookmark, indentation: 2) + } + + html += """ + + \(String.indent(by: 1))

+ + """ + + continuation.resume(returning: html) + } + } + } + + func bookmarkBody(for bookmark: BookmarkItem, indentation: Int) -> String { + switch bookmark { + case let .bookmark(title, url, metadata): + return """ + \(String.indent(by: indentation))

\(Entities.escape(title)) + """ + case let .folder(title, children, metadata): + let start = """ + \(String.indent(by: indentation))
\(Entities.escape(title)) + \(String.indent(by: indentation))

+ + """ + + let body = children.map { + bookmarkBody(for: $0, indentation: indentation + 1) + }.joined(separator: "\n") + + let end = """ + + \(String.indent(by: indentation))

+ """ + + return start + body + end + } + } +} + +private extension String { + static func indent(by level: Int) -> String { + return String(repeating: "\t", count: level) + } +} diff --git a/Ecosia/Core/Bookmarks/Document+Safari.swift b/Ecosia/Core/Bookmarks/Document+Safari.swift new file mode 100644 index 000000000000..105102eb449d --- /dev/null +++ b/Ecosia/Core/Bookmarks/Document+Safari.swift @@ -0,0 +1,29 @@ +import SwiftSoup + +extension Document { + var isSafariFormat: Bool { + if let leadingDL = try? select(.dl).first(), leadingDL.parents().size() > 2 { + return true + } + return false + } + + func normalizedDocumentIfRequired() throws -> Document { + isSafariFormat ? try normalizedSafariExport() : self + } +} + +private extension Document { + func normalizedSafariExport() throws -> Document { + guard let body = try select("body").first() else { + throw BookmarkParserError.noBody + } + + let newDocument = Document("") + let dlElement = try newDocument.appendElement("DL") + let bodyChildren = body.getChildNodes() + try dlElement.insertChildren(0, bodyChildren) + + return newDocument + } +} diff --git a/Ecosia/Core/Bookmarks/String+CssQuery.swift b/Ecosia/Core/Bookmarks/String+CssQuery.swift new file mode 100644 index 000000000000..cd95c989b4d1 --- /dev/null +++ b/Ecosia/Core/Bookmarks/String+CssQuery.swift @@ -0,0 +1,11 @@ +import Foundation + +extension String { + static let dt = "DT" + static let dl = "DL" + static let h3 = "H3" + static let a = "A" + static let href = "href" + static let addDate = "ADD_DATE" + static let lastModified = "LAST_MODIFIED" +} diff --git a/Ecosia/Braze/APNConsent.swift b/Ecosia/Core/Braze/APNConsent.swift similarity index 100% rename from Ecosia/Braze/APNConsent.swift rename to Ecosia/Core/Braze/APNConsent.swift diff --git a/Ecosia/Braze/BrazeService.swift b/Ecosia/Core/Braze/BrazeService.swift similarity index 99% rename from Ecosia/Braze/BrazeService.swift rename to Ecosia/Core/Braze/BrazeService.swift index ab3ce600752c..e78aea2ce4f0 100644 --- a/Ecosia/Braze/BrazeService.swift +++ b/Ecosia/Core/Braze/BrazeService.swift @@ -5,7 +5,6 @@ import Foundation import BrazeKit import BrazeUI -import Core import NotificationCenter final class BrazeService: NSObject { diff --git a/Ecosia/Core/Bundle.swift b/Ecosia/Core/Bundle.swift new file mode 100644 index 000000000000..26471e9e8bd6 --- /dev/null +++ b/Ecosia/Core/Bundle.swift @@ -0,0 +1,7 @@ +import Foundation + +extension Bundle { + public static let version = marketing + "." + bundle + private static let marketing = main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "4.0.20" + private static let bundle = main.infoDictionary?["CFBundleVersion"] as? String ?? "840" +} diff --git a/Ecosia/Core/CloudFlareKeyProvider.swift b/Ecosia/Core/CloudFlareKeyProvider.swift new file mode 100644 index 000000000000..fbc6598aa03a --- /dev/null +++ b/Ecosia/Core/CloudFlareKeyProvider.swift @@ -0,0 +1,8 @@ +import Foundation + +struct CloudflareKeyProvider { + static let clientId = "CF-Access-Client-Id" + static let clientSecret = "CF-Access-Client-Secret" + + private init() {} +} diff --git a/Ecosia/Core/Cookie.swift b/Ecosia/Core/Cookie.swift new file mode 100644 index 000000000000..40746c27c644 --- /dev/null +++ b/Ecosia/Core/Cookie.swift @@ -0,0 +1,182 @@ +import Foundation + +public enum Cookie: String { + case main + case consent + + // MARK: - Init + /// Initialize Cookie enum based on the name + init?(_ name: String) { + switch name { + case "ECFG": + self = .main + case "ECCC": + self = .consent + default: + return nil + } + } + + // MARK: - Main Specific Properties + + private struct MainCookieProperties { + static let userId = "cid" + static let suggestions = "as" + static let personalized = "pz" + static let customSettings = "cs" + static let adultFilter = "f" + static let marketCode = "mc" + static let treeCount = "t" + static let language = "l" + static let marketApplied = "ma" + static let marketReapplied = "mr" + static let deviceType = "dt" + static let firstSearch = "fs" + static let addon = "a" + } + + // MARK: - Common Properties + + var name: String { + switch self { + case .main: + return "ECFG" + case .consent: + return "ECCC" + } + } + + /// Values for incognito mode cookies. + static var incognitoValues: [String: String] { + var values = [String: String]() + values[MainCookieProperties.adultFilter] = User.shared.adultFilter.rawValue + values[MainCookieProperties.marketCode] = User.shared.marketCode.rawValue + values[MainCookieProperties.language] = Language.current.rawValue + values[MainCookieProperties.suggestions] = .init(NSNumber(value: User.shared.autoComplete).intValue) + values[MainCookieProperties.personalized] = .init(NSNumber(value: User.shared.personalized).intValue) + values[MainCookieProperties.marketApplied] = "1" + values[MainCookieProperties.marketReapplied] = "1" + values[MainCookieProperties.deviceType] = "mobile" + values[MainCookieProperties.firstSearch] = "0" + values[MainCookieProperties.addon] = "1" + return values + } + + /// Values for standard mode cookies. + static var standardValues: [String: String] { + var values = incognitoValues + values[MainCookieProperties.userId] = User.shared.id + values[MainCookieProperties.treeCount] = .init(User.shared.searchCount) + return values + } + + // MARK: - Functions + + /// Creates an incognito mode ECFG cookie. + /// - Parameter urlProvider: Provides the URL information. + /// - Returns: An HTTPCookie configured for incognito mode. + public static func makeIncognitoCookie(_ urlProvider: URLProvider = Environment.current.urlProvider) -> HTTPCookie { + HTTPCookie(properties: [.name: Cookie.main.name, + .domain: ".\(urlProvider.domain ?? "")", + .path: "/", + .value: Cookie.incognitoValues.map { $0.0 + "=" + $0.1 }.joined(separator: ":")])! + } + + /// Creates a standard mode ECFG cookie. + /// - Parameter urlProvider: Provides the URL information. + /// - Returns: An HTTPCookie configured for standard mode. + public static func makeStandardCookie(_ urlProvider: URLProvider = Environment.current.urlProvider) -> HTTPCookie { + HTTPCookie(properties: [.name: Cookie.main.name, + .domain: ".\(urlProvider.domain ?? "")", + .path: "/", + .value: Cookie.standardValues.map { $0.0 + "=" + $0.1 }.joined(separator: ":")])! + } + + public static func makeConsentCookie(_ urlProvider: URLProvider = Environment.current.urlProvider) -> HTTPCookie? { + guard let cookieConsentValue = User.shared.cookieConsentValue else { return nil } + return HTTPCookie(properties: [.name: Cookie.consent.name, + .domain: ".\(urlProvider.domain ?? "")", + .path: "/", + .value: cookieConsentValue]) + } + + /// Processes received cookies. + /// - Parameters: + /// - cookies: An array of HTTPCookie objects. + /// - urlProvider: Provides the URL information. + public static func received(_ cookies: [HTTPCookie], urlProvider: URLProvider = Environment.current.urlProvider) { + cookies.forEach { cookie in + guard let cookieType = Cookie(cookie.name), cookie.domain.contains(".\(urlProvider.domain ?? "")") else { return } + cookieType.extract(cookie) + } + } + + /// Processes received cookies from an HTTP response. + /// - Parameters: + /// - response: An HTTPURLResponse object. + /// - urlProvider: Provides the URL information. + public static func received(_ response: HTTPURLResponse, urlProvider: URLProvider = Environment.current.urlProvider) { + (response.allHeaderFields as? [String: String]).map { + HTTPCookie.cookies(withResponseHeaderFields: $0, for: urlProvider.root) + }.map { received($0, urlProvider: urlProvider) } + } + + /// Extracts and handles ECFG specific properties. + /// - Parameter properties: A dictionary of cookie properties. + private func extractECFG(_ properties: [String: String]) { + var user = User.shared + + properties[MainCookieProperties.userId].map { + user.id = $0 + } + + properties[MainCookieProperties.treeCount].flatMap(Int.init).map { + // tree count should only increase or be reset to 0 on logout + if $0 == 0 || $0 > user.searchCount { + user.searchCount = $0 + } + } + + properties[MainCookieProperties.marketCode].flatMap(Local.init).map { + user.marketCode = $0 + } + + properties[MainCookieProperties.adultFilter].flatMap(AdultFilter.init).map({ + user.adultFilter = $0 + }) + + properties[MainCookieProperties.personalized].flatMap(Int.init).flatMap(NSNumber.init).flatMap(Bool.init).map({ + user.personalized = $0 + }) + + properties[MainCookieProperties.suggestions].map({ + user.autoComplete = ($0 as NSString).boolValue + }) + + User.shared = user + } + + /// Extracts and handles ECCC specific properties. + /// - Parameter value: A string of cookie values expressed by a sequence of letters (e.g. `eampg`) + private func extractECCC(_ value: String) { + User.shared.cookieConsentValue = value + } + + /// Extracts properties from a cookie. + /// - Parameter cookie: An HTTPCookie object. + private func extract(_ cookie: HTTPCookie) { + + switch self { + case .main: + let properties = cookie.value.components(separatedBy: ":") + .map { $0.components(separatedBy: "=") } + .filter { $0.count == 2 } + .reduce(into: [:]) { result, item in + result[item[0]] = item[1] + } + extractECFG(properties) + case .consent: + extractECCC(cookie.value) + } + } +} diff --git a/Ecosia/Core/Date+TimestampProvider.swift b/Ecosia/Core/Date+TimestampProvider.swift new file mode 100644 index 000000000000..46a43ceb0916 --- /dev/null +++ b/Ecosia/Core/Date+TimestampProvider.swift @@ -0,0 +1,7 @@ +import Foundation + +extension Date: TimestampProvider { + public var currentTimestamp: TimeInterval { + return self.timeIntervalSince1970 + } +} diff --git a/Ecosia/Core/Encodable+Dictionary.swift b/Ecosia/Core/Encodable+Dictionary.swift new file mode 100644 index 000000000000..ebfdd397a5f2 --- /dev/null +++ b/Ecosia/Core/Encodable+Dictionary.swift @@ -0,0 +1,7 @@ +import Foundation + +extension Encodable { + public var dictionary: [String: String] { + (try? JSONSerialization.jsonObject(with: JSONEncoder().encode(self))).flatMap { $0 as? [String: String] } ?? [String: String]() + } +} diff --git a/Ecosia/Core/Environment/Environment.Auth.swift b/Ecosia/Core/Environment/Environment.Auth.swift new file mode 100644 index 000000000000..4acfaed58963 --- /dev/null +++ b/Ecosia/Core/Environment/Environment.Auth.swift @@ -0,0 +1,23 @@ +import Foundation + +extension Environment { + struct Auth: Equatable { + let id: String + let secret: String + } + + var auth: Auth? { + switch self { + case .staging: + let keyId = "CF_ACCESS_CLIENT_ID" + let keySecret = "CF_ACCESS_CLIENT_SECRET" + + guard let id = EnvironmentFetcher.valueFromMainBundleOrProcessInfo(forKey: keyId), + let secret = EnvironmentFetcher.valueFromMainBundleOrProcessInfo(forKey: keySecret) else { return nil } + return Auth(id: id, secret: secret) + + default: + return nil + } + } +} diff --git a/Ecosia/Core/Environment/Environment.swift b/Ecosia/Core/Environment/Environment.swift new file mode 100644 index 000000000000..3d077a0f7a38 --- /dev/null +++ b/Ecosia/Core/Environment/Environment.swift @@ -0,0 +1,29 @@ +import Foundation + +public enum Environment: Equatable { + case production + case staging +} + +extension Environment { + + public static var current: Environment { + #if PRODUCTION + return .production + #else + return .staging + #endif + } +} + +extension Environment { + + public var urlProvider: URLProvider { + switch self { + case .production: + return .production + case .staging: + return .staging + } + } +} diff --git a/Ecosia/Core/Environment/URLProvider.swift b/Ecosia/Core/Environment/URLProvider.swift new file mode 100644 index 000000000000..08e1f9700c52 --- /dev/null +++ b/Ecosia/Core/Environment/URLProvider.swift @@ -0,0 +1,154 @@ +import Foundation + +public enum URLProvider { + + case production + case staging + + public var root: URL { + switch self { + case .production: + return URL(string: "https://www.ecosia.org")! + case .staging: + return URL(string: "https://www.ecosia-staging.xyz")! + } + } + + public var domain: String? { + if let urlComponents = URLComponents(string: root.absoluteString) { + if let host = urlComponents.host { + let domain = host.replacingOccurrences(of: "www.", with: "") + return domain + } + } + return nil + } + + public var apiRoot: URL { + switch self { + case .production: + return URL(string: "https://api.ecosia.org")! + case .staging: + return URL(string: "https://api.ecosia-staging.xyz")! + } + } + + public var snowplow: String { + switch self { + case .production: + return "sp.ecosia.org" + case .staging: + return "org-ecosia-prod1.mini.snplow.net" + } + } + + var unleash: String { + switch self { + case .production: + return "prod" + case .staging: + return "staging" + } + } + + public var brazeEndpoint: String { + "sdk.fra-02.braze.eu" + } + + public var statistics: URL { + URL(string: "https://d2wfixp891z15b.cloudfront.net")! + } + + public var financialReportsData: URL { + URL(string: "https://s3.amazonaws.com/blog-en.ecosia.org/financial-reports/data.json")! + } + + public var privacy: URL { + URL(string: "https://www.ecosia.org/privacy")! + } + + public var faq: URL { + URL(string: "https://ecosia.helpscoutdocs.com/")! + } + + public var terms: URL { + URL(string: "https://docs.google.com/a/ecosia.org/document/d/1x31-MsVMcl17dK3k80IRPxIj5ZKQEHZPXRhU01H_Xfw/pub")! + } + + public var aboutCounter: URL { + URL(string: "https://ecosia.helpscoutdocs.com/article/369-impact-counter")! + } + + public var bookmarksHelp: URL { + URL(string: "https://ecosia.helpscoutdocs.com/article/458-import-export-bookmarks")! + } + + public var referHelp: URL { + URL(string: "https://ecosia.helpscoutdocs.com/article/358-refer-a-friend-ios-only")! + } + + public var financialReports: URL { + switch Language.current { + case .de: + return blog.appendingPathComponent("ecosia-finanzberichte-baumplanzbelege/") + case .fr: + return blog.appendingPathComponent("rapports-financiers-recus-de-plantations-arbres/") + default: + return blog.appendingPathComponent("ecosia-financial-reports-tree-planting-receipts/") + } + } + + public var blog: URL { + switch Language.current { + case .de: + return URL(string: "https://de.blog.ecosia.org/")! + case .fr: + return URL(string: "https://fr.blog.ecosia.org/")! + default: + return URL(string: "https://blog.ecosia.org/")! + } + } + + public var trees: URL { + switch Language.current { + case .de: + return blog.appendingPathComponent("tag/projekte/") + case .fr: + return blog.appendingPathComponent("tag/projets/") + default: + return blog.appendingPathComponent("tag/where-does-ecosia-plant-trees/") + } + } + + public var betaProgram: URL { + switch Language.current { + case .de: + return URL(string: "https://ecosia.typeform.com/to/catmFLuA")! + case .fr: + return URL(string: "https://ecosia.typeform.com/to/oaFZzT0F")! + default: + return URL(string: "https://ecosia.typeform.com/to/EeMLqL3X")! + } + } + + public var betaFeedback: URL { + switch Language.current { + case .de: + return URL(string: "https://ecosia.typeform.com/to/pIQ3uwp9")! + case .fr: + return URL(string: "https://ecosia.typeform.com/to/PRw7550n")! + default: + return URL(string: "https://ecosia.typeform.com/to/LlUGlFT9")! + } + } + + public var notifications: URL { + var components = URLComponents(url: URL(string: "https://api.ecosia.org/v1/notifications")!, resolvingAgainstBaseURL: false)! + components.queryItems = [ + .init(name: "language", value: Language.current.rawValue), + .init(name: "market", value: User.shared.marketCode.rawValue), + .init(name: "limit", value: "50") + ] + return components.url! + } +} diff --git a/Ecosia/Core/EnvironmentFetcher.swift b/Ecosia/Core/EnvironmentFetcher.swift new file mode 100644 index 000000000000..8c6186864fd9 --- /dev/null +++ b/Ecosia/Core/EnvironmentFetcher.swift @@ -0,0 +1,24 @@ +import Foundation + +public struct EnvironmentFetcher { + + private init() {} + + /// Fetches a string value associated with the specified key either from the Main Bundle Info Dictionary or the Process Info environment. + /// + /// - Parameters: + /// - key: The key for which to retrieve the associated string value. + /// - Returns: The string value associated with the key, or nil if not found. + public static func valueFromMainBundleOrProcessInfo(forKey key: String) -> String? { + // Attempt to retrieve the value from the Main Bundle Info Dictionary + // If not found, try to retrieve it from the Process Info environment + guard let value = Bundle.main.object(forInfoDictionaryKey: key) as? String + ?? ProcessInfo.processInfo.environment[key] else { + // Return nil if the value is not found in either location + return nil + } + + // Return the retrieved value + return value + } +} diff --git a/Ecosia/Core/Favourites.swift b/Ecosia/Core/Favourites.swift new file mode 100644 index 000000000000..88fdf6d8716a --- /dev/null +++ b/Ecosia/Core/Favourites.swift @@ -0,0 +1,13 @@ +import Foundation + +public final class Favourites { + public var items = [Page]() { + didSet { + PageStore.save(favourites: items) + } + } + + public init() { + items = PageStore.favourites + } +} diff --git a/Ecosia/Core/FeatureManagement/FeatureManagementSessionInitializer.swift b/Ecosia/Core/FeatureManagement/FeatureManagementSessionInitializer.swift new file mode 100644 index 000000000000..9dd97fe083ee --- /dev/null +++ b/Ecosia/Core/FeatureManagement/FeatureManagementSessionInitializer.swift @@ -0,0 +1,6 @@ +import Foundation + +public protocol FeatureManagementSessionInitializer { + + func startSession() async throws -> T? +} diff --git a/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/AppUpdateRule.swift b/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/AppUpdateRule.swift new file mode 100644 index 000000000000..e1cd9ddbd42d --- /dev/null +++ b/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/AppUpdateRule.swift @@ -0,0 +1,14 @@ +import Foundation + +struct AppUpdateRule: RefreshingRule { + + private var currentAppVersion: String? + + init(appVersion: String) { + self.currentAppVersion = appVersion + } + + var shouldRefresh: Bool { + currentAppVersion != Unleash.model.appVersion + } +} diff --git a/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/DeviceRegionChangeRule.swift b/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/DeviceRegionChangeRule.swift new file mode 100644 index 000000000000..12dec7deccd9 --- /dev/null +++ b/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/DeviceRegionChangeRule.swift @@ -0,0 +1,14 @@ +import Foundation + +struct DeviceRegionChangeRule: RefreshingRule { + + private var currentRegion: String + + init(localeProvider: RegionLocatable = Locale.current) { + currentRegion = localeProvider.regionIdentifierLowercasedWithFallbackValue + } + + var shouldRefresh: Bool { + currentRegion != Unleash.model.deviceRegion + } +} diff --git a/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/RefreshingRule.swift b/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/RefreshingRule.swift new file mode 100644 index 000000000000..8c88a34d61c9 --- /dev/null +++ b/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/RefreshingRule.swift @@ -0,0 +1,3 @@ +protocol RefreshingRule { + var shouldRefresh: Bool { get } +} diff --git a/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/TimeBasedRefreshingRule.swift b/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/TimeBasedRefreshingRule.swift new file mode 100644 index 000000000000..38e963e81780 --- /dev/null +++ b/Ecosia/Core/FeatureManagement/Unleash/RefreshingComponent/RefreshingRule/TimeBasedRefreshingRule.swift @@ -0,0 +1,16 @@ +import Foundation + +struct TimeBasedRefreshingRule: RefreshingRule { + + let interval: TimeInterval + let timestampProvider: TimestampProvider + + init(interval: TimeInterval, timestampProvider: TimestampProvider = Date()) { + self.interval = interval + self.timestampProvider = timestampProvider + } + + var shouldRefresh: Bool { + return timestampProvider.currentTimestamp - Unleash.model.updated.timeIntervalSince1970 > interval + } +} diff --git a/Ecosia/Core/FeatureManagement/Unleash/Unleash+RefreshComponent.swift b/Ecosia/Core/FeatureManagement/Unleash/Unleash+RefreshComponent.swift new file mode 100644 index 000000000000..0fa453861841 --- /dev/null +++ b/Ecosia/Core/FeatureManagement/Unleash/Unleash+RefreshComponent.swift @@ -0,0 +1,16 @@ +import Foundation + +extension Unleash { + + /// Adds a refreshing rule to the `rules` array. + /// + /// This method checks if a rule of the same type already exists in the `rules` array + /// and adds the new rule only if it's not present. This prevents duplicate rules of the same type. + /// + /// - Parameter rule: The refreshing rule to be added. + static func addRule(_ rule: RefreshingRule) { + if !rules.contains(where: { type(of: $0) == type(of: rule) }) { + rules.append(rule) + } + } +} diff --git a/Ecosia/Core/FeatureManagement/Unleash/Unleash.Model.swift b/Ecosia/Core/FeatureManagement/Unleash/Unleash.Model.swift new file mode 100644 index 000000000000..db2830c62bb3 --- /dev/null +++ b/Ecosia/Core/FeatureManagement/Unleash/Unleash.Model.swift @@ -0,0 +1,53 @@ +import Foundation + +extension Unleash { + public struct Model: Codable { + public var id = UUID() + var toggles = Set() + var updated = Date(timeIntervalSince1970: 0) + var appVersion: String = "" + var deviceRegion: String = "" + public var etag: String = "" + + public subscript(_ name: Toggle.Name) -> Toggle? { + toggles.first { $0.name == name.rawValue } + } + } + + public struct Toggle: Codable, Hashable { + public enum Name: String { + case apnConsentOnLaunch = "mob_ios_apn_consent_on_launch" + case brazeIntegration = "mob_ios_braze_integration" + case configTest = "mob_ios_staging_config" + case seedCounterNTP = "mob_ios_seed_counter_ntp" + case newsletterCard = "mob_ios_newsletter_card" + case onboardingRemove = "mob_ios_onboarding_remove" + } + + public let name: String + public let enabled: Bool + public let variant: Variant + + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.name == rhs.name + } + + public func hash(into: inout Hasher) { + into.combine(name) + } + } + + public struct Variant: Codable { + public let name: String + public let enabled: Bool + public let payload: Payload? + } + + public struct Payload: Codable { + public let type, value: String + } + + struct FeatureResponse: Codable { + let toggles: [Toggle] + } +} diff --git a/Ecosia/Core/FeatureManagement/Unleash/Unleash.swift b/Ecosia/Core/FeatureManagement/Unleash/Unleash.swift new file mode 100644 index 000000000000..376d64da40c6 --- /dev/null +++ b/Ecosia/Core/FeatureManagement/Unleash/Unleash.swift @@ -0,0 +1,153 @@ +import Foundation + +public protocol UnleashProtocol { + /// Checks if a toggle with the given name exists and is enabled. + /// - Parameter name: The name of the toggle. + /// - Returns: `true` if the toggle is enabled, `false` otherwise. + static func isEnabled(_ flag: Unleash.Toggle.Name) -> Bool +} + +public enum Unleash: UnleashProtocol { + + public typealias Context = [String: String] + + static var model = Model() + private static let queue = DispatchQueue(label: "com.ecosia.ModelManagerQueue") + static var rules: [RefreshingRule] = [] + static var currentDeviceRegion: String { + Locale.current.regionIdentifierLowercasedWithFallbackValue + } + + public static func queryParameters(appVersion: String) -> Context { + ["userId": model.id.uuidString, + "appName": "iOS", + "appVersion": appVersion, + "versionOnInstall": User.shared.versionOnInstall, + "environment": Environment.current.urlProvider.unleash, + "market": User.shared.marketCode.rawValue, + "deviceRegion": currentDeviceRegion, + "personalCounterSearches": "\(User.shared.searchCount)"] + } + + /// Starts the Unleash feature management session. + /// - Parameters: + /// - client: The HTTP client to use for network requests. Default is `URLSessionHTTPClient`. + /// - request: The base request to be used for the session. Default is `nil`. + /// - env: The environment for the session. Default is `.production`. + /// - force: Indicates whether to force a refresh even if the model is not expired. Default is `false`. + /// - Returns: The updated `Model` after starting the session. + /// - Throws: An error if the session fails to start or save the model. + public static func start(client: HTTPClient = URLSessionHTTPClient(), + request: BaseRequest? = nil, + env: Environment = .production, + appVersion: String) async throws -> Model { + return try await withCheckedThrowingContinuation({ continuation in + Self.queue.async { + Task { + do { + // Load from filesystem if not already happened + if model.updated.timeIntervalSince1970 == 0 { + await load().map({ Self.model = $0 }) + } + + // Call backend to refresh the model + Self.model = try await refresh(client: client, + request: request, + model: model, + env: env, + appVersion: appVersion) + + // Save the updated model to the filesystem + try await save(Self.model) + continuation.resume(returning: self.model) + } catch { + continuation.resume(throwing: error) + } + } + } + }) + } + + public static func isEnabled(_ name: Toggle.Name) -> Bool { + model[name]?.enabled ?? false + } + + /// Retrieves the variant of a toggle with the given name. + /// - Parameter name: The name of the toggle. + /// - Returns: The variant of the toggle if it exists, otherwise a default disabled variant. + public static func getVariant(_ name: Toggle.Name) -> Variant { + model[name]?.variant ?? Variant(name: "disabled", enabled: false, payload: nil) + } + + /// Refreshes the Unleash model by making a network request to the backend. + /// - Parameters: + /// - client: The HTTP client to use for network requests. Default is `URLSessionHTTPClient`. + /// - request: The base request to be used for refreshing the model. Default is `nil`. + /// - model: The current model. + /// - env: The environment for the session. + /// - appVersion: The package's hosting app version (`CFShortVersionString`) + /// - Returns: The latest available `Model` after refreshing. + /// - Throws: An error if the model fails to refresh or update. + static func refresh(client: HTTPClient = URLSessionHTTPClient(), + request: BaseRequest? = nil, + model: Model, + env: Environment, + appVersion: String) async throws -> Model { + + guard shouldRefresh else { + // Return the cached model if refresh is not required + return model + } + + // Create a request to refresh the model from the backend + let unleashRemoteRequest = UnleashStartRequest(etag: model.etag, queryParameters: Unleash.queryParameters(appVersion: appVersion)) + + // Initialize the Unleash feature management session + let unleashSessionInitializer = UnleashFeatureManagementSessionInitializer(client: client, + request: request ?? unleashRemoteRequest, + model: model) + + // Start the session and get the latest available model + var latestAvailableModel: Unleash.Model = try await unleashSessionInitializer.startSession()! + latestAvailableModel.updated = .init() + latestAvailableModel.appVersion = appVersion + latestAvailableModel.deviceRegion = currentDeviceRegion + return latestAvailableModel + } + + /// Resets the Unleash feature management session and returns the initial model. + /// - Parameters: + /// - client: The HTTP client to use for network requests. Default is `URLSessionHTTPClient`. + /// - env: The environment for the session. + /// - Returns: The initial `Model` after resetting the session. + /// - Throws: An error if the session fails to reset or save the model. + public static func reset(client: HTTPClient = URLSessionHTTPClient(), + env: Environment, + appVersion: String) async throws -> Model { + Self.model = .init() + try await save(Self.model) + let unleashRemoteRequest = UnleashStartRequest(etag: model.etag, queryParameters: Unleash.queryParameters(appVersion: appVersion)) + return try await start(client: client, + request: unleashRemoteRequest, + env: env, + appVersion: appVersion) + } + + /// Loads the model from the filesystem. + /// - Returns: The loaded `Model` if successful, otherwise `nil`. + static func load() async -> Model? { + try? JSONDecoder().decode(Model.self, from: .init(contentsOf: FileManager.unleash)) + } + + /// Saves the model to the filesystem. + /// - Parameter model: The model to be saved. + /// - Throws: An error if the model fails to be encoded or saved. + static func save(_ model: Model) async throws { + try JSONEncoder().encode(model).write(to: FileManager.unleash, options: .atomic) + } + + /// Determines whether the model should be refreshed based on its refreshing context providers. + static var shouldRefresh: Bool { + return rules.first { $0.shouldRefresh == true } != nil + } +} diff --git a/Ecosia/Core/FeatureManagement/Unleash/UnleashFeatureManagementSessionInitializer.swift b/Ecosia/Core/FeatureManagement/Unleash/UnleashFeatureManagementSessionInitializer.swift new file mode 100644 index 000000000000..dc6efd0e17ec --- /dev/null +++ b/Ecosia/Core/FeatureManagement/Unleash/UnleashFeatureManagementSessionInitializer.swift @@ -0,0 +1,52 @@ +import Foundation + +public final class UnleashFeatureManagementSessionInitializer: FeatureManagementSessionInitializer { + + private let client: HTTPClient + private let request: BaseRequest + private var model: Unleash.Model + var isSameModel: Bool = false + + public enum Error: Swift.Error { + case network + case noData + } + + public init(client: HTTPClient, request: BaseRequest, model: Unleash.Model) { + self.client = client + self.request = request + self.model = model + } + + public func startSession() async throws -> T? { + + let (data, response) = try await client.perform(request) + + guard let response else { + throw UnleashFeatureManagementSessionInitializer.Error.noData + } + + switch response.statusCode { + case 399...599: + throw UnleashFeatureManagementSessionInitializer.Error.network + case 304: // no changes reported by server -> return cached model + var updatedModel = model + updatedModel.updated = .init() + return updatedModel as? T + case 200: + break + default: + throw UnleashFeatureManagementSessionInitializer.Error.noData + } + + // read out Etag which identifies cached responses + (response.allHeaderFields["Etag"] as? String).map { model.etag = $0 } + + guard let remoteToggles = try? JSONDecoder().decode(Unleash.FeatureResponse.self, from: data) else { + return model as? T + } + + model.toggles = Set(remoteToggles.toggles) + return model as? T + } +} diff --git a/Ecosia/Core/FeatureManagement/Unleash/UnleashRefreshConfigurator.swift b/Ecosia/Core/FeatureManagement/Unleash/UnleashRefreshConfigurator.swift new file mode 100644 index 000000000000..edbc19676a8f --- /dev/null +++ b/Ecosia/Core/FeatureManagement/Unleash/UnleashRefreshConfigurator.swift @@ -0,0 +1,27 @@ +import Foundation + +public final class UnleashRefreshConfigurator { + + public init() {} + + @discardableResult + public func withAppUpdateCheckRule(appVersion: String) -> Self { + let appUpdateRule = AppUpdateRule(appVersion: appVersion) + Unleash.addRule(appUpdateRule) + return self + } + + @discardableResult + public func withTwentyFourHoursCacheExpirationRule() -> Self { + let timeRule = TimeBasedRefreshingRule(interval: TimeInterval.twentyFourHoursTimeInterval) + Unleash.addRule(timeRule) + return self + } + + @discardableResult + public func withDeviceRegionUpdateCheckRule(localeProvider: RegionLocatable = Locale.current) -> Self { + let regionRule = DeviceRegionChangeRule(localeProvider: localeProvider) + Unleash.addRule(regionRule) + return self + } +} diff --git a/Ecosia/Core/FeatureManagement/Unleash/UnleashStartRequest.swift b/Ecosia/Core/FeatureManagement/Unleash/UnleashStartRequest.swift new file mode 100644 index 000000000000..a9fa73339ce0 --- /dev/null +++ b/Ecosia/Core/FeatureManagement/Unleash/UnleashStartRequest.swift @@ -0,0 +1,22 @@ +import Foundation + +public struct UnleashStartRequest: BaseRequest { + + public var method: HTTPMethod { + .get + } + + public var path: String { + "/v2/toggles" + } + + var etag: String + + public var queryParameters: [String: String]? + + public var additionalHeaders: [String: String]? { + ["If-None-Match": etag] + } + + public var body: Data? +} diff --git a/Ecosia/Core/FileManager.swift b/Ecosia/Core/FileManager.swift new file mode 100644 index 000000000000..bada4ef80ebd --- /dev/null +++ b/Ecosia/Core/FileManager.swift @@ -0,0 +1,21 @@ +import Foundation + +extension FileManager { + static let pages = directory.appendingPathComponent("pages") + static let snapshots = directory.appendingPathComponent("snapshots") + static let user = directory.item("user") + static let tabs = pages.item("tabs") + static let currentTab = pages.item("currentTab") + static let favourites = pages.item("favourites") + static let history = pages.item("history") + static let unleash = directory.item("unleash") + static let news = directory.item("news") + + private static let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] +} + +private extension URL { + func item(_ name: String) -> URL { + appendingPathComponent(name + ".ecosia") + } +} diff --git a/Ecosia/Core/HTTPClient/HTTPClient.swift b/Ecosia/Core/HTTPClient/HTTPClient.swift new file mode 100644 index 000000000000..cf613a9e7007 --- /dev/null +++ b/Ecosia/Core/HTTPClient/HTTPClient.swift @@ -0,0 +1,8 @@ +import Foundation + +public protocol HTTPClient { + + typealias Result = (Data, HTTPURLResponse?) + + func perform(_ request: BaseRequest) async throws -> Result +} diff --git a/Ecosia/Core/HTTPClient/HTTPMethod.swift b/Ecosia/Core/HTTPClient/HTTPMethod.swift new file mode 100644 index 000000000000..bf59ef35f5ca --- /dev/null +++ b/Ecosia/Core/HTTPClient/HTTPMethod.swift @@ -0,0 +1,6 @@ +import Foundation + +public enum HTTPMethod: String { + case get = "GET" + case post = "POST" +} diff --git a/Ecosia/Core/HTTPClient/Requestable/BaseRequest.swift b/Ecosia/Core/HTTPClient/Requestable/BaseRequest.swift new file mode 100644 index 000000000000..9c46c7b424a4 --- /dev/null +++ b/Ecosia/Core/HTTPClient/Requestable/BaseRequest.swift @@ -0,0 +1,49 @@ +import Foundation + +public protocol BaseRequest: Requestable {} + +enum RequestError: Error { + case invalidBaseURL + case invalidURLComponents +} + +public extension BaseRequest { + + var baseURL: URL { + environment.urlProvider.apiRoot + } + + var environment: Environment { + .current + } + + func makeURLRequest() throws -> URLRequest { + guard var urlComponents = URLComponents(url: baseURL, resolvingAgainstBaseURL: false) else { + throw RequestError.invalidBaseURL + } + urlComponents.path = path + if let queryParameters { + urlComponents.queryItems = queryParameters.map({ .init(name: $0.key, value: $0.value ) }) + } + guard let url = urlComponents.url else { + throw RequestError.invalidURLComponents + } + + var request = URLRequest(url: url) + request.httpMethod = method.rawValue + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.cachePolicy = .reloadIgnoringLocalCacheData + request.httpBody = body + + if let auth = environment.auth { + request.setValue(auth.id, forHTTPHeaderField: CloudflareKeyProvider.clientId) + request.setValue(auth.secret, forHTTPHeaderField: CloudflareKeyProvider.clientSecret) + } + + if let additionalHeaders { + additionalHeaders.forEach({ request.setValue($0.value, forHTTPHeaderField: $0.key) }) + } + + return request + } +} diff --git a/Ecosia/Core/HTTPClient/Requestable/Requestable.swift b/Ecosia/Core/HTTPClient/Requestable/Requestable.swift new file mode 100644 index 000000000000..c4606a19708f --- /dev/null +++ b/Ecosia/Core/HTTPClient/Requestable/Requestable.swift @@ -0,0 +1,20 @@ +import Foundation + +public protocol Requestable { + + var method: HTTPMethod { get } + + var baseURL: URL { get } + + var path: String { get } + + var environment: Environment { get } + + var queryParameters: [String: String]? { get set } + + var additionalHeaders: [String: String]? { get } + + var body: Data? { get set } + + func makeURLRequest() throws -> URLRequest +} diff --git a/Ecosia/Core/HTTPClient/URLSessionHTTPClient.swift b/Ecosia/Core/HTTPClient/URLSessionHTTPClient.swift new file mode 100644 index 000000000000..d21f0d668737 --- /dev/null +++ b/Ecosia/Core/HTTPClient/URLSessionHTTPClient.swift @@ -0,0 +1,11 @@ +import Foundation + +public final class URLSessionHTTPClient: HTTPClient { + + public init() {} + + public func perform(_ request: BaseRequest) async throws -> HTTPClient.Result { + let (data, response) = try await URLSession.shared.data(for: request.makeURLRequest()) + return (data, response as? HTTPURLResponse) + } +} diff --git a/Ecosia/Core/HTTPClient/URLSessionProtocol.swift b/Ecosia/Core/HTTPClient/URLSessionProtocol.swift new file mode 100644 index 000000000000..b6698a508277 --- /dev/null +++ b/Ecosia/Core/HTTPClient/URLSessionProtocol.swift @@ -0,0 +1,7 @@ +import Foundation + +public protocol URLSessionProtocol { + func data(from url: URL) async throws -> (Data, URLResponse) +} + +extension URLSession: URLSessionProtocol { } diff --git a/Ecosia/Core/History.swift b/Ecosia/Core/History.swift new file mode 100644 index 000000000000..f55e090b0799 --- /dev/null +++ b/Ecosia/Core/History.swift @@ -0,0 +1,30 @@ +import Foundation + +public final class History { + public var items: [(Date, Page)] { + get { dictionary.sorted { $0.0 < $1.0 }.map { ($0.0, $0.1) } } + set { dictionary = .init(uniqueKeysWithValues: newValue) } + } + + private(set) var dictionary = [Date: Page]() { + didSet { + PageStore.save(history: dictionary) + } + } + + public init() { + dictionary = PageStore.history + } + + public func add(_ page: Page) { + dictionary[Date()] = page + } + + public func delete(_ at: Date) { + dictionary.removeValue(forKey: at) + } + + public func deleteAll() { + dictionary = [:] + } +} diff --git a/Ecosia/Core/Images.swift b/Ecosia/Core/Images.swift new file mode 100644 index 000000000000..040b477221b0 --- /dev/null +++ b/Ecosia/Core/Images.swift @@ -0,0 +1,63 @@ +import Foundation + +public final class Images: Publisher { + public var subscriptions = [Subscription]() + var items = Set() + private let session: URLSession + + public init(_ session: URLSession) { + self.session = session + } + + public func load(_ subscriber: AnyObject, url: URL, closure: @escaping (Input) -> Void) { + subscribe(subscriber, closure: closure) + guard let item = items.first(where: { $0.url == url }) + else { + download(url) + return + } + send(item) + } + + public func cancellAll() { + session.getAllTasks { + $0.forEach { $0.cancel() } + } + } + + public func cancel(_ url: URL) { + session.getAllTasks { + $0.first { $0.originalRequest?.url == url }?.cancel() + } + } + + private func download(_ url: URL) { + session.dataTask(with: url) { data, _, _ in + DispatchQueue.main.async { [weak self] in + data.map { + let item = Item(url, $0) + self?.send(item) + self?.items.insert(item) + } + } + }.resume() + } + + public struct Item: Hashable { + public let url: URL + public let data: Data + + init(_ url: URL, _ data: Data) { + self.url = url + self.data = data + } + + public func hash(into: inout Hasher) { + into.combine(url) + } + + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.url == rhs.url + } + } +} diff --git a/Ecosia/Core/Language.swift b/Ecosia/Core/Language.swift new file mode 100644 index 000000000000..ccd0560569fd --- /dev/null +++ b/Ecosia/Core/Language.swift @@ -0,0 +1,38 @@ +import Foundation + +public enum Language: String, Codable, CaseIterable { + case + de, + en, + es, + it, + fr, + nl, + sv + + public internal(set) static var current = make(for: .current) + + var locale: Local { + switch self { + case .de: return .de_de + case .en: return .en_us + case .es: return .es_es + case .it: return .it_it + case .fr: return .fr_fr + case .nl: return .nl_nl + case .sv: return .sv_se + } + } + + static func make(for locale: Locale) -> Self { + locale.withLanguage ?? .en + } +} + +private extension Locale { + var withLanguage: Ecosia.Language? { + languageCode.flatMap { + Ecosia.Language(rawValue: $0.lowercased()) + } + } +} diff --git a/Ecosia/Core/List.swift b/Ecosia/Core/List.swift new file mode 100644 index 000000000000..6ef7c8da88fe --- /dev/null +++ b/Ecosia/Core/List.swift @@ -0,0 +1,18 @@ +import Foundation + +struct List: Decodable where E: Decodable { + var items = [E]() + + init(from: Decoder) throws { + var root = try from.unkeyedContainer() + while !root.isAtEnd { + if let item = try? root.decode(E.self) { + items.append(item) + } else { + _ = try root.nestedContainer(keyedBy: Discard.self) + } + } + } +} + +private enum Discard: CodingKey { } diff --git a/Ecosia/Core/Local.swift b/Ecosia/Core/Local.swift new file mode 100644 index 000000000000..aaf0cd0699b1 --- /dev/null +++ b/Ecosia/Core/Local.swift @@ -0,0 +1,88 @@ +import Foundation + +public enum Local: String, Codable, CaseIterable { + case + es_ar = "es-ar", + en_au = "en-au", + de_at = "de-at", + fr_be = "fr-be", + nl_be = "nl-be", + pt_br = "pt-br", + bg_bg = "bg-bg", + en_ca = "en-ca", + fr_ca = "fr-ca", + es_cl = "es-cl", + zh_cn = "zh-cn", + es_co = "es-co", + hr_hr = "hr-hr", + da_dk = "da-dk", + fi_fi = "fi-fi", + fr_fr = "fr-fr", + de_de = "de-de", + zh_hk = "zh-hk", + en_in = "en-in", + en_id = "en-id", + en_ie = "en-ie", + it_it = "it-it", + ja_jp = "ja-jp", + lv_lv = "lv-lv", + lt_lt = "lt-lt", + en_my = "en-my", + es_mx = "es-mx", + nl_nl = "nl-nl", + en_nz = "en-nz", + nb_no = "nb-no", + es_pe = "es-pe", + en_ph = "en-ph", + pl_pl = "pl-pl", + pt_pt = "pt-pt", + ru_ru = "ru-ru", + ar_sa = "ar-sa", + en_sa = "en-sa", + en_sg = "en-sg", + sk_sk = "sk-sk", + en_za = "en-za", + ko_kr = "ko-kr", + es_es = "es-es", + sv_se = "sv-se", + de_ch = "de-ch", + fr_ch = "fr-ch", + zh_tw = "zh-tw", + en_th = "en-th", + th_th = "th-th", + tr_tr = "tr-tr", + uk_ua = "uk-ua", + en_gb = "en-gb", + en_us = "en-us", + es_us = "es-us", + es_ve = "es-ve", + en_vn = "en-vn", + vi_vn = "vi-vn", + cz_cz = "cz-cz", + ee_ee = "ee-ee", + gr_gr = "gr-gr", + ro_ro = "ro-ro", + en_ww = "en-ww" + + static func make(for locale: Locale) -> Self { + locale.local ?? locale.withCountry ?? locale.withRegion ?? .en_us + } +} + +private extension Locale { + var local: Local? { + Local(rawValue: identifier.lowercased()) + } + + var withCountry: Local? { + (self as NSLocale).countryCode.flatMap { code in + Local.allCases.first { $0.rawValue.hasSuffix(code.lowercased()) } + } + } + + var withRegion: Local? { + regionCode.flatMap { code in + Local.allCases.first { $0.rawValue.hasSuffix(code.lowercased()) } + } + } +} diff --git a/Ecosia/Core/Locale+Extensions.swift b/Ecosia/Core/Locale+Extensions.swift new file mode 100644 index 000000000000..ebbca3dcadd3 --- /dev/null +++ b/Ecosia/Core/Locale+Extensions.swift @@ -0,0 +1,22 @@ +import Foundation + +extension Locale { + + var identifierWithDashedLanguageAndRegion: String { + identifier.replacingOccurrences(of: "_", with: "-").lowercased() + } + + var regionIdentifier: String? { + if #available(iOS 16, macOS 13, *) { + return region?.identifier + } else { + return regionCode + } + } + + public var regionIdentifierLowercasedWithFallbackValue: String { + regionIdentifier?.lowercased() ?? "us" + } +} + +extension Locale: RegionLocatable {} diff --git a/Ecosia/MMP/MMP.swift b/Ecosia/Core/MMP/MMP.swift similarity index 90% rename from Ecosia/MMP/MMP.swift rename to Ecosia/Core/MMP/MMP.swift index cbf3a8440838..dd1c0a727966 100644 --- a/Ecosia/MMP/MMP.swift +++ b/Ecosia/Core/MMP/MMP.swift @@ -3,11 +3,17 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core -import Shared import AdServices import Common +public enum MMPEvent: String { + case onboardingStart = "onboarding_start" + case onboardingComplete = "onboarding_complete" + case firstSearch = "first_search" + case fifthSearch = "fifth_search" + case tenthSearch = "tenth_search" +} + public struct MMP { private init() {} diff --git a/Ecosia/Core/MMP/MMPProvider.swift b/Ecosia/Core/MMP/MMPProvider.swift new file mode 100644 index 000000000000..2c4e7c436b5d --- /dev/null +++ b/Ecosia/Core/MMP/MMPProvider.swift @@ -0,0 +1,8 @@ +import Foundation + +public protocol MMPProvider { + + func sendSessionInfo(appDeviceInfo: AppDeviceInfo) async throws + + func sendEvent(_ event: MMPEvent, appDeviceInfo: AppDeviceInfo) async throws +} diff --git a/Ecosia/Core/MMP/SKAdNetworkProtocol.swift b/Ecosia/Core/MMP/SKAdNetworkProtocol.swift new file mode 100644 index 000000000000..5c1278d405fb --- /dev/null +++ b/Ecosia/Core/MMP/SKAdNetworkProtocol.swift @@ -0,0 +1,35 @@ +import Foundation +import StoreKit.SKAdNetwork + +#if os(iOS) + +public protocol SKAdNetworkProtocol { + @available(iOS, introduced: 11.3, deprecated: 15.4) + static func registerAppForAdNetworkAttribution() + @available(iOS, introduced: 14.0, deprecated: 15.4) + static func updateConversionValue(_ conversionValue: Int) + @available(iOS 15.4, *) + static func updatePostbackConversionValue(_ conversionValue: Int) async throws + @available(iOS 16.1, *) + static func updatePostbackConversionValue(_ fineValue: Int, coarseValue: Int?, lockWindow: Bool) async throws +} + +extension SKAdNetwork: SKAdNetworkProtocol { + @available(iOS 16.1, *) + public static func updatePostbackConversionValue(_ fineValue: Int, coarseValue: Int?, lockWindow: Bool) async throws { + var coarseConversionValue: CoarseConversionValue? + switch coarseValue { + case 0: coarseConversionValue = .low + case 1: coarseConversionValue = .medium + case 2: coarseConversionValue = .high + default: break + } + if let value = coarseConversionValue { + try await updatePostbackConversionValue(fineValue, coarseValue: value, lockWindow: lockWindow) + } else { + try await updatePostbackConversionValue(fineValue) + } + } +} + +#endif diff --git a/Ecosia/Core/MMP/Singular/Service/SingularConversionValueRequest.swift b/Ecosia/Core/MMP/Singular/Service/SingularConversionValueRequest.swift new file mode 100644 index 000000000000..80049690f67e --- /dev/null +++ b/Ecosia/Core/MMP/Singular/Service/SingularConversionValueRequest.swift @@ -0,0 +1,49 @@ +import Foundation + +struct SingularConversionValueRequest: BaseRequest { + + struct Parameters: Encodable { + let identifier: String + let platform: String + let bundleId: String + let eventName: String + let osVersion: String + let appVersion: String + + enum CodingKeys: String, CodingKey { + case identifier = "sing" + case platform = "p" + case bundleId = "i" + case eventName = "n" + case osVersion = "ve" + case appVersion = "app_v" + } + + init(identifier: String, eventName: String, appDeviceInfo: AppDeviceInfo) { + self.identifier = identifier + self.platform = appDeviceInfo.platform + self.bundleId = appDeviceInfo.bundleId + self.eventName = eventName + self.osVersion = appDeviceInfo.osVersion + self.appVersion = appDeviceInfo.appVersion + } + } + + var method: HTTPMethod { + .get + } + + var path: String { + "/v2/attribution/conversion-value" + } + + var queryParameters: [String: String]? + + var additionalHeaders: [String: String]? + + var body: Data? + + init(_ parameters: Parameters, skanParameters: [String: String]) { + self.queryParameters = parameters.dictionary.merging(skanParameters) { current, _ in current } + } +} diff --git a/Ecosia/Core/MMP/Singular/Service/SingularConversionValueResponse.swift b/Ecosia/Core/MMP/Singular/Service/SingularConversionValueResponse.swift new file mode 100644 index 000000000000..589a43ae33d2 --- /dev/null +++ b/Ecosia/Core/MMP/Singular/Service/SingularConversionValueResponse.swift @@ -0,0 +1,17 @@ +import Foundation + +struct SingularConversionValueResponse: Codable, Equatable { + let conversionValue: Int + let coarseValue: Int? + let lockWindow: Bool? + + enum CodingKeys: String, CodingKey { + case conversionValue = "conversion_value" + case coarseValue = "skan_updated_coarse_value" + case lockWindow = "skan_updated_lock_window_value" + } + + var isValid: Bool { + (0...63 ~= conversionValue) && (0...2 ~= coarseValue ?? 1) + } +} diff --git a/Ecosia/Core/MMP/Singular/Service/SingularEventRequest.swift b/Ecosia/Core/MMP/Singular/Service/SingularEventRequest.swift new file mode 100644 index 000000000000..1f3b795585db --- /dev/null +++ b/Ecosia/Core/MMP/Singular/Service/SingularEventRequest.swift @@ -0,0 +1,46 @@ +import Foundation + +#if os(iOS) + +struct SingularEventRequest: BaseRequest { + + struct Parameters: Encodable { + let identifier: String + let name: String + let platform: String + let bundleId: String + let osVersion: String + + enum CodingKeys: String, CodingKey { + case identifier = "sing" + case name = "n" + case platform = "p" + case bundleId = "i" + case osVersion = "ve" + } + } + + var method: HTTPMethod { + .get + } + + var path: String { + "/v2/attribution/event" + } + + var queryParameters: [String: String]? + + var additionalHeaders: [String: String]? + + var body: Data? + + init(identifier: String, name: String, info: AppDeviceInfo) { + self.queryParameters = Parameters(identifier: identifier, + name: name, + platform: info.platform, + bundleId: info.bundleId, + osVersion: info.osVersion).dictionary + } +} + +#endif diff --git a/Ecosia/Core/MMP/Singular/Service/SingularReponse.swift b/Ecosia/Core/MMP/Singular/Service/SingularReponse.swift new file mode 100644 index 000000000000..68f3ff634764 --- /dev/null +++ b/Ecosia/Core/MMP/Singular/Service/SingularReponse.swift @@ -0,0 +1,15 @@ +import Foundation + +struct SingularResponse: Codable { + let status: String + let errorReason: String? + + enum CodingKeys: String, CodingKey { + case status + case errorReason = "reason" + } + + var isOK: Bool { + status == "ok" + } +} diff --git a/Ecosia/Core/MMP/Singular/Service/SingularService.swift b/Ecosia/Core/MMP/Singular/Service/SingularService.swift new file mode 100644 index 000000000000..00463e26743e --- /dev/null +++ b/Ecosia/Core/MMP/Singular/Service/SingularService.swift @@ -0,0 +1,60 @@ +import Foundation + +#if os(iOS) + +protocol SingularNotificationRequest: BaseRequest {} +extension SingularSessionInfoSendRequest: SingularNotificationRequest {} +extension SingularEventRequest: SingularNotificationRequest {} + +protocol SingularServiceProtocol { + func sendNotification(request: SingularNotificationRequest) async throws + func getConversionValue(request: SingularConversionValueRequest) async throws -> SingularConversionValueResponse +} + +final class SingularService: SingularServiceProtocol { + + enum Error: Swift.Error { + case network + case dataReturnedError(reason: String) + case noConversionValueReturned + } + + let client: HTTPClient + + init(client: HTTPClient = URLSessionHTTPClient()) { + self.client = client + } + + func sendNotification(request: SingularNotificationRequest) async throws { + let (data, response) = try await client.perform(request) + guard let response, response.statusCode == 200 else { + throw SingularService.Error.network + } + + let dataResult = try JSONDecoder().decode(SingularResponse.self, from: data) + + guard dataResult.isOK, dataResult.errorReason == nil else { + throw SingularService.Error.dataReturnedError(reason: dataResult.errorReason ?? "") + } + } + + func getConversionValue(request: SingularConversionValueRequest) async throws -> SingularConversionValueResponse { + let (data, response) = try await client.perform(request) + + guard let response, response.statusCode == 200 else { + throw SingularService.Error.network + } + + do { + return try JSONDecoder().decode(SingularConversionValueResponse.self, from: data) + } catch DecodingError.keyNotFound { + let fallbackResponse = try JSONDecoder().decode(SingularResponse.self, from: data) + if !fallbackResponse.isOK { + throw Error.dataReturnedError(reason: fallbackResponse.errorReason ?? "") + } + throw Error.noConversionValueReturned // Likely due to no conversion model active for the app + } + } +} + +#endif diff --git a/Ecosia/Core/MMP/Singular/Service/SingularSessionInfoSendRequest.swift b/Ecosia/Core/MMP/Singular/Service/SingularSessionInfoSendRequest.swift new file mode 100644 index 000000000000..c9bb9e5664d2 --- /dev/null +++ b/Ecosia/Core/MMP/Singular/Service/SingularSessionInfoSendRequest.swift @@ -0,0 +1,75 @@ +import Foundation + +#if os(iOS) + +struct SingularSessionInfoSendRequest: BaseRequest { + + struct Parameters: Encodable { + let identifier: String + let platform: String + let bundleId: String + let osVersion: String + let deviceManufacturer: String + let deviceModel: String + let locale: String + let country: String? + let deviceBuildVersion: String? + let appVersion: String + let installReceipt: String? + let attributionToken: String? + + enum CodingKeys: String, CodingKey { + case identifier = "sing" + case platform = "p" + case bundleId = "i" + case osVersion = "ve" + case deviceManufacturer = "ma" + case deviceModel = "mo" + case locale = "lc" + case country = "country" + case deviceBuildVersion = "bd" + case appVersion = "app_v" + case installReceipt = "install_receipt" + case attributionToken = "attribution_token" + } + } + + var method: HTTPMethod { + .get + } + + var path: String { + "/v2/attribution/launch" + } + + var queryParameters: [String: String]? + + var additionalHeaders: [String: String]? + + var body: Data? + + init(identifier: String, info: AppDeviceInfo, skanParameters: [String: String]?) { + var deviceBuildVersion: String? + if let deviceBuildVersionString = info.deviceBuildVersion { + deviceBuildVersion = #"Build\\#(deviceBuildVersionString)"# + } + var parameters = Parameters(identifier: identifier, + platform: info.platform, + bundleId: info.bundleId, + osVersion: info.osVersion, + deviceManufacturer: info.deviceManufacturer, + deviceModel: info.deviceModel, + locale: info.locale, + country: info.country, + deviceBuildVersion: deviceBuildVersion, + appVersion: info.appVersion, + installReceipt: info.installReceipt, + attributionToken: info.adServicesAttributionToken).dictionary + if let skanParameters = skanParameters { + parameters = parameters.merging(skanParameters) { (current, _) in current } + } + self.queryParameters = parameters + } +} + +#endif diff --git a/Ecosia/Core/MMP/Singular/Singular.swift b/Ecosia/Core/MMP/Singular/Singular.swift new file mode 100644 index 000000000000..5d2f79c7fe29 --- /dev/null +++ b/Ecosia/Core/MMP/Singular/Singular.swift @@ -0,0 +1,58 @@ +import Foundation + +#if os(iOS) + +public struct Singular: MMPProvider { + + let singularService: SingularServiceProtocol + let skanHelper: SingularAdNetworkHelperProtocol? + + init(singularService: SingularServiceProtocol = SingularService(), + skanHelper: SingularAdNetworkHelperProtocol? = SingularAdNetworkHelper()) { + self.singularService = singularService + self.skanHelper = skanHelper + } + + /// Initializer for Singular as MMPProvider. + /// - Parameters: + /// - includeSKAN: If true, all required logic for SKAdNetwork will be executed (e.g. register on first session or fetch updated conversion values from singular server before any event) + public init(includeSKAN: Bool) { + self.singularService = SingularService() + self.skanHelper = includeSKAN ? SingularAdNetworkHelper() : nil + } + + /// Reports a session to the Singular service. + /// - Parameters: + /// - appDeviceInfo: The device info parameters being set to Singular session endpoint. + public func sendSessionInfo(appDeviceInfo: AppDeviceInfo) async throws { + let sessionIdentifier = User.shared.analyticsId.uuidString + + var skanParameters: [String: String]? + if let skanHelper = skanHelper { + if skanHelper.isRegistered { + try? await skanHelper.fetchFromSingularServerAndUpdate(forEvent: .session, + sessionIdentifier: sessionIdentifier, + appDeviceInfo: appDeviceInfo) + } else { + try? await skanHelper.registerAppForAdNetworkAttribution() + } + + skanParameters = skanHelper.persistedValuesDictionary + } + + let request = SingularSessionInfoSendRequest(identifier: sessionIdentifier, info: appDeviceInfo, skanParameters: skanParameters) + try await singularService.sendNotification(request: request) + } + + /// Reports an event to the Singular service. + /// - Parameters: + /// - event: MMPEvent in question out of the supported cases + /// - appDeviceInfo: The device info parameters being set to Singular session endpoint. + public func sendEvent(_ event: MMPEvent, appDeviceInfo: AppDeviceInfo) async throws { + let sessionIdentifier = User.shared.analyticsId.uuidString + let request = SingularEventRequest(identifier: sessionIdentifier, name: event.rawValue, info: appDeviceInfo) + try await singularService.sendNotification(request: request) + } +} + +#endif diff --git a/Ecosia/Core/MMP/Singular/SingularAdNetworkHelper.swift b/Ecosia/Core/MMP/Singular/SingularAdNetworkHelper.swift new file mode 100644 index 000000000000..9612ed7bc69f --- /dev/null +++ b/Ecosia/Core/MMP/Singular/SingularAdNetworkHelper.swift @@ -0,0 +1,193 @@ +import Foundation +import StoreKit.SKAdNetwork + +#if os(iOS) + +protocol SingularAdNetworkHelperProtocol { + var persistedValuesDictionary: [String: String] { get } + var isRegistered: Bool { get } + + func registerAppForAdNetworkAttribution() async throws + func fetchFromSingularServerAndUpdate(forEvent event: SingularEvent, sessionIdentifier: String, appDeviceInfo: AppDeviceInfo) async throws +} + +struct SingularAdNetworkHelper: SingularAdNetworkHelperProtocol { + + enum PersistedObject: Hashable, CaseIterable { + static var allCases: [SingularAdNetworkHelper.PersistedObject] { + return [ + .firstSkanCallTimestamp, .lastSkanCallTimestamp, .conversionValue, .previousFineValue, + .coarseValue(window: .first), .coarseValue(window: .second), .coarseValue(window: .third), + .previousCoarseValue(window: .first), .previousCoarseValue(window: .second), .previousCoarseValue(window: .third), + .windowLockTimestamp(window: .first), .windowLockTimestamp(window: .second), .windowLockTimestamp(window: .third), + .errorCode + ] + } + + case firstSkanCallTimestamp + case lastSkanCallTimestamp + case conversionValue + case coarseValue(window: SkanWindow) + case previousFineValue // Only expected to exist for first window + case previousCoarseValue(window: SkanWindow) + case windowLockTimestamp(window: SkanWindow) + case errorCode + + var key: String { + switch self { + case .firstSkanCallTimestamp: return "first_skan_call_timestamp" + case .lastSkanCallTimestamp: return "last_skan_call_timestamp" + case .conversionValue: return "current_conversion_value" + case .coarseValue(let window): return "\(window.rawValue)_coarse_value" + case .previousFineValue: return "prev_fine_value" + case .previousCoarseValue(let window): return "\(window.rawValue)_prev_coarse_value" + case .windowLockTimestamp(let window): return "\(window.rawValue)_window_lock_timestamp" + case .errorCode: return "skan_error_code" + } + } + + var queryKey: String { + switch self { + case .firstSkanCallTimestamp: return "skan_first_call_to_skadnetwork_timestamp" + case .lastSkanCallTimestamp: return "skan_last_call_to_skadnetwork_timestamp" + case .conversionValue: return "skan_current_conversion_value" + case .coarseValue(let window): return "\(window.rawValue)_coarse" + case .previousFineValue: return "prev_fine_value" + case .previousCoarseValue(let window): return "\(window.rawValue)_prev_coarse_value" + case .windowLockTimestamp(let window): return "\(window.rawValue)_window_lock" + case .errorCode: return "_skerror" + } + } + } + + enum SkanWindow: String { + case first = "p0" + case second = "p1" + case third = "p2" + case over + + static let firstSkanWindowInSec = 3600 * 24 * 2 + static let secondSkanWindowInSec = 3600 * 24 * 7 + static let thirdSkanWindowInSec = 3600 * 24 * 35 + + init(timeDiff: Int) { + switch timeDiff { + case 0...SkanWindow.firstSkanWindowInSec: self = .first + case SkanWindow.firstSkanWindowInSec...SkanWindow.secondSkanWindowInSec: self = .second + case SkanWindow.secondSkanWindowInSec...SkanWindow.thirdSkanWindowInSec: self = .third + default: self = .over + } + } + } + + enum Error: Swift.Error { + case invalidConversionValues + } + + private var currentTimestamp: Int { + return Int(timestampProvider.currentTimestamp) + } + var persistedValuesDictionary: [String: String] { + var dictionary = [String: String]() + PersistedObject.allCases.forEach { obj in + if let value = getUserDefaultsInteger(for: obj) { + dictionary[obj.queryKey] = String(value) + } + } + return dictionary + } + var isRegistered: Bool { + return getUserDefaultsInteger(for: .firstSkanCallTimestamp) != nil + } + + private let skan: SKAdNetworkProtocol.Type + private let objectPersister: ObjectPersister + private let timestampProvider: TimestampProvider + private let singularService: SingularServiceProtocol + + init(skan: SKAdNetworkProtocol.Type = SKAdNetwork.self, + objectPersister: ObjectPersister = UserDefaults.standard, + timestampProvider: TimestampProvider = Date(), + singularService: SingularServiceProtocol = SingularService()) { + self.skan = skan + self.objectPersister = objectPersister + self.timestampProvider = timestampProvider + self.singularService = singularService + } + + func registerAppForAdNetworkAttribution() async throws { + guard !isRegistered else { return } + + if #available(iOS 15.4, *) { + do { + try await skan.updatePostbackConversionValue(0) + } catch { + setUserDefaults(for: .errorCode, value: (error as NSError).code) + } + } else { + skan.registerAppForAdNetworkAttribution() + } + setUserDefaults(for: .firstSkanCallTimestamp, value: currentTimestamp) + setUserDefaults(for: .lastSkanCallTimestamp, value: currentTimestamp) + persistUpdatedValues(fineValue: 0, coarseValue: nil) + } + + func fetchFromSingularServerAndUpdate(forEvent event: SingularEvent = .session, sessionIdentifier: String, appDeviceInfo: AppDeviceInfo) async throws { + let firstCallTimestamp = getUserDefaultsInteger(for: .firstSkanCallTimestamp) ?? 0 + guard SkanWindow(timeDiff: currentTimestamp - firstCallTimestamp) != .over else { + return + } + + let request = SingularConversionValueRequest(.init(identifier: sessionIdentifier, eventName: event.rawValue, appDeviceInfo: appDeviceInfo), + skanParameters: persistedValuesDictionary) + let response = try await singularService.getConversionValue(request: request) + if !response.isValid { + throw Error.invalidConversionValues + } + + let conversionValue = response.conversionValue + let coarseValue = response.coarseValue + let lockWindow = response.lockWindow ?? false + if #available(iOS 16.1, *) { + try? await skan.updatePostbackConversionValue(conversionValue, coarseValue: coarseValue, lockWindow: lockWindow) + } else if #available(iOS 15.4, *) { + try? await skan.updatePostbackConversionValue(conversionValue) + } else if #available(iOS 14, *) { + skan.updateConversionValue(conversionValue) + } + persistUpdatedValues(fineValue: conversionValue, + coarseValue: coarseValue, + lockWindow: lockWindow) + } + + private func persistUpdatedValues(fineValue: Int, coarseValue: Int?, lockWindow: Bool = false) { + let window = SkanWindow(timeDiff: currentTimestamp - (getUserDefaultsInteger(for: .firstSkanCallTimestamp) ?? 0)) + guard window != .over else { return } + + if window == .first { + let persistedFineValue: Int? = getUserDefaultsInteger(for: .conversionValue) + setUserDefaults(for: .conversionValue, value: fineValue) + setUserDefaults(for: .previousFineValue, value: persistedFineValue) + } + + let persistedCoarseValue: Int? = getUserDefaultsInteger(for: .coarseValue(window: window)) + setUserDefaults(for: .coarseValue(window: window), value: coarseValue) + setUserDefaults(for: .previousCoarseValue(window: window), value: persistedCoarseValue) + + if lockWindow { + setUserDefaults(for: .windowLockTimestamp(window: window), value: currentTimestamp) + } + + setUserDefaults(for: .lastSkanCallTimestamp, value: currentTimestamp) + } + + private func setUserDefaults(for object: PersistedObject, value: Int?) { + objectPersister.set(value, forKey: object.key) + } + + private func getUserDefaultsInteger(for object: PersistedObject) -> Int? { + return objectPersister.object(forKey: object.key) as? Int + } +} + +#endif diff --git a/Ecosia/Core/MMP/Singular/SingularEvent.swift b/Ecosia/Core/MMP/Singular/SingularEvent.swift new file mode 100644 index 000000000000..7394b702dd0d --- /dev/null +++ b/Ecosia/Core/MMP/Singular/SingularEvent.swift @@ -0,0 +1,5 @@ +import Foundation + +enum SingularEvent: String { + case session = "__SESSION__" +} diff --git a/Ecosia/Core/Market.swift b/Ecosia/Core/Market.swift new file mode 100644 index 000000000000..8501386bbc9f --- /dev/null +++ b/Ecosia/Core/Market.swift @@ -0,0 +1,24 @@ +import Foundation + +// Reference: https://github.com/ecosia/core/blob/main/common/js/universal/markets.js + +public struct Market: Decodable { + public let value: Local + public let label: String + public let languageInLabel: Bool + + public init(from decoder: Decoder) throws { + let root = try decoder.container(keyedBy: CodingKeys.self) + value = try root.decode(Local.self, forKey: .value) + label = try root.decode(String.self, forKey: .label) + if let stringValue = try? root.decode(String.self, forKey: .languageInLabel) { + languageInLabel = Bool(stringValue) ?? false + } else { + languageInLabel = false + } + } + + private enum CodingKeys: String, CodingKey { + case value, label, languageInLabel + } +} diff --git a/Ecosia/Core/News/News.swift b/Ecosia/Core/News/News.swift new file mode 100644 index 000000000000..b9599e0f9891 --- /dev/null +++ b/Ecosia/Core/News/News.swift @@ -0,0 +1,79 @@ +import Foundation + +public final class News: StatePublisher { + public var subscriptions = [Subscription<[NewsModel]>]() + public var state: [NewsModel]? { + items.sorted { $0.publishDate > $1.publishDate } + } + private let dispatch = DispatchQueue(label: "", qos: .utility) + private let characters = ["'": "'"] + + private var decoder: JSONDecoder { + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + decoder.dateDecodingStrategy = .iso8601 + return decoder + } + + private(set) var items = Set() { + didSet { + DispatchQueue.main.async { [weak self ] in + self?.state.map { self?.send($0) } + } + } + } + + public init() { + dispatch.async { [weak self] in + self?.restore() + } + } + + var needsUpdate: Bool { + guard !items.isEmpty else { return true } + return Calendar.current.dateComponents([.day], from: User.shared.news, to: .init()).day! >= 1 + } + + public func load(session: URLSession, force: Bool = false) { + guard needsUpdate || force else { return } + session.dataTask(with: Environment.current.urlProvider.notifications) { [weak self] data, _, _ in + self?.dispatch.async { + guard + let data = data, + let new = try? self?.decoder.decode([NewsModel].self, from: data) + else { + return + } + let cleaned = new.compactMap { self?.clean($0) } + self?.items = .init(cleaned + (self?.items ?? [])) + self?.save() + } + }.resume() + } + + private func restore() { + dispatch.async { [weak self] in + if let news = try? JSONDecoder().decode([NewsModel].self, from: .init(contentsOf: FileManager.news)) { + self?.items = .init(news.filter { $0.language == Language.current }) + } + } + } + + private func save() { + dispatch.async { [weak self] in + guard let items = self?.items, !items.isEmpty else { return } + if let _ = try? JSONEncoder().encode(items).write(to: FileManager.news, options: .atomic) { + User.shared.news = Date() + } + } + } + + private func clean(_ item: NewsModel) -> NewsModel { + var item = item + item.text = item.text.replacingOccurrences(of: "<[^>]+>", with: "", options: .regularExpression) + item.text = characters.reduce(item.text) { text, char in + text.replacingOccurrences(of: char.0, with: char.1) + } + return item + } +} diff --git a/Ecosia/Core/News/NewsModel.swift b/Ecosia/Core/News/NewsModel.swift new file mode 100644 index 000000000000..117d8c08f528 --- /dev/null +++ b/Ecosia/Core/News/NewsModel.swift @@ -0,0 +1,19 @@ +import Foundation + +public struct NewsModel: Codable, Hashable { + let id: Int + public internal(set) var text: String + public let language: Language + public let publishDate: Date + public let imageUrl: URL + public let targetUrl: URL + public let trackingName: String + + public func hash(into: inout Hasher) { + into.combine(id) + } + + public static func == (lhs: Self, rhs: Self) -> Bool { + lhs.id == rhs.id + } +} diff --git a/Ecosia/Core/ObjectPersister.swift b/Ecosia/Core/ObjectPersister.swift new file mode 100644 index 000000000000..de69d03f6dc7 --- /dev/null +++ b/Ecosia/Core/ObjectPersister.swift @@ -0,0 +1,6 @@ +import Foundation + +protocol ObjectPersister { + func set(_ value: Any?, forKey: String) + func object(forKey: String) -> Any? +} diff --git a/Ecosia/Core/Pages/Page.swift b/Ecosia/Core/Pages/Page.swift new file mode 100644 index 000000000000..20de74de2e16 --- /dev/null +++ b/Ecosia/Core/Pages/Page.swift @@ -0,0 +1,11 @@ +import Foundation + +public struct Page: Codable { + public let url: URL + public let title: String + + public init(url: URL, title: String) { + self.url = url + self.title = title + } +} diff --git a/Ecosia/Core/Pages/PageStore.swift b/Ecosia/Core/Pages/PageStore.swift new file mode 100644 index 000000000000..e83ab7e5f2d9 --- /dev/null +++ b/Ecosia/Core/Pages/PageStore.swift @@ -0,0 +1,60 @@ +import Foundation + +struct PageStore { + static let queue = DispatchQueue(label: "", qos: .utility) + + private init() { } + + static func save(tabs: [Tab]) { + queue.async { + createDirectory() + try? JSONEncoder().encode(tabs).write(to: FileManager.tabs, options: .atomic) + } + } + + static func save(currentTab: Int?) { + queue.async { + if let currentTab = currentTab { + createDirectory() + try? JSONEncoder().encode(currentTab).write(to: FileManager.currentTab, options: .atomic) + } else if FileManager.default.fileExists(atPath: FileManager.currentTab.path) { + try? FileManager.default.removeItem(at: FileManager.currentTab) + } + } + } + + static func save(favourites: [Page]) { + queue.async { + createDirectory() + try? JSONEncoder().encode(favourites).write(to: FileManager.favourites, options: .atomic) + } + } + + static func save(history: [Date: Page]) { + queue.async { + createDirectory() + try? JSONEncoder().encode(history).write(to: FileManager.history, options: .atomic) + } + } + + static var tabs: [Tab] { + (try? JSONDecoder().decode([Tab].self, from: .init(contentsOf: FileManager.tabs))) ?? [] + } + + static var currentTab: Int? { + try? JSONDecoder().decode(Int.self, from: .init(contentsOf: FileManager.currentTab)) + } + + static var favourites: [Page] { + (try? JSONDecoder().decode([Page].self, from: .init(contentsOf: FileManager.favourites))) ?? [] + } + + static var history: [Date: Page] { + (try? JSONDecoder().decode([Date: Page].self, from: .init(contentsOf: FileManager.history))) ?? [:] + } + + private static func createDirectory() { + guard !FileManager.default.fileExists(atPath: FileManager.pages.path) else { return } + try? FileManager.default.createDirectory(at: FileManager.pages, withIntermediateDirectories: true) + } +} diff --git a/Ecosia/Core/Publisher.swift b/Ecosia/Core/Publisher.swift new file mode 100644 index 000000000000..96106a7d46ab --- /dev/null +++ b/Ecosia/Core/Publisher.swift @@ -0,0 +1,38 @@ +import Foundation + +public protocol Publisher: AnyObject { + associatedtype Input + var subscriptions: [Subscription] { get set } +} + +public extension Publisher { + func send(_ input: Input) { + subscriptions.removeAll { $0.subscriber == nil } + subscriptions.forEach { $0.closure(input) } + } + + func subscribe(_ subscriber: AnyObject, closure: @escaping (Input) -> Void) { + guard !subscriptions.contains(where: { $0.subscriber === subscriber }) else { return } + subscriptions.append(.init(subscriber: subscriber, closure: closure)) + } + + func unsubscribe(_ subscriber: AnyObject) { + subscriptions.removeAll { $0.subscriber === subscriber } + } +} + +public struct Subscription { + weak var subscriber: AnyObject? + let closure: (Input) -> Void +} + +public protocol StatePublisher: Publisher { + var state: Input? { get } +} + +public extension StatePublisher { + func subscribeAndReceive(_ subscriber: AnyObject, closure: @escaping (Input) -> Void) { + subscribe(subscriber, closure: closure) + state.map(closure) + } +} diff --git a/Ecosia/Core/Referrals/ReferralClaimRequest.swift b/Ecosia/Core/Referrals/ReferralClaimRequest.swift new file mode 100644 index 000000000000..82035736eae4 --- /dev/null +++ b/Ecosia/Core/Referrals/ReferralClaimRequest.swift @@ -0,0 +1,28 @@ +import Foundation + +struct ReferralClaimRequest: BaseRequest { + struct Claim: Codable { + let referrer: String + let claim: String + + private enum CodingKeys: String, CodingKey { + case + referrer = "referral_code", + claim = "claim_code" + } + } + + var method: HTTPMethod { .post } + + var path: String { "/v1/referrals/claim/" } + + var queryParameters: [String: String]? + + var additionalHeaders: [String: String]? + + var body: Data? + + init(referrer: String, claim: String) { + self.body = try? JSONEncoder().encode(Claim(referrer: referrer, claim: claim)) + } +} diff --git a/Ecosia/Core/Referrals/ReferralCreateCodeRequest.swift b/Ecosia/Core/Referrals/ReferralCreateCodeRequest.swift new file mode 100644 index 000000000000..dd789e7ab017 --- /dev/null +++ b/Ecosia/Core/Referrals/ReferralCreateCodeRequest.swift @@ -0,0 +1,13 @@ +import Foundation + +struct ReferralCreateCodeRequest: BaseRequest { + var method: HTTPMethod { .post } + + var path: String { "/v1/referrals/referral/" } + + var queryParameters: [String: String]? + + var additionalHeaders: [String: String]? + + var body: Data? +} diff --git a/Ecosia/Core/Referrals/ReferralRefreshCodeRequest.swift b/Ecosia/Core/Referrals/ReferralRefreshCodeRequest.swift new file mode 100644 index 000000000000..2c74c4b7451c --- /dev/null +++ b/Ecosia/Core/Referrals/ReferralRefreshCodeRequest.swift @@ -0,0 +1,18 @@ +import Foundation + +struct ReferralRefreshCodeRequest: BaseRequest { + var method: HTTPMethod { .get } + + var path: String { "/v1/referrals/referral/\(code)" } + + var queryParameters: [String: String]? + + var additionalHeaders: [String: String]? + + var body: Data? + + let code: String + init(code: String) { + self.code = code + } +} diff --git a/Ecosia/Core/Referrals/Referrals.Model.swift b/Ecosia/Core/Referrals/Referrals.Model.swift new file mode 100644 index 000000000000..7710f28b1663 --- /dev/null +++ b/Ecosia/Core/Referrals/Referrals.Model.swift @@ -0,0 +1,58 @@ +import Foundation + +extension Referrals { + public enum Error: Int, Swift.Error { + case noConnection = -1 + case badRequest = 400 + case notFound = 404 + case alreadyUsed = 409 + case invalidCode = 422 + case genericError = 500 + } + + public struct Model: Codable, Equatable { + public static let treesPerReferred = 1 + public var code: String? + public var claims = 0 + public var isClaimed = false + public var isNewClaim = false + public var pendingClaim: String? + var updated: Date = .distantPast + var knownClaims = 0 + + public var newClaims: Int { + return claims - knownClaims + } + + public var count: Int { + return claims + (isClaimed ? 1 : 0) + } + + public mutating func accept() { + knownClaims = claims + isNewClaim = false + } + } + + struct CodeInfo: Codable { + let code: String + let claims: Int + + public init(from decoder: Decoder) throws { + let root = try decoder.container(keyedBy: CodingKeys.self) + code = try root.decode(String.self, forKey: .code) + claims = (try? root.decode(Int.self, forKey: .claims)) ?? 0 + } + + public init(code: String, claims: Int) { + self.code = code + self.claims = claims + } + + private enum CodingKeys: String, CodingKey { + case + code, + claims = "claims_count" + } + } +} diff --git a/Ecosia/Core/Referrals/Referrals.swift b/Ecosia/Core/Referrals/Referrals.swift new file mode 100644 index 000000000000..2410182d8b5e --- /dev/null +++ b/Ecosia/Core/Referrals/Referrals.swift @@ -0,0 +1,178 @@ +import Foundation + +/// The `Referrals` class is responsible for handling referral-related operations, +/// including refreshing referral codes, creating new codes, and claiming referrals. +public class Referrals: Publisher { + + /// Subscriptions to the referral model updates. + public var subscriptions = [Subscription]() + + /// Deeplink to enter the Referral's claim + public static let deepLinkPath = "ecosia://invite/" + + /// Link shown in the Modal screen as well as the invite message + public static let sharingLinkRoot = "https://ecosia.co/app?referrer=" + + /// The HTTP client used for performing network requests. + let client: HTTPClient + + /// Initializes a new instance of `Referrals` with the specified HTTP client. + /// - Parameter client: The HTTP client to use. Defaults to `URLSessionHTTPClient`. + public init(client: HTTPClient = URLSessionHTTPClient()) { + self.client = client + } + + /// Indicates whether the referral information needs to be updated. + var needsUpdate: Bool { + return Calendar.current.dateComponents([.hour], from: User.shared.referrals.updated, to: .init()).hour! >= 24 + } + + /// Indicates whether the referral information is currently being refreshed. + var isRefreshing = false + + /// Refreshes the referral information. + /// - Parameters: + /// - force: A Boolean value indicating whether to force a refresh. Defaults to `false`. + /// - createCode: A Boolean value indicating whether to create a new code if one does not exist. Defaults to `false`. + /// - Throws: An error if the refresh operation fails. + public func refresh(force: Bool = false, createCode: Bool = false) async throws { + // Check if code is present + guard let code = User.shared.referrals.code else { + // only fetch new code if desired + guard createCode else { + return + } + + let info = try await self.fetchCode() + await self.update(info) + return + } + + // only refresh if forced or needed + guard force || needsUpdate else { + return + } + + guard !isRefreshing else { + return + } + isRefreshing = true + defer { + self.isRefreshing = false + } + + // Refresh count for given code + do { + let info = try await self.refreshCode(code) + await self.update(info) + } catch { + await self.updateErrorDate() + throw error + } + } + + /// Creates a new referral code. + /// - Returns: The created referral code information. + /// - Throws: An error if the creation operation fails. + func createCode() async throws -> CodeInfo { + let request = ReferralCreateCodeRequest() + let (data, response) = try await client.perform(request) + guard response != nil else { + throw Referrals.Error.noConnection + } + return try JSONDecoder().decode(CodeInfo.self, from: data) + } + + /// Fetches the referral code information. + /// - Returns: The fetched referral code information. + /// - Throws: An error if the fetch operation fails. + func fetchCode() async throws -> CodeInfo { + // pretend success if we have a code already + if let code = User.shared.referrals.code { + return .init(code: code, claims: User.shared.referrals.claims) + } + return try await createCode() + } + + /// Refreshes the referral code information. + /// - Parameter code: The referral code to refresh. + /// - Returns: The refreshed referral code information. + /// - Throws: An error if the refresh operation fails. + func refreshCode(_ code: String) async throws -> CodeInfo { + let request = ReferralRefreshCodeRequest(code: code) + let (data, response) = try await client.perform(request) + guard let response = response else { + throw Referrals.Error.noConnection + } + switch response.statusCode { + case Referrals.Error.notFound.rawValue: + return try await createCode() + case 200: + return try JSONDecoder().decode(CodeInfo.self, from: data) + default: + let error: Referrals.Error? = .init(rawValue: response.statusCode) + throw error ?? .genericError + } + } + + /// Claims a referral using the specified referrer. + /// - Parameter referrer: The referrer identifier. + /// - Throws: An error if the claim operation fails. + public func claim(referrer: String) async throws { + var code: String + if let storedCode = User.shared.referrals.code { + code = storedCode + } else { + let info = try await self.fetchCode() + await self.update(info) + code = info.code + } + try await self.claim(referrer: referrer, claim: code) + await self.storeClaim() + } + + /// Claims a referral using the specified referrer and claim code. + /// - Parameters: + /// - referrer: The referrer identifier. + /// - claim: The claim code. + /// - Throws: An error if the claim operation fails. + private func claim(referrer: String, claim: String) async throws { + let request = ReferralClaimRequest(referrer: referrer, claim: claim) + let (_, response) = try await client.perform(request) + guard let response = response else { + throw Referrals.Error.noConnection + } + guard response.statusCode == 201 else { + let error: Referrals.Error? = .init(rawValue: response.statusCode) + throw error ?? .genericError + } + } + + /// Updates the date on error to refresh the cooldown period. + @MainActor + private func updateErrorDate() { + User.shared.referrals.updated = Date() + } + + /// Updates the referral information. + /// - Parameter info: The referral code information to update. + @MainActor + private func update(_ info: CodeInfo) { + var referrals = User.shared.referrals + referrals.code = info.code + referrals.claims = info.claims + referrals.updated = Date() + User.shared.referrals = referrals + send(referrals) + } + + /// Stores the claim information and updates the referral state. + @MainActor + private func storeClaim() { + var referrals = User.shared.referrals + referrals.isClaimed = true + referrals.isNewClaim = true + User.shared.referrals = referrals + send(referrals) + } +} diff --git a/Ecosia/Core/RegionLocatable.swift b/Ecosia/Core/RegionLocatable.swift new file mode 100644 index 000000000000..c37f7b9e3211 --- /dev/null +++ b/Ecosia/Core/RegionLocatable.swift @@ -0,0 +1,5 @@ +/// Utilized mainly for the Unleash refresh logic and accommodate testability +/// see: `DeviceRegionChangeProvider.swift` +public protocol RegionLocatable { + var regionIdentifierLowercasedWithFallbackValue: String { get } +} diff --git a/Ecosia/Core/Scheme.swift b/Ecosia/Core/Scheme.swift new file mode 100644 index 000000000000..e54620246779 --- /dev/null +++ b/Ecosia/Core/Scheme.swift @@ -0,0 +1,33 @@ +import Foundation + +public enum Scheme: String { + case + http, + https, + gmsg, + other + + public enum Policy { + case + allow, + cancel + } + + var policy: Policy { + switch self { + case .gmsg: + return .cancel + default: + return .allow + } + } + + var isBrowser: Bool { + switch self { + case .http, .https: + return true + default: + return false + } + } +} diff --git a/Ecosia/Core/SearchesCounter.swift b/Ecosia/Core/SearchesCounter.swift new file mode 100644 index 000000000000..bb2dff622f0c --- /dev/null +++ b/Ecosia/Core/SearchesCounter.swift @@ -0,0 +1,16 @@ +import Foundation + +public final class SearchesCounter: StatePublisher { + public var subscriptions = [Subscription]() + public var state: Int? { + return User.shared.searchCount + } + + public init() { + NotificationCenter.default.addObserver(self, selector: #selector(searchesCounterChanged), name: .searchesCounterChanged, object: nil) + } + + @objc private func searchesCounterChanged() { + send(state!) + } +} diff --git a/Ecosia/Core/Statistics/FinancialReports.swift b/Ecosia/Core/Statistics/FinancialReports.swift new file mode 100644 index 000000000000..60663a20901a --- /dev/null +++ b/Ecosia/Core/Statistics/FinancialReports.swift @@ -0,0 +1,42 @@ +import Foundation + +public final class FinancialReports { + public struct Report: Decodable, Equatable { + public internal(set) var totalIncome: Double + public internal(set) var numberOfTreesFinanced: Double + } + + public static let shared = FinancialReports() + public internal(set) var latestMonth: Date = .init(timeIntervalSince1970: 1685577600) + public internal(set) var latestReport: Report = .init(totalIncome: 3206010, + numberOfTreesFinanced: 961642) + + public var localizedMonthAndYear: String { + let formatter = DateFormatter() + formatter.dateFormat = "MMMM yyyy" + formatter.locale = Locale.current + formatter.timeZone = TimeZone(abbreviation: "GMT") + + let localizedMonth = formatter.string(from: latestMonth) + return localizedMonth + } + + init() { } + + public func fetchAndUpdate(urlSession: URLSessionProtocol = URLSession.shared) async throws { + let (data, _) = try await urlSession.data(from: Environment.current.urlProvider.financialReportsData) + + let response = try JSONSerialization.jsonObject(with: data) as? [String: Any] + + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-M" + dateFormatter.timeZone = .init(abbreviation: "UTC") + let months = response?.keys.compactMap { dateFormatter.date(from: $0) } ?? [] + let latestMonth = months.reduce(Date.distantPast) { $0 > $1 ? $0 : $1 } + let latestKey = dateFormatter.string(from: latestMonth) + let latestObject = response?[latestKey] as? [String: Any] ?? [:] + + self.latestMonth = latestMonth + self.latestReport = try JSONDecoder().decode(Report.self, from: JSONSerialization.data(withJSONObject: latestObject)) + } +} diff --git a/Ecosia/Core/Statistics/InvestmentsProjection.swift b/Ecosia/Core/Statistics/InvestmentsProjection.swift new file mode 100644 index 000000000000..4e9b375df2d2 --- /dev/null +++ b/Ecosia/Core/Statistics/InvestmentsProjection.swift @@ -0,0 +1,23 @@ +import Foundation + +public final class InvestmentsProjection: Publisher { + public static let shared = InvestmentsProjection() + public var subscriptions = [Subscription]() + let timer = DispatchSource.makeTimerSource(queue: .main) + + init() { + timer.activate() + timer.setEventHandler { [weak self] in + guard let count = self?.totalInvestedAt(Date()) else { return } + self?.send(count) + } + let secondsToOneEuro = max(1/Statistics.shared.investmentPerSecond, 1) + timer.schedule(deadline: .now(), repeating: secondsToOneEuro) + } + + public func totalInvestedAt(_ date: Date) -> Int { + let statistics = Statistics.shared + let deltaTimeInSeconds = date.timeIntervalSince(statistics.totalInvestmentsLastUpdated) + return .init(deltaTimeInSeconds * statistics.investmentPerSecond + statistics.totalInvestments) + } +} diff --git a/Ecosia/Core/Statistics/Statistics.swift b/Ecosia/Core/Statistics/Statistics.swift new file mode 100644 index 000000000000..ee712ae94066 --- /dev/null +++ b/Ecosia/Core/Statistics/Statistics.swift @@ -0,0 +1,75 @@ +import Foundation + +public final class Statistics { + public struct Response: Decodable { + var results: [Result] + } + public struct Result: Decodable { + var name: String + var value: String + var lastUpdated: String? + + enum StatisticName: String, Decodable { + case treesPlanted = "Total Trees Planted" + case timePerTree = "Time per tree (seconds)" + case searchesPerTree = "Searches per tree" + case activeUsers = "Active Users" + case eurToUsdMultiplier = "EUR=>USD" + case investmentPerSecond = "Investments amount per second" + case totalInvestments = "Total investments amount" + } + + func statisticName() -> StatisticName? { StatisticName(rawValue: name) } + + func doubleValue() -> Double? { Double(value) } + + func lastUpdatedDate() -> Date? { + guard let dateString = lastUpdated else { return nil } + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] + return formatter.date(from: dateString) + } + } + + public static let shared = Statistics() + public internal(set) var treesPlanted = Double(113016418) + public internal(set) var treesPlantedLastUpdated = Date(timeIntervalSince1970: 1604671200) + public internal(set) var timePerTree = Double(1.3) + public internal(set) var searchesPerTree = Double(50) + public internal(set) var activeUsers = Double(20000000) + public internal(set) var eurToUsdMultiplier = Double(1.08) + public internal(set) var investmentPerSecond = Double(0.35) + public internal(set) var totalInvestments = Double(76776000) + public internal(set) var totalInvestmentsLastUpdated = Date(timeIntervalSince1970: 1685404800) + + init() { } + + public func fetchAndUpdate(urlSession: URLSessionProtocol = URLSession.shared) async throws { + let (data, _) = try await urlSession.data(from: Environment.current.urlProvider.statistics) + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + let response = try decoder.decode(Response.self, from: data) + response.results.forEach { statistic in + switch statistic.statisticName() { + case .treesPlanted: + if let value = statistic.doubleValue(), + let date = statistic.lastUpdatedDate() { + treesPlanted = value + treesPlantedLastUpdated = date + } + case .timePerTree: timePerTree = statistic.doubleValue() ?? timePerTree + case .searchesPerTree: searchesPerTree = statistic.doubleValue() ?? searchesPerTree + case .activeUsers: activeUsers = statistic.doubleValue() ?? activeUsers + case .eurToUsdMultiplier: eurToUsdMultiplier = statistic.doubleValue() ?? eurToUsdMultiplier + case .investmentPerSecond: investmentPerSecond = statistic.doubleValue() ?? investmentPerSecond + case .totalInvestments: + if let value = statistic.doubleValue(), + let date = statistic.lastUpdatedDate() { + totalInvestments = value + totalInvestmentsLastUpdated = date + } + case nil: break + } + } + } +} diff --git a/Ecosia/Core/Statistics/TreesProjection.swift b/Ecosia/Core/Statistics/TreesProjection.swift new file mode 100644 index 000000000000..b8d39b4089ef --- /dev/null +++ b/Ecosia/Core/Statistics/TreesProjection.swift @@ -0,0 +1,22 @@ +import Foundation + +public final class TreesProjection: Publisher { + public static let shared = TreesProjection() + public var subscriptions = [Subscription]() + let timer = DispatchSource.makeTimerSource(queue: .main) + + init() { + timer.activate() + timer.setEventHandler { [weak self] in + guard let count = self?.treesAt(Date()) else { return } + self?.send(count) + } + timer.schedule(deadline: .now(), repeating: Statistics.shared.timePerTree) + } + + public func treesAt(_ date: Date) -> Int { + let statistics = Statistics.shared + let timeSinceLastUpdate = date.timeIntervalSince(statistics.treesPlantedLastUpdated) + return .init(timeSinceLastUpdate / statistics.timePerTree + statistics.treesPlanted - 1) + } +} diff --git a/Ecosia/Core/Tabs/Tab.swift b/Ecosia/Core/Tabs/Tab.swift new file mode 100644 index 000000000000..e206b30abcac --- /dev/null +++ b/Ecosia/Core/Tabs/Tab.swift @@ -0,0 +1,17 @@ +import Foundation + +public struct Tab: Codable, Identifiable { + public var page: Page? + public let id: UUID + + public init(page: Page?) { + self.page = page + id = .init() + } +} + +public extension Tab { + var snapshot: Data? { + return try? Data(contentsOf: FileManager.snapshots.appendingPathComponent(id.uuidString)) + } +} diff --git a/Ecosia/Core/Tabs/Tabs.swift b/Ecosia/Core/Tabs/Tabs.swift new file mode 100644 index 000000000000..926683c70d12 --- /dev/null +++ b/Ecosia/Core/Tabs/Tabs.swift @@ -0,0 +1,96 @@ +import Foundation + +public final class Tabs { + public var current: Int? { + didSet { + PageStore.save(currentTab: current) + } + } + + public private(set) var items = [Tab]() { + didSet { + PageStore.save(tabs: items) + } + } + + let queue = DispatchQueue(label: "", qos: .utility) + + public init() { + items = PageStore.tabs + if let current = PageStore.currentTab { + self.current = current < items.count ? current : nil + } + } + + public func new(_ url: URL?) { + var items = self.items + items.removeAll { $0.page == nil } + let new = Tab(page: url.map { .init(url: $0, title: "") }) + current = items.count + items.append(new) + self.items = items + } + + public func close(_ id: UUID) { + guard let index = items.firstIndex(where: { $0.id == id }) else { return } + if current != nil { + if current == index { + current = nil + } else if index < current! { + current = current! - 1 + } + } + deleteSnapshot(items[index].id) + items.remove(at: index) + } + + public func clear() { + items = [] + current = nil + queue.async { + if FileManager.default.fileExists(atPath: FileManager.snapshots.path) { + try? FileManager.default.removeItem(at: FileManager.snapshots) + } + } + } + + public func update(_ tab: UUID, page: Page) { + items.firstIndex { $0.id == tab }.map { + items[$0].page = page + } + } + + public func page(_ tab: UUID) -> Page? { + items.first { $0.id == tab }?.page + } + + public func image(_ id: UUID, completion: @escaping (Data?) -> Void) { + queue.async { + let data = try? Data(contentsOf: FileManager.snapshots.appendingPathComponent(id.uuidString)) + DispatchQueue.main.async { + completion(data) + } + } + } + + public func save(_ image: Data, with: UUID) { + queue.async { + if !FileManager.default.fileExists(atPath: FileManager.snapshots.path) { + var url = FileManager.snapshots + var resources = URLResourceValues() + resources.isExcludedFromBackup = true + try? url.setResourceValues(resources) + try? FileManager.default.createDirectory(at: url, withIntermediateDirectories: true) + } + try? image.write(to: FileManager.snapshots.appendingPathComponent(with.uuidString), options: .atomic) + } + } + + func deleteSnapshot(_ id: UUID) { + queue.async { + if FileManager.default.fileExists(atPath: FileManager.snapshots.appendingPathComponent(id.uuidString).path) { + try? FileManager.default.removeItem(at: FileManager.snapshots.appendingPathComponent(id.uuidString)) + } + } + } +} diff --git a/Ecosia/Core/TimeInterval+Extensions.swift b/Ecosia/Core/TimeInterval+Extensions.swift new file mode 100644 index 000000000000..dd5a6131d95f --- /dev/null +++ b/Ecosia/Core/TimeInterval+Extensions.swift @@ -0,0 +1,6 @@ +import Foundation + +extension TimeInterval { + + static let twentyFourHoursTimeInterval: TimeInterval = 24*60*60 +} diff --git a/Ecosia/Core/TimestampProvider.swift b/Ecosia/Core/TimestampProvider.swift new file mode 100644 index 000000000000..c1b12e7a47de --- /dev/null +++ b/Ecosia/Core/TimestampProvider.swift @@ -0,0 +1,5 @@ +import Foundation + +protocol TimestampProvider { + var currentTimestamp: TimeInterval { get } +} diff --git a/Ecosia/Core/URL+Extensions.swift b/Ecosia/Core/URL+Extensions.swift new file mode 100644 index 000000000000..637e2cd588c3 --- /dev/null +++ b/Ecosia/Core/URL+Extensions.swift @@ -0,0 +1,80 @@ +import Foundation + +extension URL { + + public enum Key: String { + case + query = "q", + typeTag = "tt", + userId = "_sp" + } + + public static func ecosiaSearchWithQuery(_ query: String, urlProvider: URLProvider = Environment.current.urlProvider) -> URL { + var components = URLComponents(url: urlProvider.root, resolvingAgainstBaseURL: false)! + components.path = "/search" + components.queryItems = [item(key: .query, value: query), item(key: .typeTag, value: "iosapp")] + return components.url! + } + + /// Check whether the URL being browsed will present the SERP out of a search or a search suggestion + public func isEcosiaSearchQuery(_ urlProvider: URLProvider = Environment.current.urlProvider) -> Bool { + guard isEcosia(urlProvider), + let components = URLComponents(url: self, resolvingAgainstBaseURL: false) else { + return false + } + return components.path == "/search" + } + + /// Check whether the URL should be Ecosified. At the moment this is true for every Ecosia URL. + public func shouldEcosify(_ urlProvider: URLProvider = Environment.current.urlProvider) -> Bool { + return isEcosia(urlProvider) + } + + public func ecosified(isIncognitoEnabled: Bool, urlProvider: URLProvider = Environment.current.urlProvider) -> URL { + guard isEcosia(urlProvider), + var components = components + else { return self } + components.queryItems?.removeAll(where: { $0.name == Key.userId.rawValue }) + var items = components.queryItems ?? .init() + /* + The `sendAnonymousUsageData` is set by the native UX component in settings + that determines whether the app would send the events to Snowplow. + To align the business logic, this parameter will also function as a condition + that decides whether we would send our AnalyticsID as query paramter for + searches. In this scenario thuogh, the naming is a bit misleanding, thus + checking for the negative evaluation of it. + */ + let shouldAnonymizeUserId = isIncognitoEnabled || + !User.shared.hasAnalyticsCookieConsent || + !User.shared.sendAnonymousUsageData + let userId = shouldAnonymizeUserId ? UUID(uuid: UUID_NULL).uuidString : User.shared.analyticsId.uuidString + items.append(Self.item(key: .userId, value: userId)) + components.queryItems = items + return components.url! + } + + public var policy: Scheme.Policy { + (scheme + .flatMap(Scheme.init(rawValue:)) ?? .other) + .policy + } + + private subscript(_ key: Key) -> String? { + components?.queryItems?.first { $0.name == key.rawValue }?.value + } + + private func isEcosia(_ urlProvider: URLProvider = Environment.current.urlProvider) -> Bool { + guard let domain = urlProvider.domain else { return false } + let isBrowser = scheme.flatMap(Scheme.init(rawValue:))?.isBrowser == true + let hasURLProviderDomainSuffix = host?.hasSuffix(domain) == true + return isBrowser && hasURLProviderDomainSuffix + } + + private var components: URLComponents? { + URLComponents(url: self, resolvingAgainstBaseURL: false) + } + + private static func item(key: Key, value: String) -> URLQueryItem { + .init(name: key.rawValue, value: value) + } +} diff --git a/Ecosia/Core/URLRequest+Extensions.swift b/Ecosia/Core/URLRequest+Extensions.swift new file mode 100644 index 000000000000..816d50be7967 --- /dev/null +++ b/Ecosia/Core/URLRequest+Extensions.swift @@ -0,0 +1,18 @@ +import Foundation + +extension URLRequest { + + public mutating func withAuthParameters(environment: Environment = Environment.current) -> URLRequest { + if let auth = environment.auth { + setValue(auth.id, forHTTPHeaderField: CloudflareKeyProvider.clientId) + setValue(auth.secret, forHTTPHeaderField: CloudflareKeyProvider.clientSecret) + } + return self + } + + /// This function provides an additional HTTP request header when loading SERP through native UI (i.e. submitting a search) + /// to help SERP decide which market to serve. + public mutating func addLanguageRegionHeader() { + setValue(Locale.current.identifierWithDashedLanguageAndRegion, forHTTPHeaderField: "x-ecosia-app-language-region") + } +} diff --git a/Ecosia/Core/User.swift b/Ecosia/Core/User.swift new file mode 100644 index 000000000000..a8e213fb570f --- /dev/null +++ b/Ecosia/Core/User.swift @@ -0,0 +1,269 @@ +import Foundation +import UserNotifications +import Combine + +extension Notification.Name { + static let searchesCounterChanged = Notification.Name("searchesCounterChanged") + public static let searchSettingsChanged = Notification.Name("searchSettingsChanged") +} + +public struct User: Codable, Equatable { + public static var shared = User() { + didSet { + guard shared != oldValue else { return } + shared.save() + + if shared.hasNewSearchSetting(compared: oldValue) { + DispatchQueue.main.async { + NotificationCenter.default.post(name: .searchSettingsChanged, object: nil) + } + } + } + } + + // MARK: Search Settings + public var marketCode = Local.make(for: .current) + public var adultFilter = AdultFilter.moderate + public var autoComplete = true + public var personalized = false + + // MARK: Privacy settings + public var sendAnonymousUsageData = true + public internal(set) var cookieConsentValue: String? + public var hasAnalyticsCookieConsent: Bool { + guard let cookieConsentValue else { + return false + } + return cookieConsentValue.contains("a") + } + + // MARK: NTP Customization + public var showTopSites = true + public var topSitesRows = 4 + public var showClimateImpact = true + public var showEcosiaNews = true + public var showAboutEcosia = true + + // MARK: Install + public var install = Date() + public var analyticsId = UUID() + public var versionOnInstall = "0.0.0" + public var firstTime = true + + // MARK: Other + public var news = Date.distantPast + public var migrated = false + public var referrals = Referrals.Model() + public internal(set) var id: String? + public var whatsNewItemsVersionsShown = Set() + public internal(set) var analyticsUserState = AnalyticsStateContext() + + public var searchCount = 0 { + didSet { + guard oldValue != searchCount else { return } + DispatchQueue.main.async { + NotificationCenter.default.post(name: .searchesCounterChanged, object: nil) + } + } + } + + var state = [String: String]() + + private enum CodingKeys: String, CodingKey { + case + install, + versionOnInstall, + news, + analyticsId, + marketCode, + adultFilter, + autoComplete, + firstTime, + personalized, + sendAnonymousUsageData, + topSitesRows, + showClimateImpact, + showEcosiaNews, + showAboutEcosia, + migrated, + referrals, + id, + state, + cookieConsentValue, + whatsNewItemsVersionsShown, + analyticsUserState + // Reusing previous decoding keys + case searchCount = "treeCount" + case showTopSites = "topSites" + } + + public init(from decoder: Decoder) throws { + let root = try decoder.container(keyedBy: CodingKeys.self) + install = (try? root.decode(Date.self, forKey: .install)) ?? .init() + versionOnInstall = (try? root.decode(String.self, forKey: .versionOnInstall)) ?? "0.0.0" + news = (try? root.decode(Date.self, forKey: .news)) ?? .distantPast + analyticsId = (try? root.decode(UUID.self, forKey: .analyticsId)) ?? .init() + marketCode = (try? root.decode(Local.self, forKey: .marketCode)) ?? Local.make(for: .current) + adultFilter = (try? root.decode(AdultFilter.self, forKey: .adultFilter)) ?? .moderate + autoComplete = (try? root.decode(Bool.self, forKey: .autoComplete)) ?? true + firstTime = (try? root.decode(Bool.self, forKey: .firstTime)) ?? true + personalized = (try? root.decode(Bool.self, forKey: .personalized)) ?? false + sendAnonymousUsageData = (try? root.decode(Bool.self, forKey: .sendAnonymousUsageData)) ?? true + topSitesRows = (try? root.decode(Int.self, forKey: .topSitesRows)) ?? 4 + showTopSites = (try? root.decode(Bool.self, forKey: .showTopSites)) ?? true + showClimateImpact = (try? root.decode(Bool.self, forKey: .showClimateImpact)) ?? true + showEcosiaNews = (try? root.decode(Bool.self, forKey: .showEcosiaNews)) ?? true + showAboutEcosia = (try? root.decode(Bool.self, forKey: .showAboutEcosia)) ?? true + migrated = (try? root.decode(Bool.self, forKey: .migrated)) ?? false + referrals = (try? root.decode(Referrals.Model.self, forKey: .referrals)) ?? .init() + id = try? root.decode(String.self, forKey: .id) + searchCount = (try? root.decode(Int.self, forKey: .searchCount)) ?? 0 + state = (try? root.decode([String: String].self, forKey: .state)) ?? [:] + cookieConsentValue = try? root.decode(String.self, forKey: .cookieConsentValue) + whatsNewItemsVersionsShown = (try? root.decode(Set.self, forKey: .whatsNewItemsVersionsShown)) ?? [] + analyticsUserState = (try? root.decode(AnalyticsStateContext.self, forKey: .analyticsUserState)) ?? .init() + } + + init() { + if let stored = self.stored { + id = stored.id + adultFilter = stored.adultFilter + marketCode = stored.marketCode + searchCount = stored.searchCount + autoComplete = stored.autoComplete + firstTime = stored.firstTime + analyticsId = stored.analyticsId + personalized = stored.personalized + sendAnonymousUsageData = stored.sendAnonymousUsageData + migrated = stored.migrated + state = stored.state + news = stored.news + topSitesRows = stored.topSitesRows + showTopSites = stored.showTopSites + showClimateImpact = stored.showClimateImpact + showEcosiaNews = stored.showEcosiaNews + showAboutEcosia = stored.showAboutEcosia + referrals = stored.referrals + install = stored.install + versionOnInstall = stored.versionOnInstall + cookieConsentValue = stored.cookieConsentValue + whatsNewItemsVersionsShown = stored.whatsNewItemsVersionsShown + analyticsUserState = stored.analyticsUserState + } else { + save() + } + } + + private var stored: User? { + try? JSONDecoder().decode(User.self, from: .init(contentsOf: FileManager.user)) + } + + static let queue = DispatchQueue(label: "", qos: .utility) + private func save() { + let user = self + User.queue.async { + try? JSONEncoder().encode(user).write(to: FileManager.user, options: .atomic) + } + } +} + +// MARK: Helper methods +extension User { + + public var showsReferralSpotlight: Bool { + guard install < Calendar.current.date(byAdding: .day, value: -3, to: .init())! else { return false } + return state[Key.referralSpotlight.rawValue].map(Bool.init) != false + } + + public var showsInactiveTabsTooltip: Bool { + state[Key.inactiveTabsTooltip.rawValue].map(Bool.init) != false + } + + public var showsBookmarksImportExportTooltip: Bool { + state[Key.bookmarksImportExportTooltipShown.rawValue].map(Bool.init) != false + } + + public var shouldShowImpactIntro: Bool { + state[Key.impactIntro.rawValue].map(Bool.init) != false + } + + public mutating func hideImpactIntro() { + state[Key.impactIntro.rawValue] = "\(false)" + } + + public mutating func showImpactIntro() { + state[Key.impactIntro.rawValue] = "\(true)" + } + + public mutating func hideReferralSpotlight() { + state[Key.referralSpotlight.rawValue] = "\(false)" + } + + public mutating func showInactiveTabsTooltip() { + state[Key.inactiveTabsTooltip.rawValue] = "\(true)" + } + + public mutating func hideInactiveTabsTooltip() { + state[Key.inactiveTabsTooltip.rawValue] = "\(false)" + } + + public mutating func hideBookmarksImportExportTooltip() { + state[Key.bookmarksImportExportTooltipShown.rawValue] = "\(false)" + } + + enum Key: String { + case + referralSpotlight, + impactIntro = "counterIntro", // Reusing previous key + inactiveTabsTooltip, + bookmarksImportExportTooltipShown, + isNewUserSinceBookmarksImportExportHasBeenShipped + } +} + +// MARK: Search Setting Helper +extension User { + private struct SearchSetting: Equatable { + let marketCode: Local + let adultFilter: AdultFilter + let autoComplete: Bool + let personalized: Bool + } + + private var searchSetting: SearchSetting { + .init(marketCode: marketCode, adultFilter: adultFilter, autoComplete: autoComplete, personalized: personalized) + } + + func hasNewSearchSetting(compared to: User) -> Bool { + searchSetting != to.searchSetting + } +} + +// MARK: User state context +extension User { + + /// Mimics the high level push notification states + public enum PushNotificationState: String, Codable { + case enabled + case disabled + case notDetermined = "not_determined" + } + + /// The values to pass into the Analytics User State Dedicated context + public struct AnalyticsStateContext: Codable, Equatable { + var pushNotificationState: PushNotificationState = .notDetermined + + enum CodingKeys: String, CodingKey { + case pushNotificationState = "push_notification_state" + } + } + + /// Updates the Analytics' User State given the current App's User Notification's status + public mutating func updatePushNotificationUserStateWithAnalytics(from status: UNAuthorizationStatus) { + analyticsUserState.pushNotificationState = switch status { + case .authorized, .ephemeral, .provisional: .enabled + case .denied: .disabled + default: .notDetermined + } + } +} diff --git a/Ecosia/Core/UserDefaults+ObjectPersister.swift b/Ecosia/Core/UserDefaults+ObjectPersister.swift new file mode 100644 index 000000000000..7179a318e924 --- /dev/null +++ b/Ecosia/Core/UserDefaults+ObjectPersister.swift @@ -0,0 +1,3 @@ +import Foundation + +extension UserDefaults: ObjectPersister {} diff --git a/Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift b/Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift index 42545dc22612..89f74d7a30ad 100644 --- a/Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift +++ b/Ecosia/Experiments/Unleash/APNConsentOnLaunchExperiment.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core import NotificationCenter <<<<<<<< HEAD:Ecosia/Braze/APNConsent.swift diff --git a/Ecosia/Experiments/Unleash/BrazeIntegrationExperiment.swift b/Ecosia/Experiments/Unleash/BrazeIntegrationExperiment.swift index bbda45d3d0c6..31e74c262eaf 100644 --- a/Ecosia/Experiments/Unleash/BrazeIntegrationExperiment.swift +++ b/Ecosia/Experiments/Unleash/BrazeIntegrationExperiment.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core struct BrazeIntegrationExperiment { diff --git a/Ecosia/Experiments/Unleash/NewsletterCardExperiment.swift b/Ecosia/Experiments/Unleash/NewsletterCardExperiment.swift index 497f40026eaa..58ad64de23af 100644 --- a/Ecosia/Experiments/Unleash/NewsletterCardExperiment.swift +++ b/Ecosia/Experiments/Unleash/NewsletterCardExperiment.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core public struct NewsletterCardExperiment { private init() {} diff --git a/Ecosia/Extensions/DeviceInfo+Ecosia.swift b/Ecosia/Extensions/DeviceInfo+Ecosia.swift index 6012a0569cd1..04b9ce994ac6 100644 --- a/Ecosia/Extensions/DeviceInfo+Ecosia.swift +++ b/Ecosia/Extensions/DeviceInfo+Ecosia.swift @@ -3,9 +3,8 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Shared -import Common import UIKit +import Common extension DeviceInfo { diff --git a/Ecosia/FeatureManagement/FeatureManagement.swift b/Ecosia/FeatureManagement/FeatureManagement.swift index 3b6431f0ef86..20cea51ac34d 100644 --- a/Ecosia/FeatureManagement/FeatureManagement.swift +++ b/Ecosia/FeatureManagement/FeatureManagement.swift @@ -4,7 +4,6 @@ import Foundation import Common -import Core public struct FeatureManagement { diff --git a/Ecosia/Helpers/AppInfoProvider/DefaultAppVersionInfoProvider.swift b/Ecosia/Helpers/AppInfoProvider/DefaultAppVersionInfoProvider.swift index 4d2942ad1f22..6b71cc62ed5e 100644 --- a/Ecosia/Helpers/AppInfoProvider/DefaultAppVersionInfoProvider.swift +++ b/Ecosia/Helpers/AppInfoProvider/DefaultAppVersionInfoProvider.swift @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/ -import Shared +import Foundation import Common public struct DefaultAppVersionInfoProvider: AppVersionInfoProvider { diff --git a/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType+Extensions.swift b/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType+Extensions.swift index 5a3480c898d1..6c39cc534f1e 100644 --- a/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType+Extensions.swift +++ b/Ecosia/Helpers/EcosiaInstallType/EcosiaInstallType+Extensions.swift @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/ -import Core +import Foundation /// This extension provides functionality to evaluate the current Ecosia installation type based on the provided app version information. extension EcosiaInstallType { diff --git a/Ecosia/Helpers/Version/Version+Extensions.swift b/Ecosia/Helpers/Version/Version+Extensions.swift index 0d72cd7f9dd5..7ba87dcc8e84 100644 --- a/Ecosia/Helpers/Version/Version+Extensions.swift +++ b/Ecosia/Helpers/Version/Version+Extensions.swift @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/ -import Shared +import Foundation import Common /// Extension handling previous version retrieval and saving current version. diff --git a/Ecosia/L10N/String.swift b/Ecosia/L10N/String.swift index 3f967a2b510a..55dcd475ffe2 100644 --- a/Ecosia/L10N/String.swift +++ b/Ecosia/L10N/String.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Core extension String { public static func localized(_ key: Key) -> String { diff --git a/EcosiaTests/Core/BookmarkParserTests.swift b/EcosiaTests/Core/BookmarkParserTests.swift new file mode 100644 index 000000000000..debf9acfbb70 --- /dev/null +++ b/EcosiaTests/Core/BookmarkParserTests.swift @@ -0,0 +1,37 @@ +@testable import Core +import XCTest + +final class BookmarkParserTests: XCTestCase { + func testParsesFolderAndBookmarks_Chrome() async throws { + let html = BookmarkFixtures.html(.chrome).value + + let importer = try BookmarkParser(html: html) + let bookmarks = try await importer.parseBookmarks() + + let expectedResult = BookmarkFixtures.debugString(.chrome).value + + XCTAssertEqual(bookmarks.debugDescription, expectedResult) + } + + func testParsesFolderAndBookmarks_Firefox() async throws { + let html = BookmarkFixtures.html(.firefox).value + + let importer = try BookmarkParser(html: html) + let bookmarks = try await importer.parseBookmarks() + + let expectedResult = BookmarkFixtures.debugString(.firefox).value + + XCTAssertEqual(bookmarks.debugDescription, expectedResult) + } + + func testParsesFolderAndBookmarks_Safari() async throws { + let html = BookmarkFixtures.html(.safari).value + + let importer = try BookmarkParser(html: html) + let bookmarks = try await importer.parseBookmarks() + + let expectedResult = BookmarkFixtures.debugString(.safari).value + + XCTAssertEqual(bookmarks.debugDescription, expectedResult) + } +} diff --git a/EcosiaTests/Core/BookmarkSerializerTests.swift b/EcosiaTests/Core/BookmarkSerializerTests.swift new file mode 100644 index 000000000000..88f38494f85b --- /dev/null +++ b/EcosiaTests/Core/BookmarkSerializerTests.swift @@ -0,0 +1,27 @@ +@testable import Core +import XCTest + +final class BookmarkSerializerTests: XCTestCase { + func test_SerializesBookmarks() async throws { + let bookmarks: [BookmarkItem] = [ + .folder("Favorites", [ + .bookmark("One", "https://example.com/one", .empty), + .bookmark("Two", "https://example.com/two", .empty), + .folder("My Folder #1", [ + .bookmark("Three", "https://example.com/three", .init(addedAt: .init(timeIntervalSince1970: 123), modifiedAt: nil)) + ], .empty), + .folder("My Folder #2", [ + .bookmark("Four", "https://example.com/four", .init(addedAt: .init(timeIntervalSince1970: 456), modifiedAt: nil)), + .folder("My Subfolder #1", [ + .bookmark("Five", "https://example.com/five", .init(addedAt: .init(timeIntervalSince1970: 789), modifiedAt: .init(timeIntervalSince1970: 987))) + ], .empty), + ], .empty) + ], .empty) + ] + + let html = try await BookmarkSerializer().serializeBookmarks(bookmarks) + .filter { !$0.isWhitespace } + + XCTAssertEqual(html, BookmarkFixtures.ecosiaExportedHtml.filter { !$0.isWhitespace }) + } +} diff --git a/EcosiaTests/Core/BookmarkTests.swift b/EcosiaTests/Core/BookmarkTests.swift new file mode 100644 index 000000000000..9e12181f686d --- /dev/null +++ b/EcosiaTests/Core/BookmarkTests.swift @@ -0,0 +1,20 @@ +@testable import Core +import XCTest + +final class BookmarkTests: XCTestCase { + func test_BookmarkSerializer_Parser() async throws { + let input: [BookmarkItem] = [ + .bookmark("One", "https://example.com/one", .empty), + .folder("My first folder 😆", [ + .bookmark("Two &!/{}", "https://example.com/two", .empty), + .bookmark("Three ÖÄÜ'*", "https://example.com/three", .empty) + ], .empty) + ] + + let html = try await BookmarkSerializer().serializeBookmarks(input) + + let output = try await BookmarkParser(html: html).parseBookmarks() + + XCTAssertEqual(input, output) + } +} diff --git a/EcosiaTests/Core/CookieTests.swift b/EcosiaTests/Core/CookieTests.swift new file mode 100644 index 000000000000..ee1f0d5e3d95 --- /dev/null +++ b/EcosiaTests/Core/CookieTests.swift @@ -0,0 +1,250 @@ +@testable import Core +import XCTest + +final class CookieTests: XCTestCase { + + var urlProvider: URLProvider = .production + + override func setUp() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + func testDefaults() { + XCTAssertEqual("ECFG", Cookie.makeStandardCookie(urlProvider).name) + XCTAssertEqual(".ecosia.org", Cookie.makeStandardCookie(urlProvider).domain) + XCTAssertEqual("/", Cookie.makeStandardCookie(urlProvider).path) + } + + func testIncognitoValuesNoPersonalData() { + User.shared.searchCount = 1234 + User.shared.id = "neverland" + + let incognitoDict = Cookie.makeIncognitoCookie(urlProvider).value.components(separatedBy: ":").map { $0.components(separatedBy: "=") }.reduce(into: [String: String]()) { + guard $1.count == 2 else { return } + $0[$1[0]] = $1[1] + } + XCTAssertNil(incognitoDict["cid"]) + XCTAssertNil(incognitoDict["t"]) + + let standardDict = Cookie.makeStandardCookie(urlProvider).value.components(separatedBy: ":").map { $0.components(separatedBy: "=") }.reduce(into: [String: String]()) { + guard $1.count == 2 else { return } + $0[$1[0]] = $1[1] + } + XCTAssertNotNil(standardDict["cid"]) + XCTAssertNotNil(standardDict["t"]) + } + + func testMakeConsentCookieReturnsCookieWhenValueStoredInUser() { + User.shared.cookieConsentValue = "eampg" + + XCTAssertNotNil(Cookie.makeConsentCookie(urlProvider)) + XCTAssertEqual(Cookie.makeConsentCookie(urlProvider)?.name, Cookie.consent.name) + } + + func testMakeConsentCookieDoesNotReturnCookieWhenValueNotStoredInUser() { + User.shared.cookieConsentValue = nil + + XCTAssertNil(Cookie.makeConsentCookie(urlProvider)) + } + + func testDefaultsAddingUser() { + User.shared.searchCount = 1234 + User.shared.marketCode = .es_cl + User.shared.adultFilter = .off + User.shared.autoComplete = false + User.shared.id = "neverland" + User.shared.personalized = true + + let dictionary = Cookie.makeStandardCookie(urlProvider).value.components(separatedBy: ":").map { $0.components(separatedBy: "=") }.reduce(into: [String: String]()) { + guard $1.count == 2 else { return } + $0[$1[0]] = $1[1] + } + XCTAssertEqual(Language.current.rawValue, dictionary["l"]) + XCTAssertEqual("1234", dictionary["t"]) + XCTAssertEqual("n", dictionary["f"]) + XCTAssertEqual("es-cl", dictionary["mc"]) + XCTAssertEqual("0", dictionary["as"]) + XCTAssertEqual("1", dictionary["ma"]) + XCTAssertEqual("1", dictionary["mr"]) + XCTAssertEqual("mobile", dictionary["dt"]) + XCTAssertEqual("0", dictionary["fs"]) + XCTAssertEqual("neverland", dictionary["cid"]) + XCTAssertEqual("1", dictionary["a"]) + XCTAssertEqual("1", dictionary["pz"]) + } + + func testDefaultsNoUserId() { + User.shared.id = nil + + let dictionary = Cookie.makeStandardCookie(urlProvider).value.components(separatedBy: ":").map { $0.components(separatedBy: "=") }.reduce(into: [String: String]()) { + guard $1.count == 2 else { return } + $0[$1[0]] = $1[1] + } + XCTAssertEqual(Language.current.rawValue, dictionary["l"]) + XCTAssertNil(dictionary["cid"]) + } + + func testReceivedInvalidDomain() { + User.shared.searchCount = 3 + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.it", .path: "/", .value: "as=0:f=s:mc=en-uk:t=9999"])!]) + + let dictionary = Cookie.makeStandardCookie(urlProvider).value.components(separatedBy: ":").map { $0.components(separatedBy: "=") }.reduce(into: [String: String]()) { + guard $1.count == 2 else { return } + $0[$1[0]] = $1[1] + } + XCTAssertEqual("3", dictionary["t"]) + } + + func testReceiving() { + User.shared.searchCount = 0 + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "as=0:f=s:mc=en-uk:t=9999:cid=loremipsum"])!]) + + let dictionary = Cookie.makeStandardCookie(urlProvider).value.components(separatedBy: ":").map { $0.components(separatedBy: "=") }.reduce(into: [String: String]()) { + guard $1.count == 2 else { return } + $0[$1[0]] = $1[1] + } + XCTAssertEqual("9999", dictionary["t"]) + XCTAssertEqual("loremipsum", dictionary["cid"]) + } + + func testReceivingUpdatesCounter() { + User.shared.searchCount = 0 + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "as=0:f=s:mc=en-uk:t=9999"])!]) + + XCTAssertEqual(9999, User.shared.searchCount) + } + + func testReceivingUpdatesCounterToZero() { + User.shared.searchCount = 5 + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "as=0:f=s:mc=en-uk:t=0"])!]) + + XCTAssertEqual(0, User.shared.searchCount) + } + + func testReceivingUpdatesCounterOnlyIncrease() { + User.shared.searchCount = 5 + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "as=0:f=s:mc=en-uk:t=4"])!]) + + XCTAssertEqual(5, User.shared.searchCount) + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "as=0:f=s:mc=en-uk:t=6"])!]) + XCTAssertEqual(6, User.shared.searchCount) + } + + func testReceivingUpdatesUserId() { + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "as=0:f=s:mc=en-uk:t=9999:cid=lorem"])!]) + + XCTAssertEqual("lorem", User.shared.id) + } + + func testReceivingTreeCount() { + User.shared.searchCount = 0 + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "t=9999"])!]) + XCTAssertEqual(9999, User.shared.searchCount) + } + + func testReceivingAdultFilter() { + User.shared.adultFilter = .off + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "f=i"])!]) + XCTAssert(User.shared.adultFilter == .moderate) + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "f=y"])!]) + XCTAssert(User.shared.adultFilter == .strict) + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "f=n"])!]) + XCTAssert(User.shared.adultFilter == .off) + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "f=foo"])!]) + XCTAssert(User.shared.adultFilter == .off) + } + + func testReceivingMarketCode() { + User.shared.marketCode = .en_us + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "mc=en-gb"])!]) + XCTAssert(User.shared.marketCode == .en_gb) + } + + func testReceivingAutocomplete() { + User.shared.autoComplete = false + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "as=1"])!]) + XCTAssertTrue(User.shared.autoComplete) + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "as=0"])!]) + XCTAssertFalse(User.shared.autoComplete) + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "as=foo"])!]) + XCTAssertFalse(User.shared.autoComplete) + } + + func testReceivingPersonalisedSearch() { + User.shared.personalized = false + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "pz=1"])!]) + XCTAssertTrue(User.shared.personalized) + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "pz=0"])!]) + XCTAssertFalse(User.shared.personalized) + + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "pz=foo"])!]) + XCTAssertFalse(User.shared.personalized) + } + + func testRemoveUnknownProperties() { + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "as=0:name=test"])!]) + + let dictionary = Cookie.makeStandardCookie(urlProvider).value.components(separatedBy: ":").map { $0.components(separatedBy: "=") }.reduce(into: [String: String]()) { + guard $1.count == 2 else { return } + $0[$1[0]] = $1[1] + } + XCTAssertNil(dictionary["name"]) + } + + func testReceivingMaintainsUserId() { + User.shared.id = "hello" + extractReceivedCookies([HTTPCookie(properties: [.name: "ECFG", .domain: ".ecosia.org", .path: "/", .value: "as=0:f=s:mc=en-uk:t=9999"])!]) + + XCTAssertEqual("hello", User.shared.id) + } + + func testReceivedInvalidName() { + User.shared.searchCount = 3 + extractReceivedCookies([HTTPCookie(properties: [.name: "Facebook", .domain: ".ecosia.org", .path: "/", .value: "as=0:f=s:mc=en-uk:t=9999"])!]) + + let dictionary = Cookie.makeStandardCookie(urlProvider).value.components(separatedBy: ":").map { $0.components(separatedBy: "=") }.reduce(into: [String: String]()) { + guard $1.count == 2 else { return } + $0[$1[0]] = $1[1] + } + XCTAssertEqual("3", dictionary["t"]) + } + + func testExtractECCCNoAnalyticsConsent() { + User.shared.cookieConsentValue = "e" + extractReceivedCookies([HTTPCookie(properties: [.name: "ECCC", .domain: ".ecosia.org", .path: "/", .value: "e"])!]) + + XCTAssertEqual(User.shared.cookieConsentValue, "e") + XCTAssertFalse(User.shared.hasAnalyticsCookieConsent) + } + + func testExtractECCCWithAnalyticsConsent() { + User.shared.cookieConsentValue = "e" + extractReceivedCookies([HTTPCookie(properties: [.name: "ECCC", .domain: ".ecosia.org", .path: "/", .value: "eampg"])!]) + + XCTAssertEqual(User.shared.cookieConsentValue, "eampg") + XCTAssertTrue(User.shared.hasAnalyticsCookieConsent) + } +} + +extension CookieTests { + + /// This function calls the original `Cookie.received` injecting the `urlProvider` utilized for tests + func extractReceivedCookies(_ cookies: [HTTPCookie]) { + Cookie.received(cookies, urlProvider: urlProvider) + } +} diff --git a/EcosiaTests/Core/FavouritesTests.swift b/EcosiaTests/Core/FavouritesTests.swift new file mode 100644 index 000000000000..b44d484dbe7a --- /dev/null +++ b/EcosiaTests/Core/FavouritesTests.swift @@ -0,0 +1,38 @@ +@testable import Core +import XCTest + +final class FavouritesTests: XCTestCase { + + override func setUp() { + try? FileManager.default.removeItem(at: FileManager.pages) + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.pages) + } + + func testSave() { + let expect = expectation(description: "") + let favourites = Favourites() + favourites.items.append(.init(url: URL(string: "https://avocado.com")!, title: "")) + PageStore.queue.async { + XCTAssertTrue(FileManager.default.fileExists(atPath: FileManager.favourites.path)) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testLoad() { + let expect = expectation(description: "") + var favourites = Favourites() + favourites.items.append(.init(url: URL(string: "https://www.avocado.com")!, title: "hello world")) + favourites.items.append(.init(url: URL(string: "https://www.guacamole.com")!, title: "lorem ipsum")) + PageStore.queue.async { + favourites = .init() + XCTAssertEqual("hello world", favourites.items.first?.title) + XCTAssertEqual("lorem ipsum", favourites.items.last?.title) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } +} diff --git a/EcosiaTests/Core/FeatureFlaggingSessionInitializerTests.swift b/EcosiaTests/Core/FeatureFlaggingSessionInitializerTests.swift new file mode 100644 index 000000000000..41bde3b79024 --- /dev/null +++ b/EcosiaTests/Core/FeatureFlaggingSessionInitializerTests.swift @@ -0,0 +1,41 @@ +import XCTest +import Foundation +@testable import Core + +class FeatureManagementSessiontInitializerTests: XCTestCase { + + func testInitializeSession() async throws { + + // given + let initializer = FeatureManagementSessiontInitializerSPY() + + // when + let expect = expectation(description: "The session initialization should be sent asynchronously") + do { + let _: DummyResponse = try await initializer.startSession()! + XCTAssertTrue(initializer.initializeSessionRequestSent) + expect.fulfill() + } catch { + XCTFail("Initializing session failed: \(error.localizedDescription)") + } + + wait(for: [expect], timeout: 1.0) + } +} + +extension FeatureManagementSessiontInitializerTests { + + class FeatureManagementSessiontInitializerSPY: FeatureManagementSessionInitializer { + + var initializeSessionRequestSent: Bool! + + func startSession() async throws -> T? where T: Decodable { + initializeSessionRequestSent = true + return DummyResponse(value: 0) as? T + } + } + + struct DummyResponse: Decodable { + let value: Int + } +} diff --git a/EcosiaTests/Core/FinancialReportsTests.swift b/EcosiaTests/Core/FinancialReportsTests.swift new file mode 100644 index 000000000000..dccd68e6a289 --- /dev/null +++ b/EcosiaTests/Core/FinancialReportsTests.swift @@ -0,0 +1,40 @@ +@testable import Core +import XCTest + +final class FinancialReportsTests: XCTestCase { + private var financialReports: FinancialReports! + private var mockURLSession: MockURLSessionProtocol! + + override func setUp() { + financialReports = FinancialReports.shared + mockURLSession = MockURLSessionProtocol() + } + + func testFetchAndUpdate() async throws { + mockURLSession.data = Data(""" + { + "2023-8": { "totalIncome": 456, "numberOfTreesFinanced": 11 }, + "2023-7": { "totalIncome": 123, "numberOfTreesFinanced": 10 } + } + """.utf8) + + try await financialReports.fetchAndUpdate(urlSession: mockURLSession) + + XCTAssertEqual(financialReports.latestMonth, Date(timeIntervalSince1970: 1690848000)) + XCTAssertEqual(financialReports.latestReport, + FinancialReports.Report(totalIncome: 456, + numberOfTreesFinanced: 11)) + } + + func testLocalizedMonthAndYear() async throws { + mockURLSession.data = Data(""" + { + "2021-5": { "totalIncome": 1, "numberOfTreesFinanced": 1 } + } + """.utf8) + + try await financialReports.fetchAndUpdate(urlSession: mockURLSession) + + XCTAssertEqual(financialReports.localizedMonthAndYear, "May 2021") + } +} diff --git a/EcosiaTests/Core/HistoryTests.swift b/EcosiaTests/Core/HistoryTests.swift new file mode 100644 index 000000000000..28d302df6181 --- /dev/null +++ b/EcosiaTests/Core/HistoryTests.swift @@ -0,0 +1,72 @@ +@testable import Core +import XCTest + +final class HistoryTests: XCTestCase { + override func setUp() { + try? FileManager.default.removeItem(at: FileManager.pages) + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.pages) + } + + func testSave() { + let expect = expectation(description: "") + let history = History() + history.add(.init(url: URL(string: "https://avocado.com")!, title: "hello world")) + PageStore.queue.async { + XCTAssertTrue(FileManager.default.fileExists(atPath: FileManager.history.path)) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testLoad() { + let expect = expectation(description: "") + var history = History() + history.add(.init(url: URL(string: "https://avocado.com")!, title: "hello world")) + history.add(.init(url: URL(string: "https://guacamole.com")!, title: "lorem ipsum")) + PageStore.queue.async { + history = .init() + PageStore.queue.async { + XCTAssertGreaterThan(history.items.first!.0, Date(timeIntervalSince1970: 1)) + XCTAssertGreaterThan(history.items.last!.0, Date(timeIntervalSince1970: 1)) + XCTAssertEqual("hello world", history.items.first?.1.title) + XCTAssertEqual("lorem ipsum", history.items.last?.1.title) + expect.fulfill() + } + } + waitForExpectations(timeout: 1) + } + + func testDelete() { + let expect = expectation(description: "") + var history = History() + history.add(.init(url: URL(string: "https://avocado.com")!, title: "hello world")) + PageStore.queue.async { + history = .init() + history.delete(history.items.first!.0) + PageStore.queue.async { + XCTAssertTrue(History().items.isEmpty) + expect.fulfill() + } + } + waitForExpectations(timeout: 1) + } + + func testDeleteAll() { + let expect = expectation(description: "") + var history = History() + history.add(.init(url: URL(string: "https://avocado.com")!, title: "hello world")) + history.add(.init(url: URL(string: "https://guacamlo.com")!, title: "lorem ipsum")) + PageStore.queue.async { + history = .init() + history.deleteAll() + PageStore.queue.async { + XCTAssertTrue(History().items.isEmpty) + expect.fulfill() + } + } + waitForExpectations(timeout: 1) + } +} diff --git a/EcosiaTests/Core/ImagesTests.swift b/EcosiaTests/Core/ImagesTests.swift new file mode 100644 index 000000000000..c743242ba400 --- /dev/null +++ b/EcosiaTests/Core/ImagesTests.swift @@ -0,0 +1,38 @@ +import XCTest +@testable import Core + +final class ImagesTests: XCTestCase { + private var session: MockURLSession! + private var images: Images! + + override func setUp() { + session = .init() + images = .init(session) + } + + func testDownload() { + let expect = expectation(description: "") + let url = URL(string: "avocado.com")! + session.data = [.init("hello".utf8)] + images.load(self, url: url) { + XCTAssertEqual(url, $0.url) + XCTAssertFalse($0.data.isEmpty) + XCTAssertEqual(.main, Thread.current) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testCache() { + let expect = expectation(description: "") + let url = URL(string: "avocado.com")! + session.request = { + XCTFail() + } + images.items.insert(.init(url, .init("hello".utf8))) + images.load(self, url: url) { _ in + expect.fulfill() + } + waitForExpectations(timeout: 1) + } +} diff --git a/EcosiaTests/Core/InvestmentsProjectionTests.swift b/EcosiaTests/Core/InvestmentsProjectionTests.swift new file mode 100644 index 000000000000..3efa515eab28 --- /dev/null +++ b/EcosiaTests/Core/InvestmentsProjectionTests.swift @@ -0,0 +1,34 @@ +@testable import Core +import XCTest + +final class InvestmentsProjectionTests: XCTestCase { + private var investmentsProjection: InvestmentsProjection! + + override func setUp() { + investmentsProjection = InvestmentsProjection.shared + } + + func testTotalInvestedAt() { + let date = Date() + Statistics.shared.totalInvestments = 123456789 + Statistics.shared.totalInvestmentsLastUpdated = date.addingTimeInterval(-100) + Statistics.shared.investmentPerSecond = 0.5 + XCTAssertEqual(Int(100*0.5 + 123456789), investmentsProjection.totalInvestedAt(date)) + } + + func testTimerIsActive() { + let investmentPerSecond = 1.0 + Statistics.shared.investmentPerSecond = investmentPerSecond + + let exp = XCTestExpectation(description: "Wait for timer") + let projection = InvestmentsProjection() + var receivedAmount: Int? + projection.subscribe(self) { amount in + receivedAmount = amount + exp.fulfill() + } + wait(for: [exp], timeout: 1) + + XCTAssertNotNil(receivedAmount) + } +} diff --git a/EcosiaTests/Core/LanguageTests.swift b/EcosiaTests/Core/LanguageTests.swift new file mode 100644 index 000000000000..550453fc3389 --- /dev/null +++ b/EcosiaTests/Core/LanguageTests.swift @@ -0,0 +1,18 @@ +@testable import Core +import XCTest + +final class LanguageTests: XCTestCase { + func testCurrent() { + XCTAssertEqual(.en, Language.current) + } + + func testMake() { + XCTAssertEqual(.en, Language.make(for: .init(identifier: "en-DE"))) + XCTAssertEqual(.de, Language.make(for: .init(identifier: "de-MX"))) + XCTAssertEqual(.es, Language.make(for: .init(identifier: "es-ES"))) + XCTAssertEqual(.es, Language.make(for: .init(identifier: "es-MX"))) + XCTAssertEqual(.en, Language.make(for: .init(identifier: "en-US"))) + XCTAssertEqual(.es, Language.make(for: .init(identifier: "es-US"))) + XCTAssertEqual(.en, Language.make(for: .init(identifier: "Invalid"))) + } +} diff --git a/EcosiaTests/Core/ListTests.swift b/EcosiaTests/Core/ListTests.swift new file mode 100644 index 000000000000..0bff07066c84 --- /dev/null +++ b/EcosiaTests/Core/ListTests.swift @@ -0,0 +1,23 @@ +@testable import Core +import XCTest + +final class ListTests: XCTestCase { + func testIncomplete() { + let json = """ +[{ + "name": "test", + "id": 1 +}, +{ + "id": 2 +}] +""" + XCTAssertNil(try? JSONDecoder().decode([Model].self, from: .init(json.utf8))) + XCTAssertEqual("test", (try? JSONDecoder().decode(List.self, from: .init(json.utf8)).items.first?.name)) + } +} + +private struct Model: Decodable { + let name: String + let id: Int +} diff --git a/EcosiaTests/Core/LocalTests.swift b/EcosiaTests/Core/LocalTests.swift new file mode 100644 index 000000000000..52c607baf594 --- /dev/null +++ b/EcosiaTests/Core/LocalTests.swift @@ -0,0 +1,29 @@ +@testable import Core +import XCTest + +final class LocalTests: XCTestCase { + func testCurrent() { + XCTAssertEqual("en-us", Language.current.locale.rawValue) + } + + func testCountryCode() { + let locale = NSLocale(localeIdentifier: "it-DE") + XCTAssertEqual("DE", locale.countryCode) + XCTAssertEqual(.de_de, Local.make(for: locale as Locale)) + } + + func testRegion() { + XCTAssertEqual(.de_de, Local.make(for: .init(identifier: "en-DE"))) + XCTAssertEqual(.es_mx, Local.make(for: .init(identifier: "de-MX"))) + XCTAssertEqual(.es_es, Local.make(for: .init(identifier: "es-ES"))) + XCTAssertEqual(.es_mx, Local.make(for: .init(identifier: "es-MX"))) + XCTAssertEqual(.en_us, Local.make(for: .init(identifier: "en-US"))) + XCTAssertEqual(.es_us, Local.make(for: .init(identifier: "es-US"))) + XCTAssertEqual(.en_us, Local.make(for: .init(identifier: "Invalid"))) + } + + func testIdentifier() { + XCTAssertEqual("en-us", Local.en_us.rawValue) + XCTAssertEqual("de-de", Local.de_de.rawValue) + } +} diff --git a/EcosiaTests/Core/NewsTests.swift b/EcosiaTests/Core/NewsTests.swift new file mode 100644 index 000000000000..667fa0237d24 --- /dev/null +++ b/EcosiaTests/Core/NewsTests.swift @@ -0,0 +1,158 @@ +@testable import Core +import XCTest + +final class NewsTests: XCTestCase { + override func setUp() { + try? FileManager.default.removeItem(at: FileManager.news) + try? FileManager.default.removeItem(at: FileManager.user) + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.news) + try? FileManager.default.removeItem(at: FileManager.user) + } + + private func mockSavedItems() { + let items = [ + NewsModel(id: 1, text: "", language: .en, publishDate: .distantPast, + imageUrl: URL(string: "https://avocade.com")!, targetUrl: URL(string: "https://avocadoe.com")!, trackingName: ""), + NewsModel(id: 2, text: "hello", language: .en, publishDate: .distantFuture, + imageUrl: URL(string: "https://guacamole.com")!, targetUrl: URL(string: "https://guaca.com")!, trackingName: ""), + NewsModel(id: 3, text: "hello", language: .de, publishDate: .distantFuture, + imageUrl: URL(string: "https://guacamole.com")!, targetUrl: URL(string: "https://guaca.com")!, trackingName: "") + ] + try? JSONEncoder().encode(items).write(to: FileManager.news, options: .atomic) + } + + func testPublishOnMainThread() { + let expect = expectation(description: "") + + mockSavedItems() + let notifications = News() + notifications.subscribe(self) { _ in + XCTAssertEqual(.main, Thread.current) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testLoadFromDisk() { + let expect = expectation(description: "") + mockSavedItems() + + let notifications = News() + notifications.subscribe(self) { + XCTAssertEqual(2, $0.count) + $0.forEach { + XCTAssertEqual(.en, $0.language) + } + XCTAssertGreaterThan($0.first!.publishDate, $0.last!.publishDate) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testAvoidDuplication() { + var set = Set([NewsModel(id: 1, text: "Great headline ", language: .en, publishDate: .distantPast, + imageUrl: URL(string: "https://avocade.com")!, targetUrl: URL(string: "https://avocadoe.com")!, trackingName: "")]) + set.insert(NewsModel(id: 1, text: "hello", language: .de, publishDate: .distantFuture, + imageUrl: URL(string: "https://guacamole.com")!, targetUrl: URL(string: "https://guaca.com")!, trackingName: "")) + XCTAssertEqual(1, set.count) + } + + func testLoadNewForced() { + User.shared.news = Date() + + let expect = expectation(description: "") + let session = MockURLSession() + session.data = [try! .init(contentsOf: Bundle.module.url(forResource: "notifications", withExtension: "json")!)] + + let notifications = News() + notifications.subscribe(self) { + XCTAssertEqual(10, $0.count) + XCTAssertGreaterThan($0.first!.publishDate, $0.last!.publishDate) + + expect.fulfill() + } + notifications.load(session: session) + waitForExpectations(timeout: 1) + } + + func testNeedsUpdateOnEmptyNews() { + let news = News() + XCTAssertTrue(news.needsUpdate) + } + + func testNeedsUpdateAfterLoading() { + let expect = expectation(description: "") + mockSavedItems() + User.shared.news = .distantPast + let news = News() + + news.subscribe(self) { _ in + XCTAssertTrue(news.needsUpdate) + + User.shared.news = Date() + XCTAssertFalse(news.needsUpdate) + + User.shared.news = Date().advanced(by: -25 * 60 * 60) + XCTAssertTrue(news.needsUpdate) + + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testSubscribeAndReceive() { + let expect = expectation(description: "") + let news = News() + + news.subscribeAndReceive(self) { items in + XCTAssert(news.state?.count == items.count) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testCallOnFailed() { + let expect = expectation(description: "") + expect.isInverted = true // we expect no callback + let session = MockURLSession() + let notifications = News() + notifications.subscribe(self) { _ in + expect.fulfill() + } + notifications.load(session: session) + waitForExpectations(timeout: 1) + } + + func testCleanTextFromBundle() { + let expect = expectation(description: "") + mockSavedItems() + let notifications = News() + notifications.subscribe(self) { + $0.forEach { + XCTAssertFalse($0.text.contains("'")) + XCTAssertFalse($0.text.contains("")) + } + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testCleanTextFromNetwork() { + let expect = expectation(description: "") + let session = MockURLSession() + session.data = [try! .init(contentsOf: Bundle.module.url(forResource: "notifications", withExtension: "json")!)] + let notifications = News() + notifications.subscribe(self) { + $0.forEach { + XCTAssertFalse($0.text.contains("'")) + XCTAssertFalse($0.text.contains("")) + } + expect.fulfill() + } + notifications.load(session: session) + waitForExpectations(timeout: 1) + } +} diff --git a/EcosiaTests/Core/PublishersTests.swift b/EcosiaTests/Core/PublishersTests.swift new file mode 100644 index 000000000000..c944a627785c --- /dev/null +++ b/EcosiaTests/Core/PublishersTests.swift @@ -0,0 +1,59 @@ +@testable import Core +import XCTest + +final class PublishersTests: XCTestCase { + func testNotifySubscriber() { + let publisher = ExamplePublisher() + let subscriber = ExampleSubscriber(expectation(description: ""), publisher: publisher) + subscriber.shouldReceive = ["hello", "world"] + publisher.eventHappened(["hello", "world"]) + waitForExpectations(timeout: 1) + } + + func testNotRetainingSubscriber() { + let publisher = ExamplePublisher() + var subscriber: ExampleSubscriber? = ExampleSubscriber(expectation(description: ""), publisher: publisher) + subscriber!.shouldReceive = ["hello", "world"] + publisher.eventHappened(["hello", "world"]) + subscriber = nil + publisher.eventHappened(["hello", "world"]) + waitForExpectations(timeout: 1) { _ in + XCTAssertTrue(publisher.subscriptions.isEmpty) + } + } + + func testUnsubscribe() { + let publisher = ExamplePublisher() + publisher.subscribe(self) { _ in } + publisher.unsubscribe(self) + XCTAssertTrue(publisher.subscriptions.isEmpty) + } + + func testSubscribeMultipleTimes() { + let publisher = ExamplePublisher() + publisher.subscribe(self) { _ in } + publisher.subscribe(self) { _ in } + XCTAssertEqual(1, publisher.subscriptions.count) + } +} + +private final class ExamplePublisher: Publisher { + var subscriptions = [Subscription<[String]>]() + + func eventHappened(_ messages: [String]) { + send(messages) + } +} + +private final class ExampleSubscriber { + var shouldReceive = [String]() + private let expect: XCTestExpectation + + init(_ expect: XCTestExpectation, publisher: ExamplePublisher) { + self.expect = expect + publisher.subscribe(self) { [weak self] in + XCTAssertEqual(self?.shouldReceive, $0) + self?.expect.fulfill() + } + } +} diff --git a/EcosiaTests/Core/ReferralsModelTests.swift b/EcosiaTests/Core/ReferralsModelTests.swift new file mode 100644 index 000000000000..b78cbc9be2dc --- /dev/null +++ b/EcosiaTests/Core/ReferralsModelTests.swift @@ -0,0 +1,56 @@ +import XCTest +@testable import Core + +final class ReferralsModelTests: XCTestCase { + override func setUp() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + func testInitWithCode() { + let expect = expectation(description: "") + User.shared.referrals = .init(code: "avocado1234") + User.queue.async { + let user = User() + XCTAssertEqual(0, user.referrals.claims) + XCTAssertEqual("avocado1234", user.referrals.code) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testUpdateReferred() { + let expect = expectation(description: "") + User.shared.referrals = .init(code: "avocado12") + User.queue.async { + User.shared.referrals.claims += 1 + User.queue.async { + let user = User() + XCTAssertEqual(1, user.referrals.claims) + expect.fulfill() + } + } + waitForExpectations(timeout: 1) + } + + func testCount() { + var referrals = Referrals.Model() + XCTAssertEqual(0, referrals.count) + referrals.claims = 1 + XCTAssertEqual(1, referrals.count) + referrals.isClaimed = true + XCTAssertEqual(2, referrals.count) + } + + func testClaims() { + var referrals = Referrals.Model() + XCTAssertEqual(0, referrals.newClaims) + referrals.claims = 2 + XCTAssertEqual(2, referrals.newClaims) + referrals.accept() + XCTAssertEqual(0, referrals.newClaims) + } +} diff --git a/EcosiaTests/Core/ReferralsTests.swift b/EcosiaTests/Core/ReferralsTests.swift new file mode 100644 index 000000000000..8cbe2c440e19 --- /dev/null +++ b/EcosiaTests/Core/ReferralsTests.swift @@ -0,0 +1,176 @@ +import XCTest +@testable import Core + +final class ReferralsTests: XCTestCase { + + var httpClientMock: HTTPClientMock! + var referrals: Referrals! + let mockURL = URL(string: "https://www.example.com")! + let okResponse = HTTPURLResponse(url: URL(string: "https://example.com")!, statusCode: 200, httpVersion: nil, headerFields: nil) + let createdResponse = HTTPURLResponse(url: URL(string: "https://www.example.com")!, statusCode: 201, httpVersion: nil, headerFields: nil) + let failureResponse = HTTPURLResponse(url: URL(string: "https://www.example.com")!, statusCode: 500, httpVersion: nil, headerFields: nil) + let notFoundResponse = HTTPURLResponse(url: URL(string: "https://www.example.com")!, statusCode: 404, httpVersion: nil, headerFields: nil) + + override func setUp() { + try? FileManager.default.removeItem(at: FileManager.user) + + httpClientMock = HTTPClientMock() + httpClientMock.data = try! Data(contentsOf: Bundle.module.url(forResource: "referrals", withExtension: "json")!) + httpClientMock.response = failureResponse + + // Force clean state + var user = User() + user.referrals = .init() + User.shared = user + + referrals = Referrals(client: httpClientMock) + } + + func testFetchCodeNotCreated() async throws { + XCTAssertNil(User.shared.referrals.code) + httpClientMock.response = okResponse + + try await referrals.refresh(createCode: false) + + XCTAssertNil(User.shared.referrals.code) + } + + func testFetchCodeCreate() async throws { + XCTAssertNil(User.shared.referrals.code) + httpClientMock.response = okResponse + + let expect = expectation(description: "") + referrals.subscribe(self) { model in + self.referrals.unsubscribe(self) + XCTAssertEqual(model.code, "MANGO-2UGicG") + XCTAssertEqual(User.shared.referrals.code, "MANGO-2UGicG") + XCTAssertEqual(model.claims, 1) + expect.fulfill() + } + try await referrals.refresh(createCode: true) + await fulfillment(of: [expect], timeout: 1) + } + + func testFetchCodeWithCodeInPlace() async throws { + User.shared.referrals.code = "Avocado" + + let codeInfo = try await referrals.fetchCode() + + XCTAssertEqual(codeInfo.code, "Avocado") + } + + func testRefreshHandlesNotFound() async throws { + User.shared.referrals.code = "MANGO-2UGicG" + XCTAssertEqual(User.shared.referrals.claims, 0) + httpClientMock.response = notFoundResponse + httpClientMock.executeBeforeResponse = { + XCTAssertEqual(self.httpClientMock.response, self.notFoundResponse) + } + try await referrals.refresh() + } + + func testRefreshHandlesNotFound_CreatesNewCode() async throws { + User.shared.referrals.code = "MANGO-2UGicG" + XCTAssertEqual(User.shared.referrals.claims, 0) + httpClientMock.response = notFoundResponse + httpClientMock.data = """ + { + "code": "NEW-CODE", + "claims": 0 + } + """.data(using: .utf8)! + try await referrals.refresh() + XCTAssertEqual(User.shared.referrals.code, "NEW-CODE") + XCTAssertEqual(User.shared.referrals.claims, 0) + } + + func testRefresh() async throws { + User.shared.referrals.code = "MANGO-2UGicG" + XCTAssertEqual(User.shared.referrals.claims, 0) + httpClientMock.response = okResponse + + let expect = expectation(description: "") + referrals.subscribe(self) { model in + self.referrals.unsubscribe(self) + XCTAssertEqual(model.code, User.shared.referrals.code) + XCTAssertEqual(User.shared.referrals.claims, 1) + expect.fulfill() + } + try await referrals.refresh() + await fulfillment(of: [expect], timeout: 1) + } + + func testClaim() async throws { + User.shared.referrals.code = "MANGO-2UGicG" + XCTAssertFalse(User.shared.referrals.isClaimed) + XCTAssertFalse(User.shared.referrals.isNewClaim) + httpClientMock.response = createdResponse + + try await referrals.claim(referrer: "MANGO-1XrUBl") + + XCTAssertTrue(User.shared.referrals.isClaimed) + XCTAssertTrue(User.shared.referrals.isNewClaim) + } + + func testFetchCodeBeforeClaim() async throws { + XCTAssertNil(User.shared.referrals.code) + httpClientMock.response = createdResponse + + try await referrals.claim(referrer: "MANGO-1XrUBl") + + XCTAssertEqual(User.shared.referrals.code, "MANGO-2UGicG") + XCTAssertTrue(User.shared.referrals.isClaimed) + XCTAssertTrue(User.shared.referrals.isNewClaim) + } + + func testCooldown() async throws { + let lastUpdate = User.shared.referrals.updated + httpClientMock.response = okResponse + + try await referrals.refresh(createCode: true) + let recentUpdate = User.shared.referrals.updated + XCTAssert(recentUpdate > lastUpdate) + + // run into cooldown + try await self.referrals.refresh(force: false) + XCTAssert(User.shared.referrals.updated == recentUpdate) + + // update with force + try await self.referrals.refresh(force: true) + XCTAssert(User.shared.referrals.updated > recentUpdate) + } + + func testRefreshCooldownOnError() async throws { + User.shared.referrals.code = "MANGO-2UGicG" + httpClientMock.response = failureResponse + let lastUpdate = User.shared.referrals.updated + + try? await referrals.refresh(force: false) + + XCTAssert(User.shared.referrals.updated > lastUpdate) + } + + func testIsRefreshingTrueWhileRefreshing() async throws { + User.shared.referrals.code = "MANGO-2UGicG" + XCTAssertEqual(User.shared.referrals.claims, 0) + httpClientMock.response = okResponse + referrals.isRefreshing = false + + httpClientMock.executeBeforeResponse = { + XCTAssertTrue(self.referrals.isRefreshing) + } + try await referrals.refresh() + + XCTAssertFalse(referrals.isRefreshing) + } + + func testRefreshCodeIsNotCalledWhenRefreshing() async throws { + User.shared.referrals.code = "MANGO-2UGicG" + XCTAssertEqual(User.shared.referrals.claims, 0) + // Set failure so that it throws if unwanted request is made + httpClientMock.response = failureResponse + + referrals.isRefreshing = true + try await referrals.refresh() + } +} diff --git a/EcosiaTests/Core/Resources/Bookmarks/export_bookmark_ecosia.html b/EcosiaTests/Core/Resources/Bookmarks/export_bookmark_ecosia.html new file mode 100644 index 000000000000..d75531e77f53 --- /dev/null +++ b/EcosiaTests/Core/Resources/Bookmarks/export_bookmark_ecosia.html @@ -0,0 +1,24 @@ + + + Bookmarks +

Bookmarks

+

+

Favorites

+

+

One +
Two +

My Folder #1

+

+

Three +

+

My Folder #2

+

+

Four +

My Subfolder #1

+

+

Five +

+

+

+

+ diff --git a/EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_chrome.html b/EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_chrome.html new file mode 100644 index 000000000000..cc5083890890 --- /dev/null +++ b/EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_chrome.html @@ -0,0 +1,21 @@ + + + +Bookmarks +

Bookmarks

+

+

Lesezeichenleiste

+

+

ecosia/ios-browser: The iOS Browser that plants trees 🌱 +
Bookmark import/export – Figma +

Ecosia

+

+

Test1

+

+

test +

+

+

+

diff --git a/EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_firefox.html b/EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_firefox.html new file mode 100644 index 000000000000..19b069fdf708 --- /dev/null +++ b/EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_firefox.html @@ -0,0 +1,20 @@ + + + + +Bookmarks +

Lesezeichen-Menü

+ +

+

Mozilla Firefox

+

+

Hilfe erhalten +
Firefox anpassen +
Machen Sie mit +
Über uns +
Hilfe und Anleitungen +

+

diff --git a/EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_safari.html b/EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_safari.html new file mode 100644 index 000000000000..4d9cc72f0efd --- /dev/null +++ b/EcosiaTests/Core/Resources/Bookmarks/import_input_bookmark_safari.html @@ -0,0 +1,38 @@ + + + + Lesezeichen +

Lesezeichen

+

Favoriten

+

+

Home

+

+

Pi-hole - pihole +
Free dynamic DNS for IPv6 +
Munzinger Online – Startseite +
GENIOS +

+

Apple

+

+

M1

+

+

[Fix] Issue while installing ruby with rbenv in M1 Mac - Prabin Poudel - Rails & Web App Developer | Freelancer +
Is Apple silicon ready? +
Übertragen von Dateien zwischen einem Mac mit Apple Chips und einem anderen Mac - Apple Support +

+

Home: Apple Support Communities +

+

Development

+

+

Kubernetes

+

+

Kubernetes Ingress using NGINX | Nic Williams +
timescale/tobs: tobs - The Observability Stack for Kubernetes. Easy install of a full observability stack into a k8s cluster with a CLI tool or Helm charts. +
Upgrading kubeadm clusters | Kubernetes +
How to Set Up an Nginx Ingress with Cert-Manager on DigitalOcean Kubernetes | DigitalOcean +
Kubernetes on Hetzner with Kubermatic KubeOne in 2021 +
Kubernetes and RBAC: Restrict user access to one namespace · Jeremie Vallee +

+

+

restic · Backups done right! + diff --git a/EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_chrome.txt b/EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_chrome.txt new file mode 100644 index 000000000000..6764d479c66d --- /dev/null +++ b/EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_chrome.txt @@ -0,0 +1 @@ +[Core.BookmarkItem.folder("Lesezeichenleiste", [Core.BookmarkItem.bookmark("ecosia/ios-browser: The iOS Browser that plants trees 🌱", "https://github.com/ecosia/ios-browser", Core.BookmarkMetadata(addedAt: Optional(2023-03-15 08:44:44 +0000), modifiedAt: nil)), Core.BookmarkItem.bookmark("Bookmark import/export – Figma", "https://www.figma.com/file/uy3Bb5k5b3JVGvKi49P7RT/Bookmark-import%2Fexport?node-id=2%3A115787&t=zansqVg8w5nbf5vD-0", Core.BookmarkMetadata(addedAt: Optional(2023-03-15 12:28:09 +0000), modifiedAt: nil)), Core.BookmarkItem.folder("Ecosia", [Core.BookmarkItem.folder("Test1", [Core.BookmarkItem.bookmark("test", "https://test.tst/", Core.BookmarkMetadata(addedAt: Optional(2023-03-15 12:34:43 +0000), modifiedAt: nil))], Core.BookmarkMetadata(addedAt: Optional(2023-03-15 12:34:32 +0000), modifiedAt: Optional(2023-03-15 12:34:43 +0000)))], Core.BookmarkMetadata(addedAt: Optional(2023-03-15 12:33:18 +0000), modifiedAt: Optional(2023-03-15 12:34:32 +0000)))], Core.BookmarkMetadata(addedAt: Optional(2023-03-09 14:18:52 +0000), modifiedAt: Optional(2023-03-15 12:33:18 +0000)))] diff --git a/EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_firefox.txt b/EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_firefox.txt new file mode 100644 index 000000000000..484c95dbd5b1 --- /dev/null +++ b/EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_firefox.txt @@ -0,0 +1 @@ +[Core.BookmarkItem.folder("Mozilla Firefox", [Core.BookmarkItem.bookmark("Hilfe erhalten", "https://support.mozilla.org/de/products/firefox", Core.BookmarkMetadata(addedAt: Optional(2021-12-02 10:41:13 +0000), modifiedAt: Optional(2021-12-02 10:41:13 +0000))), Core.BookmarkItem.bookmark("Firefox anpassen", "https://support.mozilla.org/de/kb/customize-firefox-controls-buttons-and-toolbars?utm_source=firefox-browser&utm_medium=default-bookmarks&utm_campaign=customize", Core.BookmarkMetadata(addedAt: Optional(2020-05-31 09:45:59 +0000), modifiedAt: Optional(2021-12-11 10:25:06 +0000))), Core.BookmarkItem.bookmark("Machen Sie mit", "https://www.mozilla.org/de/contribute/", Core.BookmarkMetadata(addedAt: Optional(2020-05-31 09:45:59 +0000), modifiedAt: Optional(2021-12-11 10:25:06 +0000))), Core.BookmarkItem.bookmark("Über uns", "https://www.mozilla.org/de/about/", Core.BookmarkMetadata(addedAt: Optional(2020-05-31 09:45:59 +0000), modifiedAt: Optional(2021-12-11 10:25:06 +0000))), Core.BookmarkItem.bookmark("Hilfe und Anleitungen", "https://support.mozilla.org/de/products/firefox", Core.BookmarkMetadata(addedAt: Optional(2020-05-31 09:45:59 +0000), modifiedAt: Optional(2021-12-09 17:13:46 +0000)))], Core.BookmarkMetadata(addedAt: Optional(2020-05-31 09:45:59 +0000), modifiedAt: Optional(2021-12-11 10:25:06 +0000)))] diff --git a/EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_safari.txt b/EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_safari.txt new file mode 100644 index 000000000000..d6fd65d704be --- /dev/null +++ b/EcosiaTests/Core/Resources/Bookmarks/import_output_bookmark_safari.txt @@ -0,0 +1 @@ +[Core.BookmarkItem.folder("Favoriten", [Core.BookmarkItem.folder("Home", [Core.BookmarkItem.bookmark("Pi-hole - pihole", "http://pihole.lan/admin/", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("Free dynamic DNS for IPv6", "https://dynv6.com/", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("Munzinger Online – Startseite", "https://online.munzinger.de/", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("GENIOS", "https://bib-voebb.genios.de/", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil))], Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.folder("Apple", [Core.BookmarkItem.folder("M1", [Core.BookmarkItem.bookmark("[Fix] Issue while installing ruby with rbenv in M1 Mac - Prabin Poudel - Rails & Web App Developer | Freelancer", "https://prabinpoudel.com.np/articles/fix-issue-while-installing-ruby-with-rbenv-in-m1-mac/", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("Is Apple silicon ready?", "https://isapplesiliconready.com/", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("Übertragen von Dateien zwischen einem Mac mit Apple Chips und einem anderen Mac - Apple Support", "https://support.apple.com/de-de/guide/mac-help/mchlb37e8ca7/12.0/mac/12.0", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil))], Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("Home: Apple Support Communities", "https://discussions.apple.com/index.jspa", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil))], Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.folder("Development", [Core.BookmarkItem.folder("Kubernetes", [Core.BookmarkItem.bookmark("Kubernetes Ingress using NGINX | Nic Williams", "https://www.tiredpixel.com/2021/12/06/kubernetes-ingress-using-nginx/", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("timescale/tobs: tobs - The Observability Stack for Kubernetes. Easy install of a full observability stack into a k8s cluster with a CLI tool or Helm charts.", "https://github.com/timescale/tobs", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("Upgrading kubeadm clusters | Kubernetes", "https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("How to Set Up an Nginx Ingress with Cert-Manager on DigitalOcean Kubernetes | DigitalOcean", "https://www.digitalocean.com/community/tutorials/how-to-set-up-an-nginx-ingress-with-cert-manager-on-digitalocean-kubernetes", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("Kubernetes on Hetzner with Kubermatic KubeOne in 2021", "https://www.kubermatic.com/blog/kubernetes-on-hetzner-with-kubermatic-kubeone-in-2021/", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("Kubernetes and RBAC: Restrict user access to one namespace · Jeremie Vallee", "https://jeremievallee.com/2018/05/28/kubernetes-rbac-namespace-user.html", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil))], Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil))], Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil)), Core.BookmarkItem.bookmark("restic · Backups done right!", "https://restic.net/", Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil))], Core.BookmarkMetadata(addedAt: nil, modifiedAt: nil))] diff --git a/EcosiaTests/Core/Resources/notifications.json b/EcosiaTests/Core/Resources/notifications.json new file mode 100644 index 000000000000..e882a339af9b --- /dev/null +++ b/EcosiaTests/Core/Resources/notifications.json @@ -0,0 +1 @@ +[{"id":357,"text":"Nouveau bilan des plantations tout droit du Brésil ! À visionner ici.","tracking_name":"TU22_FR","publish_date":"2020-02-03T12:44:18Z","target_url":"https://youtu.be/MpAWfmOkuWg","image_url":"https://s3.amazonaws.com/static.ecosia.org/images/TreeUpdate_ThumbnailBaner_x6PYaqr.jpg","language":"fr","level":3},{"id":356,"text":"Neues Baumpflanz-Update aus Brasilien! Für Video hier klicken","tracking_name":"TU22_DE","publish_date":"2020-02-03T12:42:49Z","target_url":"https://youtu.be/MpAWfmOkuWg","image_url":"https://s3.amazonaws.com/static.ecosia.org/images/TreeUpdate_ThumbnailBaner_girJyIZ.jpg","language":"de","level":3},{"id":355,"text":"New tree-planting update from Brazil! Watch here","tracking_name":"TU22_EN","publish_date":"2020-02-03T12:42:17Z","target_url":"https://youtu.be/MpAWfmOkuWg","image_url":"https://s3.amazonaws.com/static.ecosia.org/images/TreeUpdate_ThumbnailBaner.jpg","language":"en","level":3},{"id":347,"text":"Tutte le ricerche effettuate giovedì contribuiranno a piantare alberi in Australia! Per saperne di più","tracking_name":"IT_australia1","publish_date":"2020-01-20T16:03:10Z","target_url":"https://blog.ecosia.org/trees-for-australia/","image_url":"https://s3.amazonaws.com/static.ecosia.org/images/ausnotif_Cl5D6vA.jpg","language":"it","level":3},{"id":346,"text":"Alla sökningar som görs pÃ¥ torsdag planterar träd i Australien! Läs mer","tracking_name":"SW_australia1","publish_date":"2020-01-20T16:02:32Z","target_url":"https://blog.ecosia.org/trees-for-australia/","image_url":"https://s3.amazonaws.com/static.ecosia.org/images/ausnotif_YjEUtXg.jpg","language":"sv","level":3},{"id":345,"text":"Este jueves, ¡todas tus búsquedas ayudarán a plantar árboles en Australia!","tracking_name":"ES_australia1","publish_date":"2020-01-20T16:01:40Z","target_url":"https://blog.ecosia.org/trees-for-australia/","image_url":"https://s3.amazonaws.com/static.ecosia.org/images/ausnotif_smHbNe4.jpg","language":"es","level":3},{"id":344,"text":"Alle zoekopdrachten op donderdag zullen ervoor zorgen dat er bomen geplant worden in Australië! Meer informatie","tracking_name":"NL_australia1","publish_date":"2020-01-20T16:00:41Z","target_url":"https://blog.ecosia.org/trees-for-australia/","image_url":"https://s3.amazonaws.com/static.ecosia.org/images/ausnotif_avSY0Ke.jpg","language":"nl","level":3},{"id":360,"text":"L’importance des forêts et 3 manières de les protéger : découvrez notre vidéo.","tracking_name":"FR_IntlForestDay","publish_date":"2020-03-20T16:31:58Z","target_url":"https://youtu.be/_dWJVHIE9S8","image_url":"https://s3.amazonaws.com/static.ecosia.org/images/Notification_jsl5H96.jpg","language":"fr","level":3},{"id":359,"text":"Die Bedeutung von Wäldern und drei Wege, sie zu schützen: Video anschauen","tracking_name":"DE_IntlForestDay","publish_date":"2020-03-20T14:12:24Z","target_url":"https://youtu.be/_dWJVHIE9S8","image_url":"https://s3.amazonaws.com/static.ecosia.org/images/Notification_QVLTM7l.jpg","language":"de","level":3},{"id":358,"text":"The ' importance of forests and three ways you can protect them: watch video","tracking_name":"EN_IntlForestDay","publish_date":"2020-03-20T14:12:15Z","target_url":"https://youtu.be/_dWJVHIE9S8","image_url":"https://s3.amazonaws.com/static.ecosia.org/images/Notification_Rt0jeAh.jpg","language":"en","level":3}] diff --git a/EcosiaTests/Core/Resources/referrals.json b/EcosiaTests/Core/Resources/referrals.json new file mode 100644 index 000000000000..075c534b6aa7 --- /dev/null +++ b/EcosiaTests/Core/Resources/referrals.json @@ -0,0 +1,4 @@ +{ + "code": "MANGO-2UGicG", + "claims_count": 1 +} diff --git a/EcosiaTests/Core/SearchesCounterTests.swift b/EcosiaTests/Core/SearchesCounterTests.swift new file mode 100644 index 000000000000..3c8ddbe33adb --- /dev/null +++ b/EcosiaTests/Core/SearchesCounterTests.swift @@ -0,0 +1,37 @@ +@testable import Core +import XCTest + +final class SearchesCounterTests: XCTestCase { + override func setUp() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + func testSubscribeAndReceive() { + let expect = expectation(description: "") + let counter = SearchesCounter() + + counter.subscribeAndReceive(self) { items in + XCTAssertEqual(counter.state, User.shared.searchCount) + counter.unsubscribe(self) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testSubscribe() { + let expect = expectation(description: "") + let counter = SearchesCounter() + + counter.subscribe(self) { items in + XCTAssertEqual(counter.state, 2) + counter.unsubscribe(self) + expect.fulfill() + } + User.shared.searchCount = 2 + waitForExpectations(timeout: 1) + } +} diff --git a/EcosiaTests/Core/SingularAdNetworkHelperTests.swift b/EcosiaTests/Core/SingularAdNetworkHelperTests.swift new file mode 100644 index 000000000000..cecf57aba5c6 --- /dev/null +++ b/EcosiaTests/Core/SingularAdNetworkHelperTests.swift @@ -0,0 +1,325 @@ +import XCTest +@testable import Core + +#if os(iOS) + +class SingularAdNetworkHelperTests: XCTestCase { + let mockAppDeviceInfo = AppDeviceInfo(platform: "test", + bundleId: "com.test", + osVersion: "16.1", + deviceManufacturer: "d", + deviceModel: "e", + locale: "f", + appVersion: "0.0", + installReceipt: "h") + let mockAppDeviceInfoParameters = [ + "p": "test", + "i": "com.test", + "ve": "16.1", + "app_v": "0.0", + ] + var objectPersister: MockObjectPersister! + var timestampProvider: MockTimestampProvider! + private var singularService: MockSingularService! + var helper: SingularAdNetworkHelper! + + override func setUpWithError() throws { + objectPersister = MockObjectPersister() + timestampProvider = MockTimestampProvider(currentTimestamp: 1234567890) + singularService = MockSingularService() + helper = SingularAdNetworkHelper(skan: MockSkan.self, + objectPersister: objectPersister, + timestampProvider: timestampProvider, + singularService: singularService) + MockSkan.shouldThrowError = false + } + + override func tearDownWithError() throws { + objectPersister = nil + timestampProvider = nil + singularService = nil + helper = nil + } + + // MARK: Register for ad network + func testRegisterForAdNetwork() async throws { + try await helper.registerAppForAdNetworkAttribution() + + XCTAssertEqual(MockSkan.conversionValue, 0) + XCTAssertEqual(objectPersister.getValueFor(.firstSkanCallTimestamp) as? Int, 1234567890) + XCTAssertEqual(objectPersister.getValueFor(.lastSkanCallTimestamp) as? Int, 1234567890) + XCTAssertEqual(objectPersister.getValueFor(.conversionValue) as? Int, 0) + + XCTAssertNil(objectPersister.getValueFor(.previousFineValue)) + XCTAssertNil(objectPersister.getValueFor(.coarseValue(window: .first))) + XCTAssertNil(objectPersister.getValueFor(.previousCoarseValue(window: .first))) + XCTAssertNil(objectPersister.getValueFor(.windowLockTimestamp(window: .first))) + } + + func testDoesNotRegisterForAdNetworkGivenAleradyDonePreviously() async throws { + objectPersister.setValueFor(.firstSkanCallTimestamp, value: 1) + XCTAssertNil(MockSkan.conversionValue) + XCTAssertNil(objectPersister.getValueFor(.lastSkanCallTimestamp)) + XCTAssertNil(objectPersister.getValueFor(.conversionValue)) + + try await helper.registerAppForAdNetworkAttribution() + + XCTAssertNil(MockSkan.conversionValue) + XCTAssertNil(objectPersister.getValueFor(.lastSkanCallTimestamp)) + XCTAssertNil(objectPersister.getValueFor(.conversionValue)) + XCTAssertNil(objectPersister.getValueFor(.previousFineValue)) + XCTAssertNil(objectPersister.getValueFor(.coarseValue(window: .first))) + XCTAssertNil(objectPersister.getValueFor(.previousCoarseValue(window: .first))) + XCTAssertNil(objectPersister.getValueFor(.windowLockTimestamp(window: .first))) + } + + func testRegisterForAdNetworkHandlesError() async throws { + MockSkan.shouldThrowError = true + + try await helper.registerAppForAdNetworkAttribution() + + XCTAssertEqual(objectPersister.getValueFor(.errorCode) as? Int, 1234) + } + + // MARK: Get persisted values + func testGetPersistedValuesDictionary() { + objectPersister.setValueFor(.firstSkanCallTimestamp, value: 123) + objectPersister.setValueFor(.lastSkanCallTimestamp, value: 456) + objectPersister.setValueFor(.conversionValue, value: 2) + objectPersister.setValueFor(.coarseValue(window: .first), value: 3) + objectPersister.setValueFor(.coarseValue(window: .second), value: 4) + objectPersister.setValueFor(.coarseValue(window: .third), value: 5) + objectPersister.setValueFor(.previousFineValue, value: 6) + objectPersister.setValueFor(.previousCoarseValue(window: .first), value: 7) + objectPersister.setValueFor(.previousCoarseValue(window: .second), value: 8) + objectPersister.setValueFor(.previousCoarseValue(window: .third), value: 9) + objectPersister.setValueFor(.windowLockTimestamp(window: .first), value: 10) + objectPersister.setValueFor(.windowLockTimestamp(window: .second), value: 11) + objectPersister.setValueFor(.windowLockTimestamp(window: .third), value: 12) + objectPersister.setValueFor(.errorCode, value: 1234) + + let dictionary = helper.persistedValuesDictionary + + XCTAssertEqual(dictionary["skan_first_call_to_skadnetwork_timestamp"], "123") + XCTAssertEqual(dictionary["skan_last_call_to_skadnetwork_timestamp"], "456") + XCTAssertEqual(dictionary["skan_current_conversion_value"], "2") + XCTAssertEqual(dictionary["p0_coarse"], "3") + XCTAssertEqual(dictionary["p1_coarse"], "4") + XCTAssertEqual(dictionary["p2_coarse"], "5") + XCTAssertEqual(dictionary["prev_fine_value"], "6") + XCTAssertEqual(dictionary["p0_prev_coarse_value"], "7") + XCTAssertEqual(dictionary["p1_prev_coarse_value"], "8") + XCTAssertEqual(dictionary["p2_prev_coarse_value"], "9") + XCTAssertEqual(dictionary["p0_window_lock"], "10") + XCTAssertEqual(dictionary["p1_window_lock"], "11") + XCTAssertEqual(dictionary["p2_window_lock"], "12") + XCTAssertEqual(dictionary["_skerror"], "1234") + } + + // MARK: Fetch and update from server + func testUpdateFetchedConversionValuesFromServerOnFirstWindow() async throws { + objectPersister.setValueFor(.firstSkanCallTimestamp, value: 1234567880) + objectPersister.setValueFor(.lastSkanCallTimestamp, value: 123) + objectPersister.setValueFor(.conversionValue, value: 2) + objectPersister.setValueFor(.coarseValue(window: .first), value: 3) + objectPersister.setValueFor(.previousFineValue, value: 6) + objectPersister.setValueFor(.previousCoarseValue(window: .first), value: 7) + objectPersister.setValueFor(.windowLockTimestamp(window: .first), value: 10) + singularService.responseStub = SingularConversionValueResponse(conversionValue: 50, + coarseValue: nil, + lockWindow: true) + + try await helper.fetchFromSingularServerAndUpdate(sessionIdentifier: "123", appDeviceInfo: mockAppDeviceInfo) + + XCTAssertEqual(singularService.receivedParameters, [ + "n": "__SESSION__", + "sing": "123", + "p0_coarse": "3", + "p0_prev_coarse_value": "7", + "p0_window_lock": "10", + "prev_fine_value": "6", + "skan_current_conversion_value": "2", + "skan_first_call_to_skadnetwork_timestamp": "1234567880", + "skan_last_call_to_skadnetwork_timestamp": "123", + ].merging(mockAppDeviceInfoParameters) { (current, _) in current }) + XCTAssertEqual(MockSkan.conversionValue, 50) + XCTAssertNil(MockSkan.coarseValue) + XCTAssertEqual(MockSkan.lockWindow, true) + XCTAssertEqual(objectPersister.getValueFor(.conversionValue) as? Int, 50) + XCTAssertEqual(objectPersister.getValueFor(.previousFineValue) as? Int, 2) + XCTAssertNil(objectPersister.getValueFor(.coarseValue(window: .first))) + XCTAssertEqual(objectPersister.getValueFor(.previousCoarseValue(window: .first)) as? Int, 3) + XCTAssertEqual(objectPersister.getValueFor(.windowLockTimestamp(window: .first)) as? Int, 1234567890) + } + + func testUpdateFetchedConversionValuesFromServerOnSecondWindow() async throws { + objectPersister.setValueFor(.firstSkanCallTimestamp, value: 1234387890) + objectPersister.setValueFor(.lastSkanCallTimestamp, value: 456) + objectPersister.setValueFor(.conversionValue, value: 7) + objectPersister.setValueFor(.coarseValue(window: .second), value: 5) + objectPersister.setValueFor(.previousCoarseValue(window: .second), value: 8) + objectPersister.setValueFor(.windowLockTimestamp(window: .second), value: 15) + singularService.responseStub = SingularConversionValueResponse(conversionValue: 30, + coarseValue: 2, + lockWindow: nil) + + try await helper.fetchFromSingularServerAndUpdate(sessionIdentifier: "123", appDeviceInfo: mockAppDeviceInfo) + + XCTAssertEqual(singularService.receivedParameters, [ + "n": "__SESSION__", + "sing": "123", + "p1_coarse": "5", + "p1_prev_coarse_value": "8", + "p1_window_lock": "15", + "skan_current_conversion_value": "7", + "skan_first_call_to_skadnetwork_timestamp": "1234387890", + "skan_last_call_to_skadnetwork_timestamp": "456", + ].merging(mockAppDeviceInfoParameters) { (current, _) in current }) + XCTAssertEqual(MockSkan.conversionValue, 30) + XCTAssertEqual(MockSkan.coarseValue, 2) + XCTAssertEqual(MockSkan.lockWindow, false) + XCTAssertEqual(objectPersister.getValueFor(.coarseValue(window: .second)) as? Int, 2) + XCTAssertEqual(objectPersister.getValueFor(.previousCoarseValue(window: .second)) as? Int, 5) + XCTAssertEqual(objectPersister.getValueFor(.windowLockTimestamp(window: .second)) as? Int, 15) + } + + func testUpdateFetchedConversionValuesFromServerOnThirdWindow() async throws { + objectPersister.setValueFor(.firstSkanCallTimestamp, value: 1233567890) + objectPersister.setValueFor(.lastSkanCallTimestamp, value: 789) + objectPersister.setValueFor(.conversionValue, value: 11) + objectPersister.setValueFor(.coarseValue(window: .third), value: 20) + objectPersister.setValueFor(.previousCoarseValue(window: .third), value: 23) + objectPersister.setValueFor(.windowLockTimestamp(window: .third), value: 25) + singularService.responseStub = SingularConversionValueResponse(conversionValue: 44, + coarseValue: 0, + lockWindow: false) + + try await helper.fetchFromSingularServerAndUpdate(sessionIdentifier: "123", appDeviceInfo: mockAppDeviceInfo) + + XCTAssertEqual(singularService.receivedParameters, [ + "n": "__SESSION__", + "sing": "123", + "p2_coarse": "20", + "p2_prev_coarse_value": "23", + "p2_window_lock": "25", + "skan_current_conversion_value": "11", + "skan_first_call_to_skadnetwork_timestamp": "1233567890", + "skan_last_call_to_skadnetwork_timestamp": "789", + ].merging(mockAppDeviceInfoParameters) { (current, _) in current }) + XCTAssertEqual(MockSkan.conversionValue, 44) + XCTAssertEqual(MockSkan.coarseValue, 0) + XCTAssertEqual(MockSkan.lockWindow, false) + XCTAssertEqual(objectPersister.getValueFor(.coarseValue(window: .third)) as? Int, 0) + XCTAssertEqual(objectPersister.getValueFor(.previousCoarseValue(window: .third)) as? Int, 20) + XCTAssertEqual(objectPersister.getValueFor(.windowLockTimestamp(window: .third)) as? Int, 25) + } + + func testDoesNotFetchConversionValuesFromServerOnOverWindow() async throws { + objectPersister.setValueFor(.firstSkanCallTimestamp, value: 1231542890) + + try await helper.fetchFromSingularServerAndUpdate(sessionIdentifier: "123", appDeviceInfo: mockAppDeviceInfo) + + XCTAssertNil(singularService.receivedParameters) + XCTAssertNil(MockSkan.conversionValue) + XCTAssertNil(MockSkan.coarseValue) + } + + func testErrorWhenInvalidFetchedConversionValue() async throws { + objectPersister.setValueFor(.firstSkanCallTimestamp, value: 1234567880) + singularService.responseStub = SingularConversionValueResponse(conversionValue: 64, + coarseValue: 1, + lockWindow: false) + + do { + try await helper.fetchFromSingularServerAndUpdate(sessionIdentifier: "123", appDeviceInfo: mockAppDeviceInfo) + XCTFail("Did not throw error when it should") + } catch SingularAdNetworkHelper.Error.invalidConversionValues { + // expected + } catch { + XCTFail("Received unexpected error \(error)") + } + } + + func testErrorWhenInvalidFetchedCoarseValue() async throws { + objectPersister.setValueFor(.firstSkanCallTimestamp, value: 1234567880) + singularService.responseStub = SingularConversionValueResponse(conversionValue: 1, + coarseValue: 3, + lockWindow: false) + + do { + try await helper.fetchFromSingularServerAndUpdate(sessionIdentifier: "123", appDeviceInfo: mockAppDeviceInfo) + XCTFail("Did not throw error when it should") + } catch SingularAdNetworkHelper.Error.invalidConversionValues { + // expected + } catch { + XCTFail("Received unexpected error \(error)") + } + } +} + +// MARK: SKAdNetwork Mock +class MockSkan: SKAdNetworkProtocol { + + static var conversionValue: Int? + static var coarseValue: Int? + static var lockWindow: Bool? + static var shouldThrowError = false + + static func updatePostbackConversionValue(_ conversionValue: Int) async throws { + guard !shouldThrowError else { + throw NSError(domain: "MockSkanError", code: 1234, userInfo: nil) + } + self.conversionValue = conversionValue + } + + static func updatePostbackConversionValue(_ fineValue: Int, coarseValue: Int?, lockWindow: Bool) async throws { + self.conversionValue = fineValue + self.coarseValue = coarseValue + self.lockWindow = lockWindow + } + + // Should never call this method on the latest iOS version + static func registerAppForAdNetworkAttribution() {} + + // Should never call this method on the latest iOS version + static func updateConversionValue(_ conversionValue: Int) {} +} + +// MARK: ObjectPersister Mock +class MockObjectPersister: ObjectPersister { + + var values = [String: Any]() + func setValueFor(_ object: SingularAdNetworkHelper.PersistedObject, value: Any) { + values[object.key] = value + } + func getValueFor(_ object: SingularAdNetworkHelper.PersistedObject) -> Any? { + return values[object.key] + } + + func set(_ value: Any?, forKey key: String) { + values[key] = value + } + + func object(forKey key: String) -> Any? { + return values[key] + } +} + +// MARK: SingularService Mock +private class MockSingularService: SingularServiceProtocol { + var responseStub: SingularConversionValueResponse? + + var receivedParameters: [String: String]? + func getConversionValue(request: SingularConversionValueRequest) async throws -> SingularConversionValueResponse { + receivedParameters = request.queryParameters + return responseStub! + } + + func sendNotification(request: SingularNotificationRequest) async throws { + throw NSError(domain: "SingularAdNetworkHelperTests", + code: 0, + userInfo: [NSLocalizedDescriptionKey: "Should never get called in this context"]) + } +} + +#endif diff --git a/EcosiaTests/Core/SingularServiceTests.swift b/EcosiaTests/Core/SingularServiceTests.swift new file mode 100644 index 000000000000..5e62b438cdf9 --- /dev/null +++ b/EcosiaTests/Core/SingularServiceTests.swift @@ -0,0 +1,200 @@ +@testable import Core +import XCTest + +#if os(iOS) + +class SingularServiceTests: XCTestCase { + + var httpClientMock: HTTPClientMock! + let failureResponseMock = HTTPURLResponse(url: URL(string: "https://www.example.com")!, + statusCode: 404, httpVersion: nil, headerFields: nil) + let successResponseMock = HTTPURLResponse(url: URL(string: "https://www.example.com")!, + statusCode: 200, httpVersion: nil, headerFields: nil) + var sessionInfoRequestMock: SingularSessionInfoSendRequest! + var eventRequestMock: SingularEventRequest! + var conversionValueRequestMock: SingularConversionValueRequest! + var service: SingularService! + + override func setUpWithError() throws { + httpClientMock = HTTPClientMock() + let deviceInfo = AppDeviceInfo(platform: "a", bundleId: "b", osVersion: "c", deviceManufacturer: "d", deviceModel: "e", locale: "f", country: "g", appVersion: "h") + sessionInfoRequestMock = SingularSessionInfoSendRequest(identifier: "123", info: deviceInfo, skanParameters: ["something": "test"]) + eventRequestMock = SingularEventRequest(identifier: "123", name: "some-event", info: deviceInfo) + conversionValueRequestMock = SingularConversionValueRequest(.init(identifier: "123", eventName: "c", appDeviceInfo: deviceInfo), skanParameters: ["something": "test"]) + service = SingularService(client: httpClientMock) + } + + // Since this is a generic method that supports multiple requests, we re-use the tests + // MARK: Send Notification Info + func testSessionInfoFailsOnReceivingErrorResult() async throws { + try await genericFailsOnReceivingErrorResult(sessionInfoRequestMock) + } + func testEventFailsOnReceivingErrorResult() async throws { + try await genericFailsOnReceivingErrorResult(eventRequestMock) + } + func genericFailsOnReceivingErrorResult(_ mockRequest: SingularNotificationRequest) async throws { + // given + httpClientMock.response = successResponseMock + let singularResult = SingularResponse(status: "error", errorReason: "a reason") + httpClientMock.data = try JSONEncoder().encode(singularResult) + + // when + do { + try await service.sendNotification(request: mockRequest) + } catch SingularService.Error.dataReturnedError(let reason) { + XCTAssertEqual(reason, "a reason") + } catch { + XCTFail("Received unexpected error \(error)") + } + + // then + XCTAssertEqual(httpClientMock.requests.count, 1) + XCTAssertEqual(try? httpClientMock.requests[0].makeURLRequest(), try? mockRequest.makeURLRequest()) + } + + func testSessionInfoFailsOnReceivingNoDataInResponse() async throws { + try await genericFailsOnReceivingNoDataInResponse(sessionInfoRequestMock) + } + func testEventFailsOnReceivingNoDataInResponse() async throws { + try await genericFailsOnReceivingNoDataInResponse(eventRequestMock) + } + func genericFailsOnReceivingNoDataInResponse(_ mockRequest: SingularNotificationRequest) async throws { + // given + httpClientMock.response = successResponseMock + + // when + do { + try await service.sendNotification(request: mockRequest) + } catch DecodingError.dataCorrupted { + // expected + } catch { + XCTFail("Received unexpected error \(error)") + } + + // then + XCTAssertEqual(httpClientMock.requests.count, 1) + XCTAssertEqual(try? httpClientMock.requests[0].makeURLRequest(), try? mockRequest.makeURLRequest()) + } + + func testSessionInfoReturnsDataResultOK() async throws { + try await genericReturnsDataResultOK(sessionInfoRequestMock) + } + func testEventReturnsDataResultOK() async throws { + try await genericReturnsDataResultOK(eventRequestMock) + } + func genericReturnsDataResultOK(_ mockRequest: SingularNotificationRequest) async throws { + // given + httpClientMock.response = successResponseMock + httpClientMock.data = try JSONEncoder().encode(SingularResponse(status: "ok", errorReason: nil)) + + // when + try await service.sendNotification(request: mockRequest) + + // then + XCTAssertEqual(httpClientMock.requests.count, 1) + XCTAssertEqual(try? httpClientMock.requests[0].makeURLRequest(), try? mockRequest.makeURLRequest()) + } + + func testSessionInfoNetworkError() async throws { + try await genericNetworkError(sessionInfoRequestMock) + } + func testEventNetworkError() async throws { + try await genericNetworkError(eventRequestMock) + } + func genericNetworkError(_ mockRequest: SingularNotificationRequest) async throws { + // given + httpClientMock.response = failureResponseMock + + // when + do { + // when + try await service.sendNotification(request: mockRequest) + + // then + XCTFail("Did not throw error when it should") + } catch SingularService.Error.network { + // expected + } catch { + XCTFail("Received unexpected error \(error)") + } + + // Then + XCTAssertEqual(httpClientMock.requests.count, 1) + XCTAssertEqual(try? httpClientMock.requests[0].makeURLRequest(), try? mockRequest.makeURLRequest()) + } + + // MARK: Get Conversion Value + func testGetConversionValueFailsOnFailureStatus() async throws { + // given + httpClientMock.response = failureResponseMock + + do { + // when + _ = try await service.getConversionValue(request: conversionValueRequestMock) + + // then + XCTFail("Did not throw error when it should") + } catch SingularService.Error.network { + // expected + } catch { + XCTFail("Received unexpected error \(error)") + } + } + + func testGetConversionValueReturnsResponse() async throws { + // given + httpClientMock.response = successResponseMock + let expectedResponse = SingularConversionValueResponse(conversionValue: 12, coarseValue: 1, lockWindow: true) + httpClientMock.data = try JSONEncoder().encode(expectedResponse) + + // when + let response = try await service.getConversionValue(request: conversionValueRequestMock) + + // then + XCTAssertEqual(httpClientMock.requests.count, 1) + XCTAssertEqual(try? httpClientMock.requests[0].makeURLRequest(), try? conversionValueRequestMock.makeURLRequest()) + XCTAssertEqual(response, expectedResponse) + } + + func testGetConversionDecodesFallbackResponseAndReturnsError() async throws { + // given + httpClientMock.response = successResponseMock + let expectedResponse = SingularResponse(status: "ok", errorReason: nil) + httpClientMock.data = try JSONEncoder().encode(expectedResponse) + + // when + do { + // when + _ = try await service.getConversionValue(request: conversionValueRequestMock) + + // then + XCTFail("Did not throw error when it should") + } catch SingularService.Error.noConversionValueReturned { + // expected + } catch { + XCTFail("Received unexpected error \(error)") + } + } + + func testGetConversionReturnsFallbackResponseError() async throws { + // given + httpClientMock.response = successResponseMock + let expectedResponse = SingularResponse(status: "error", errorReason: "any reason") + httpClientMock.data = try JSONEncoder().encode(expectedResponse) + + // when + do { + // when + _ = try await service.getConversionValue(request: conversionValueRequestMock) + + // then + XCTFail("Did not throw error when it should") + } catch SingularService.Error.dataReturnedError(let reason) { + XCTAssertEqual(reason, "any reason") + } catch { + XCTFail("Received unexpected error \(error)") + } + } +} + +#endif diff --git a/EcosiaTests/Core/SingularTests.swift b/EcosiaTests/Core/SingularTests.swift new file mode 100644 index 000000000000..9fc4a742a4b8 --- /dev/null +++ b/EcosiaTests/Core/SingularTests.swift @@ -0,0 +1,295 @@ +import XCTest +@testable import Core + +#if os(iOS) + +class SingularTests: XCTestCase { + + private var singularService: MockSingularService! + private var skanHelper: MockSingularAdNetworkHelper! + var singular: Singular! + + override func setUpWithError() throws { + singularService = MockSingularService() + skanHelper = MockSingularAdNetworkHelper() + singular = Singular(singularService: singularService, skanHelper: skanHelper) + } + + override func tearDownWithError() throws { + singularService = nil + skanHelper = nil + singular = nil + } + + // MARK: Public init + func testPublicInitIncludingSKAN() { + // when + singular = Singular(includeSKAN: true) + + // then + XCTAssertNotNil(singular.skanHelper) + } + + func testPublicInitWithoutSKAN() { + // when + singular = Singular(includeSKAN: false) + + // then + XCTAssertNil(singular.skanHelper) + } + + // MARK: Send session info + func testShouldSendSessionInfoWithSKAN() async throws { + // given + skanHelper.persistedValuesDictionary = MockSessionParameters.mockPersistedSkanValues + + // when + try await singular.sendSessionInfo(appDeviceInfo: MockSessionParameters.mockAppDeviceInfo) + + // then + XCTAssertFalse(skanHelper.registerAppForAdNetworkAttributionCalled) + XCTAssertEqual(skanHelper.fetchFromSingularServerAndUpdateEvent, .session) + XCTAssertNotNil(skanHelper.fetchFromSingularServerAndUpdateIdentifier) + XCTAssertEqual(skanHelper.fetchFromSingularServerAndUpdateAppDeviceInfo, MockSessionParameters.mockAppDeviceInfo) + XCTAssert(singularService.sendNotificationReceivedRequest is SingularSessionInfoSendRequest) + MockSessionParameters.assertReceivedParametersEqualToExpected(singularService.sendNotificationReceivedParameters) + } + + func testFirstSessionInfoWithSKAN() async throws { + // given + skanHelper.isRegistered = false + skanHelper.persistedValuesDictionary = MockSessionParameters.mockPersistedSkanValues + + // when + try await singular.sendSessionInfo(appDeviceInfo: MockSessionParameters.mockAppDeviceInfo) + + // then + XCTAssertTrue(skanHelper.registerAppForAdNetworkAttributionCalled) + XCTAssertNil(skanHelper.fetchFromSingularServerAndUpdateEvent) + XCTAssertNil(skanHelper.fetchFromSingularServerAndUpdateIdentifier) + XCTAssertNil(skanHelper.fetchFromSingularServerAndUpdateAppDeviceInfo) + XCTAssert(singularService.sendNotificationReceivedRequest is SingularSessionInfoSendRequest) + MockSessionParameters.assertReceivedParametersEqualToExpected(singularService.sendNotificationReceivedParameters) + } + + func testShouldSendSessionInfoWithoutSKAN() async throws { + // given + singular = Singular(singularService: singularService, skanHelper: nil) + + // when + try await singular.sendSessionInfo(appDeviceInfo: MockSessionParameters.mockAppDeviceInfo) + + // then + XCTAssertFalse(skanHelper.registerAppForAdNetworkAttributionCalled) + XCTAssertNil(skanHelper.fetchFromSingularServerAndUpdateEvent) + XCTAssertNil(skanHelper.fetchFromSingularServerAndUpdateIdentifier) + XCTAssertNil(skanHelper.fetchFromSingularServerAndUpdateAppDeviceInfo) + XCTAssert(singularService.sendNotificationReceivedRequest is SingularSessionInfoSendRequest) + MockSessionParameters.assertReceivedParametersEqualToExpected(singularService.sendNotificationReceivedParameters, includeSkan: false) + } + + func testShouldThrowSendSessionInfoError() async throws { + // given + let expectedError = NSError(domain: "test", code: 0) + singularService.sendNotificationError = expectedError + + // when + do { + try await singular.sendSessionInfo(appDeviceInfo: MockSessionParameters.mockAppDeviceInfo) + XCTFail("Did not throw expected error") + } catch { + // then + XCTAssertEqual(error as NSError, expectedError) + } + } + + // MARK: Handle SKAN errors + func testShouldNotThrowSKANRegisterError() async throws { + // given + skanHelper.isRegistered = false + skanHelper.persistedValuesDictionary = MockSessionParameters.mockPersistedSkanValues + skanHelper.registerAppForAdNetworkAttributionError = NSError(domain: "test", code: 0) + + // when + do { + try await singular.sendSessionInfo(appDeviceInfo: MockSessionParameters.mockAppDeviceInfo) + } catch { + XCTFail("No error expected, but received \(error)") + } + + // then + MockSessionParameters.assertReceivedParametersEqualToExpected(singularService.sendNotificationReceivedParameters) + } + + func testShouldNotThrowSKANServerError() async throws { + // given + skanHelper.persistedValuesDictionary = MockSessionParameters.mockPersistedSkanValues + skanHelper.fetchFromSingularServerAndUpdateError = NSError(domain: "test", code: 0) + + // when + do { + try await singular.sendSessionInfo(appDeviceInfo: MockSessionParameters.mockAppDeviceInfo) + } catch { + XCTFail("No error expected, but received \(error)") + } + + // then + MockSessionParameters.assertReceivedParametersEqualToExpected(singularService.sendNotificationReceivedParameters) + } + + // MARK: Send event + func testShouldSendEvent() async throws { + // given + let expectedEvent = MMPEvent.firstSearch + + // when + try await singular.sendEvent(expectedEvent, appDeviceInfo: MockSessionParameters.mockAppDeviceInfo) + + // then + XCTAssert(singularService.sendNotificationReceivedRequest is SingularEventRequest) + MockSessionParameters.assertReceivedParametersEqualToExpected(singularService.sendNotificationReceivedParameters, includeSkan: false, event: expectedEvent.rawValue) + } + + func testShouldThrowSendEventError() async throws { + // given + let expectedError = NSError(domain: "test", code: 0) + singularService.sendNotificationError = expectedError + + // when + do { + try await singular.sendEvent(MMPEvent.firstSearch, appDeviceInfo: MockSessionParameters.mockAppDeviceInfo) + XCTFail("Did not throw expected error") + } catch { + // then + XCTAssertEqual(error as NSError, expectedError) + } + } +} + +// MARK: SingularService Mock +private class MockSingularService: SingularServiceProtocol { + var responseStub: SingularConversionValueResponse? + + func getConversionValue(request: SingularConversionValueRequest) async throws -> SingularConversionValueResponse { + throw NSError(domain: "SingularTests", + code: 0, + userInfo: [NSLocalizedDescriptionKey: "Should never call this method directly in this context"]) + } + + var sendNotificationError: Error? + var sendNotificationReceivedRequest: SingularNotificationRequest? + var sendNotificationReceivedParameters: [String: String]? + func sendNotification(request: SingularNotificationRequest) async throws { + if let error = sendNotificationError { + throw error + } + sendNotificationReceivedRequest = request + sendNotificationReceivedParameters = request.queryParameters + } +} + +// MARK: SingularAdNetworkHelper Mock +class MockSingularAdNetworkHelper: SingularAdNetworkHelperProtocol { + var persistedValuesDictionary: [String: String] = [:] + var isRegistered: Bool = true + + var registerAppForAdNetworkAttributionError: Error? + var registerAppForAdNetworkAttributionCalled = false + func registerAppForAdNetworkAttribution() async throws { + if let error = registerAppForAdNetworkAttributionError { + throw error + } + registerAppForAdNetworkAttributionCalled = true + } + + var fetchFromSingularServerAndUpdateError: Error? + var fetchFromSingularServerAndUpdateEvent: SingularEvent? + var fetchFromSingularServerAndUpdateIdentifier: String? + var fetchFromSingularServerAndUpdateAppDeviceInfo: AppDeviceInfo? + func fetchFromSingularServerAndUpdate(forEvent event: SingularEvent, sessionIdentifier: String, appDeviceInfo: AppDeviceInfo) async throws { + if let error = fetchFromSingularServerAndUpdateError { + throw error + } + fetchFromSingularServerAndUpdateEvent = event + fetchFromSingularServerAndUpdateIdentifier = sessionIdentifier + fetchFromSingularServerAndUpdateAppDeviceInfo = appDeviceInfo + } +} + +// MARK: Parameters Mock +enum MockSessionParameters { + static let mockAppDeviceInfo = AppDeviceInfo(platform: "a", + bundleId: "b", + osVersion: "c", + deviceManufacturer: "d", + deviceModel: "e", + locale: "f", + country: "g", + appVersion: "h", + installReceipt: "i", + adServicesAttributionToken: "j") + private static let mockExpectedDeviceInfoParameters = [ + "p": "a", + "i": "b", + "ve": "c", + "ma": "d", + "mo": "e", + "lc": "f", + "country": "g", + "app_v": "h", + "install_receipt": "i", + "attribution_token": "j" + ] + private static let mockExpectedReducedDeviceInfoParameters = [ + "p": "a", + "i": "b", + "ve": "c" + ] + static let mockPersistedSkanValues = [ + SingularAdNetworkHelper.PersistedObject.conversionValue.queryKey: "test", + SingularAdNetworkHelper.PersistedObject.firstSkanCallTimestamp.queryKey: "abc", + SingularAdNetworkHelper.PersistedObject.lastSkanCallTimestamp.queryKey: "def", + SingularAdNetworkHelper.PersistedObject.coarseValue(window: .first).queryKey: "ghi", + SingularAdNetworkHelper.PersistedObject.coarseValue(window: .second).queryKey: "jkl", + SingularAdNetworkHelper.PersistedObject.coarseValue(window: .third).queryKey: "mno", + SingularAdNetworkHelper.PersistedObject.previousFineValue.queryKey: "pqr", + SingularAdNetworkHelper.PersistedObject.previousCoarseValue(window: .first).queryKey: "stu", + SingularAdNetworkHelper.PersistedObject.previousCoarseValue(window: .second).queryKey: "vxw", + SingularAdNetworkHelper.PersistedObject.previousCoarseValue(window: .third).queryKey: "yza", + SingularAdNetworkHelper.PersistedObject.windowLockTimestamp(window: .first).queryKey: "bcd", + SingularAdNetworkHelper.PersistedObject.windowLockTimestamp(window: .second).queryKey: "efg", + SingularAdNetworkHelper.PersistedObject.windowLockTimestamp(window: .third).queryKey: "hij" + ] + private static let mockExpectedSkanParameters = [ + "skan_current_conversion_value": "test", + "skan_first_call_to_skadnetwork_timestamp": "abc", + "skan_last_call_to_skadnetwork_timestamp": "def", + "p0_coarse": "ghi", + "p1_coarse": "jkl", + "p2_coarse": "mno", + "prev_fine_value": "pqr", + "p0_prev_coarse_value": "stu", + "p1_prev_coarse_value": "vxw", + "p2_prev_coarse_value": "yza", + "p0_window_lock": "bcd", + "p1_window_lock": "efg", + "p2_window_lock": "hij" + ] + + static func assertReceivedParametersEqualToExpected(_ receivedParameters: [String: String]?, includeSkan: Bool = true, event: String? = nil) { + var parameters = receivedParameters + + // Assert and remove id since it is randomly generated + XCTAssertNotNil(parameters?.removeValue(forKey: "sing")) + + let isEvent = (event != nil) + let deviceInfo = isEvent ? mockExpectedReducedDeviceInfoParameters : mockExpectedDeviceInfoParameters + let expectedParameters = deviceInfo + .merging(includeSkan ? mockExpectedSkanParameters : [:]) { (current, _) in current } + .merging(isEvent ? ["n": event!] : [:]) { (current, _) in current } + + XCTAssertEqual(parameters, expectedParameters) + } +} + +#endif diff --git a/EcosiaTests/Core/SnapshotsTests.swift b/EcosiaTests/Core/SnapshotsTests.swift new file mode 100644 index 000000000000..3368f56d5720 --- /dev/null +++ b/EcosiaTests/Core/SnapshotsTests.swift @@ -0,0 +1,94 @@ +@testable import Core +import XCTest + +final class SnapshotsTests: XCTestCase { + private var tabs: Tabs! + + override func setUp() { + tabs = .init() + try? FileManager.default.removeItem(at: FileManager.snapshots) + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.snapshots) + } + + func testNoImage() { + let expect = expectation(description: "") + tabs.image(UUID()) { + XCTAssertNil($0) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testGetImage() { + let expect = expectation(description: "") + let id = UUID() + tabs.save(.init("hello world".utf8), with: id) + tabs.queue.async { + self.tabs.image(UUID()) { + XCTAssertNil($0) + } + self.tabs.image(id) { + XCTAssertEqual("hello world", String(decoding: $0 ?? Data(), as: UTF8.self)) + expect.fulfill() + } + } + waitForExpectations(timeout: 1) + } + + func testReplaceImage() { + let expect = expectation(description: "") + let id = UUID() + tabs.save(.init("hello world".utf8), with: id) + tabs.save(.init("lorem ipsum".utf8), with: id) + tabs.queue.async { + self.tabs.image(id) { + XCTAssertEqual("lorem ipsum", String(decoding: $0 ?? Data(), as: UTF8.self)) + expect.fulfill() + } + } + waitForExpectations(timeout: 1) + } + + func testClear() { + let expect = expectation(description: "") + let idA = UUID() + let idB = UUID() + let idC = UUID() + tabs.save(.init("hello world".utf8), with: idA) + tabs.save(.init("lorem ipsum".utf8), with: idB) + tabs.save(.init("avocado".utf8), with: idC) + tabs.queue.async { + self.tabs.image(idA) { + XCTAssertNotNil($0) + self.tabs.clear() + self.tabs.image(idA) { + XCTAssertNil($0) + expect.fulfill() + } + } + } + waitForExpectations(timeout: 1) + } + + func testDelete() { + let expect = expectation(description: "") + let idA = UUID() + let idB = UUID() + tabs.save(.init("hello world".utf8), with: idA) + tabs.save(.init("lorem ipsum".utf8), with: idB) + tabs.deleteSnapshot(idA) + tabs.queue.async { + self.tabs.image(idA) { + XCTAssertNil($0) + } + self.tabs.image(idB) { + XCTAssertNotNil($0) + expect.fulfill() + } + } + waitForExpectations(timeout: 1) + } +} diff --git a/EcosiaTests/Core/StatisticsTests.swift b/EcosiaTests/Core/StatisticsTests.swift new file mode 100644 index 000000000000..d49213217b6a --- /dev/null +++ b/EcosiaTests/Core/StatisticsTests.swift @@ -0,0 +1,41 @@ +@testable import Core +import XCTest + +final class StatisticsTests: XCTestCase { + private var statistics: Statistics! + private var mockURLSession: MockURLSessionProtocol! + + override func setUp() { + statistics = Statistics.shared + mockURLSession = MockURLSessionProtocol() + } + + func testFetchAndUpdate() async throws { + mockURLSession.data = Data(""" + { + "results": [ + {"name": "Total Trees Planted", "value": "123456789", "last_updated": "2023-08-01T11:40:00.000000Z"}, + {"name": "Time per tree (seconds)", "value": "0.8"}, + {"name": "Searches per tree", "value": "20"}, + {"name": "Active Users", "value": "80000000"}, + {"name": "EUR=>USD", "value": "1.5"}, + {"name": "Some other name", "value": "123"}, + {"name": "Investments amount per second", "value": "0.423", "last_updated": null}, + {"name": "Total investments amount", "value": "2345678", "last_updated": "2023-07-30T00:00:00.000000Z"} + ] + } + """.utf8) + + try await statistics.fetchAndUpdate(urlSession: mockURLSession) + + XCTAssertEqual(statistics.treesPlanted, 123456789) + XCTAssertEqual(statistics.treesPlantedLastUpdated, Date(timeIntervalSince1970: 1690890000)) + XCTAssertEqual(statistics.timePerTree, 0.8) + XCTAssertEqual(statistics.searchesPerTree, 20) + XCTAssertEqual(statistics.activeUsers, 80000000) + XCTAssertEqual(statistics.eurToUsdMultiplier, 1.5) + XCTAssertEqual(statistics.investmentPerSecond, 0.423) + XCTAssertEqual(statistics.totalInvestments, 2345678) + XCTAssertEqual(statistics.totalInvestmentsLastUpdated, Date(timeIntervalSince1970: 1690675200)) + } +} diff --git a/EcosiaTests/Core/TabsTests.swift b/EcosiaTests/Core/TabsTests.swift new file mode 100644 index 000000000000..3ce3d284a81a --- /dev/null +++ b/EcosiaTests/Core/TabsTests.swift @@ -0,0 +1,221 @@ +@testable import Core +import XCTest + +final class TabsTests: XCTestCase { + override func setUp() { + try? FileManager.default.removeItem(at: FileManager.pages) + try? FileManager.default.removeItem(at: FileManager.snapshots) + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.pages) + try? FileManager.default.removeItem(at: FileManager.snapshots) + } + + func testNew() { + let tabs = Tabs() + XCTAssertTrue(tabs.items.isEmpty) + XCTAssertNil(tabs.current) + } + + func testAdd() { + let expect = expectation(description: "") + let url = URL(string: "https://www.avocado.com")! + let tabs = Tabs() + tabs.new(url) + XCTAssertEqual(url, tabs.items.first?.page?.url) + XCTAssertEqual(0, tabs.current) + PageStore.queue.async { + XCTAssertFalse(((try? Data(contentsOf: FileManager.tabs)) ?? Data()).isEmpty) + XCTAssertFalse(((try? Data(contentsOf: FileManager.currentTab)) ?? Data()).isEmpty) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testLoad() { + let expect = expectation(description: "") + let urlFirst = URL(string: "https://www.avocado.com")! + let urlSecond = URL(string: "https://www.trees.com")! + var tabs = Tabs() + tabs.new(urlFirst) + tabs.new(urlSecond) + PageStore.queue.async { + tabs = .init() + XCTAssertEqual(urlFirst, tabs.items.first?.page?.url) + XCTAssertEqual(urlSecond, tabs.items.last?.page?.url) + XCTAssertEqual(1, tabs.current) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testCurrentOutOfBounds() { + let expect = expectation(description: "") + PageStore.save(currentTab: 0) + PageStore.queue.async { + let tabs = Tabs() + XCTAssertNil(tabs.current) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testClose() { + let expect = expectation(description: "") + var tabs = Tabs() + tabs.new(URL(string: "https://www.avocado.com")!) + tabs.close(tabs.items.first!.id) + PageStore.queue.async { + tabs = .init() + XCTAssertTrue(tabs.items.isEmpty) + XCTAssertNil(tabs.current) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testCloseNotCurrent() { + let expect = expectation(description: "") + var tabs = Tabs() + let url = URL(string: "https://www.avocado.com")! + tabs.new(URL(string: "https://www.trees.com")!) + tabs.new(url) + tabs.close(tabs.items.first!.id) + PageStore.queue.async { + tabs = .init() + XCTAssertEqual(url, tabs.items.first?.page?.url) + XCTAssertEqual(1, tabs.items.count) + XCTAssertEqual(0, tabs.current) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testCloseOffsetIndex() { + let expect = expectation(description: "") + var tabs = Tabs() + tabs.new(URL(string: "https://www.something.com")!) + tabs.new(URL(string: "https://www.else.com")!) + tabs.new(URL(string: "https://www.trees.com")!) + tabs.new(URL(string: "https://www.avocado.com")!) + tabs.close(tabs.items.first!.id) + PageStore.queue.async { + tabs = .init() + XCTAssertEqual(3, tabs.items.count) + XCTAssertEqual(2, tabs.current) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testClearIndexOnClose() { + let expect = expectation(description: "") + var tabs = Tabs() + tabs.new(URL(string: "https://www.something.com")!) + tabs.new(URL(string: "https://www.else.com")!) + tabs.new(URL(string: "https://www.trees.com")!) + tabs.new(URL(string: "https://www.avocado.com")!) + tabs.close(tabs.items[3].id) + PageStore.queue.async { + tabs = .init() + XCTAssertEqual(3, tabs.items.count) + XCTAssertNil(tabs.current) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testCloseNoIndex() { + let expect = expectation(description: "") + var tabs = Tabs() + tabs.new(URL(string: "https://www.avocado.com")!) + tabs.new(URL(string: "https://www.trees.com")!) + tabs.current = nil + tabs.close(tabs.items.first!.id) + PageStore.queue.async { + tabs = .init() + XCTAssertEqual(1, tabs.items.count) + XCTAssertNil(tabs.current) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testKeepIndexOnClose() { + let expect = expectation(description: "") + var tabs = Tabs() + tabs.new(URL(string: "https://www.something.com")!) + tabs.new(URL(string: "https://www.else.com")!) + tabs.new(URL(string: "https://www.trees.com")!) + tabs.new(URL(string: "https://www.avocado.com")!) + tabs.current = 1 + tabs.close(tabs.items[3].id) + PageStore.queue.async { + tabs = .init() + XCTAssertEqual(3, tabs.items.count) + XCTAssertEqual(1, tabs.current) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testClear() { + let expect = expectation(description: "") + var tabs = Tabs() + tabs.new(URL(string: "https://www.something.com")!) + tabs.new(URL(string: "https://www.else.com")!) + tabs.clear() + PageStore.queue.async { + tabs = .init() + XCTAssertTrue(tabs.items.isEmpty) + XCTAssertNil(tabs.current) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testMaxOneWithoutPage() { + let expect = expectation(description: "") + let tabs = Tabs() + tabs.new(nil) + tabs.new(URL(string: "https://www.avocado.com")!) + tabs.new(nil) + tabs.new(nil) + PageStore.queue.async { + XCTAssertEqual(2, tabs.items.count) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testUpdatePage() { + let expect = expectation(description: "") + let url = URL(string: "https://www.avocado.com")! + let title = "hello world" + let tabs = Tabs() + tabs.new(URL(string: "https://www.some.com")!) + tabs.new(nil) + tabs.update(tabs.items.last!.id, page: .init(url: url, title: title)) + PageStore.queue.async { + XCTAssertEqual(url, tabs.items.last?.page?.url) + XCTAssertEqual(title, tabs.items.last?.page?.title) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testCloseRemoveSnapshot() { + let expect = expectation(description: "") + let tabs = Tabs() + tabs.new(URL(string: "https://www.avocado.com")!) + let id = tabs.items.first!.id + tabs.save(.init("hello world".utf8), with: id) + tabs.close(tabs.items.first!.id) + tabs.image(id) { + XCTAssertNil($0) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } +} diff --git a/EcosiaTests/Core/Tools/BookmarkFixtures.swift b/EcosiaTests/Core/Tools/BookmarkFixtures.swift new file mode 100644 index 000000000000..74e0d979f3ba --- /dev/null +++ b/EcosiaTests/Core/Tools/BookmarkFixtures.swift @@ -0,0 +1,31 @@ +import Foundation + +enum BookmarkFixtures { + enum Browser: String { + case chrome, firefox, safari + } + + case html(Browser), debugString(Browser) + + var value: String { + switch self { + case let .html(browser): + return String( + data: try! Data(contentsOf: Bundle.module.url(forResource: "import_input_bookmark_\(browser.rawValue)", withExtension: "html")!), + encoding: .utf8 + )!.trimmingCharacters(in: .newlines) + case let .debugString(browser): + return String( + data: try! Data(contentsOf: Bundle.module.url(forResource: "import_output_bookmark_\(browser.rawValue)", withExtension: "txt")!), + encoding: .utf8 + )!.trimmingCharacters(in: .newlines) + } + } + + static var ecosiaExportedHtml: String { + String( + data: try! Data(contentsOf: Bundle.module.url(forResource: "export_bookmark_ecosia", withExtension: "html")!), + encoding: .utf8 + )!.trimmingCharacters(in: .newlines) + } +} diff --git a/EcosiaTests/Core/Tools/HTTPClientMock.swift b/EcosiaTests/Core/Tools/HTTPClientMock.swift new file mode 100644 index 000000000000..39f7c0b074d2 --- /dev/null +++ b/EcosiaTests/Core/Tools/HTTPClientMock.swift @@ -0,0 +1,16 @@ +@testable import Core +import Foundation + +class HTTPClientMock: HTTPClient { + + var requests: [BaseRequest] = [] + var response: HTTPURLResponse? + var data = Data() + var executeBeforeResponse: (() -> Void)? + + func perform(_ request: BaseRequest) async throws -> (Data, HTTPURLResponse?) { + requests.append(request) + executeBeforeResponse?() + return (data, response) + } +} diff --git a/EcosiaTests/Core/Tools/MockTimestampProvider.swift b/EcosiaTests/Core/Tools/MockTimestampProvider.swift new file mode 100644 index 000000000000..f2d06570bccf --- /dev/null +++ b/EcosiaTests/Core/Tools/MockTimestampProvider.swift @@ -0,0 +1,11 @@ +import Foundation +@testable import Core + +final class MockTimestampProvider: TimestampProvider { + + var currentTimestamp: TimeInterval + + init(currentTimestamp: TimeInterval) { + self.currentTimestamp = currentTimestamp + } +} diff --git a/EcosiaTests/Core/Tools/MockURLSession.swift b/EcosiaTests/Core/Tools/MockURLSession.swift new file mode 100644 index 000000000000..45ab157b3512 --- /dev/null +++ b/EcosiaTests/Core/Tools/MockURLSession.swift @@ -0,0 +1,32 @@ +import Foundation + +final class MockURLSession: URLSession { + var data = [Data]() + var request: (() -> Void)? + var response: HTTPURLResponse? + + override init() { + super.init() + } + + override func dataTask(with: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask { + request?() + completionHandler(data.popLast(), response, nil) + return MockDataTask() + } + + override func dataTask(with: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask { + request?() + completionHandler(data.popLast(), response, nil) + return MockDataTask() + } +} + +private class MockDataTask: URLSessionDataTask { + override init() { + super.init() + } + + override func resume() { + } +} diff --git a/EcosiaTests/Core/Tools/MockURLSessionProtocol.swift b/EcosiaTests/Core/Tools/MockURLSessionProtocol.swift new file mode 100644 index 000000000000..e697a9f64487 --- /dev/null +++ b/EcosiaTests/Core/Tools/MockURLSessionProtocol.swift @@ -0,0 +1,13 @@ +import Foundation +@testable import Core + +// Needed in spite of the already existing MockURLSession +// since URLSession's async methods are not open +class MockURLSessionProtocol: URLSessionProtocol { + var data: Data? + + func data(from url: URL) async throws -> (Data, URLResponse) { + let response = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil)! + return (data!, response) + } +} diff --git a/EcosiaTests/Core/TreesProjectionTests.swift b/EcosiaTests/Core/TreesProjectionTests.swift new file mode 100644 index 000000000000..fd625a4e3226 --- /dev/null +++ b/EcosiaTests/Core/TreesProjectionTests.swift @@ -0,0 +1,34 @@ +@testable import Core +import XCTest + +final class TreesProjectionTests: XCTestCase { + private var treesProjection: TreesProjection! + + override func setUp() { + treesProjection = TreesProjection.shared + } + + func testTreesAt() { + let date = Date() + Statistics.shared.treesPlanted = 10 + Statistics.shared.treesPlantedLastUpdated = date.addingTimeInterval(-100) + Statistics.shared.timePerTree = 2 + XCTAssertEqual(Int(100/2 + 10-1), treesProjection.treesAt(date)) + } + + func testTimerIsActive() { + let timePerTree = 0.1 + Statistics.shared.timePerTree = timePerTree + + let exp = XCTestExpectation(description: "Wait for timer") + let projection = TreesProjection() + var receivedCount: Int? + projection.subscribe(self) { count in + receivedCount = count + exp.fulfill() + } + wait(for: [exp], timeout: timePerTree) + + XCTAssertNotNil(receivedCount) + } +} diff --git a/EcosiaTests/Core/URLProviderDependantTests/ProductionURLProviderTests.swift b/EcosiaTests/Core/URLProviderDependantTests/ProductionURLProviderTests.swift new file mode 100644 index 000000000000..cc1379164283 --- /dev/null +++ b/EcosiaTests/Core/URLProviderDependantTests/ProductionURLProviderTests.swift @@ -0,0 +1,22 @@ +@testable import Core +import XCTest + +final class ProductionURLProviderTests: XCTestCase { + + var urlProvider: URLProvider = .production + + func testProduction() { + XCTAssertEqual("https://www.ecosia.org", urlProvider.root.absoluteString) + } + + func testProductionURLsAreValid() { + XCTAssertNotNil(urlProvider.root) + XCTAssertNotNil(urlProvider.statistics) + XCTAssertNotNil(urlProvider.privacy) + XCTAssertNotNil(urlProvider.faq) + XCTAssertNotNil(urlProvider.terms) + XCTAssertNotNil(urlProvider.aboutCounter) + XCTAssertNotNil(urlProvider.snowplow) + XCTAssertNotNil(urlProvider.notifications) + } +} diff --git a/EcosiaTests/Core/URLProviderDependantTests/StagingURLProviderTests.swift b/EcosiaTests/Core/URLProviderDependantTests/StagingURLProviderTests.swift new file mode 100644 index 000000000000..f2a390f0817f --- /dev/null +++ b/EcosiaTests/Core/URLProviderDependantTests/StagingURLProviderTests.swift @@ -0,0 +1,22 @@ +@testable import Core +import XCTest + +final class StagingURLProviderTests: XCTestCase { + + var urlProvider: URLProvider = .staging + + func testStaging() { + XCTAssertEqual("https://www.ecosia-staging.xyz", urlProvider.root.absoluteString) + } + + func testStagingURLsAreValid() { + XCTAssertNotNil(urlProvider.root) + XCTAssertNotNil(urlProvider.statistics) + XCTAssertNotNil(urlProvider.privacy) + XCTAssertNotNil(urlProvider.faq) + XCTAssertNotNil(urlProvider.terms) + XCTAssertNotNil(urlProvider.aboutCounter) + XCTAssertNotNil(urlProvider.snowplow) + XCTAssertNotNil(urlProvider.notifications) + } +} diff --git a/EcosiaTests/Core/URLProviderDependantTests/URLProviderTests.swift b/EcosiaTests/Core/URLProviderDependantTests/URLProviderTests.swift new file mode 100644 index 000000000000..98d38834f945 --- /dev/null +++ b/EcosiaTests/Core/URLProviderDependantTests/URLProviderTests.swift @@ -0,0 +1,92 @@ +@testable import Core +import XCTest + +final class URLProviderTests: XCTestCase { + + var urlProvider: URLProvider = .staging + + func testFinancialReports() { + let def = Language.current + Language.current = .en + XCTAssertNotNil(urlProvider.financialReports) + XCTAssertEqual(urlProvider.financialReports.pathComponents.last, "ecosia-financial-reports-tree-planting-receipts") + + Language.current = .fr + XCTAssertNotNil(urlProvider.financialReports) + XCTAssertEqual(urlProvider.financialReports.pathComponents.last, "rapports-financiers-recus-de-plantations-arbres") + + Language.current = .de + XCTAssertNotNil(urlProvider.financialReports) + XCTAssertEqual(urlProvider.financialReports.pathComponents.last, "ecosia-finanzberichte-baumplanzbelege") + + Language.current = def + } + + func testBlog() { + let def = Language.current + Language.current = .en + XCTAssertNotNil(urlProvider.blog) + XCTAssertEqual(urlProvider.blog.absoluteString, "https://blog.ecosia.org/") + + Language.current = .fr + XCTAssertNotNil(urlProvider.blog) + XCTAssertEqual(urlProvider.blog.absoluteString, "https://fr.blog.ecosia.org/") + + Language.current = .de + XCTAssertNotNil(urlProvider.blog) + XCTAssertEqual(urlProvider.blog.absoluteString, "https://de.blog.ecosia.org/") + + Language.current = def + } + + func testTrees() { + let def = Language.current + Language.current = .en + XCTAssertNotNil(urlProvider.trees) + XCTAssertTrue(urlProvider.trees.absoluteString.hasSuffix("tag/where-does-ecosia-plant-trees/")) + + Language.current = .fr + XCTAssertNotNil(urlProvider.trees) + XCTAssertTrue(urlProvider.trees.absoluteString.hasSuffix("tag/projets/")) + + Language.current = .de + XCTAssertNotNil(urlProvider.trees) + XCTAssertTrue(urlProvider.trees.absoluteString.hasSuffix("tag/projekte/")) + + Language.current = def + } + + func testBetaProgram() { + let def = Language.current + Language.current = .en + XCTAssertNotNil(urlProvider.betaProgram) + XCTAssertEqual(urlProvider.betaProgram.absoluteString, "https://ecosia.typeform.com/to/EeMLqL3X") + + Language.current = .fr + XCTAssertNotNil(urlProvider.betaProgram) + XCTAssertEqual(urlProvider.betaProgram.absoluteString, "https://ecosia.typeform.com/to/oaFZzT0F") + + Language.current = .de + XCTAssertNotNil(urlProvider.betaProgram) + XCTAssertEqual(urlProvider.betaProgram.absoluteString, "https://ecosia.typeform.com/to/catmFLuA") + + Language.current = def + } + + func testBetaFeedback() { + let def = Language.current + Language.current = .en + XCTAssertNotNil(urlProvider.betaFeedback) + XCTAssertEqual(urlProvider.betaFeedback.absoluteString, "https://ecosia.typeform.com/to/LlUGlFT9") + + Language.current = .fr + XCTAssertNotNil(urlProvider.betaFeedback) + XCTAssertEqual(urlProvider.betaFeedback.absoluteString, "https://ecosia.typeform.com/to/PRw7550n") + + Language.current = .de + XCTAssertNotNil(urlProvider.betaFeedback) + XCTAssertEqual(urlProvider.betaFeedback.absoluteString, "https://ecosia.typeform.com/to/pIQ3uwp9") + + Language.current = def + } +} diff --git a/EcosiaTests/Core/URLRequestTests.swift b/EcosiaTests/Core/URLRequestTests.swift new file mode 100644 index 000000000000..0784defa0df6 --- /dev/null +++ b/EcosiaTests/Core/URLRequestTests.swift @@ -0,0 +1,13 @@ +import XCTest +@testable import Core + +final class URLRequestTests: XCTestCase { + + func testAddLanguageRegionHeader() { + var request = URLRequest(url: URL(string: "https://www.ecosia.org/search")!) + request.addLanguageRegionHeader() + + let dashedLanguageAndRegion = Locale.current.identifier.replacingOccurrences(of: "_", with: "-").lowercased() + XCTAssertEqual(request.value(forHTTPHeaderField: "x-ecosia-app-language-region"), dashedLanguageAndRegion) + } +} diff --git a/EcosiaTests/Core/URLTests.swift b/EcosiaTests/Core/URLTests.swift new file mode 100644 index 000000000000..aa758847b92b --- /dev/null +++ b/EcosiaTests/Core/URLTests.swift @@ -0,0 +1,179 @@ +@testable import Core +import XCTest + +final class URLTests: XCTestCase { + + private var root: String! + var urlProvider: URLProvider = .production + + override func setUp() { + root = "\(urlProvider.root.scheme!)" + "://" + urlProvider.root.host! + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + func testSearchUrl() { + let expect = expectation(description: "") + let suffix = "&tt=iosapp" + User.queue.async { + XCTAssertEqual(self.root + "/search?q=somefakesitecom" + suffix, URL.ecosiaSearchWithQuery("somefakesitecom", urlProvider: self.urlProvider).absoluteString) + XCTAssertEqual(self.root + "/search?q=some%20fakes%20ite.com" + suffix, URL.ecosiaSearchWithQuery("some fakes ite.com", urlProvider: self.urlProvider).absoluteString) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testEncodedQuery() { + let expect = expectation(description: "") + User.queue.async { + XCTAssertEqual(self.root + "/search?q=Paul+Coffee%3DGood,%20right?&tt=iosapp", URL.ecosiaSearchWithQuery("Paul+Coffee=Good, right?", urlProvider: self.urlProvider).absoluteString) + XCTAssertEqual(self.root + "/search?q=Hello%20THEre!&tt=iosapp", URL.ecosiaSearchWithQuery("Hello THEre!", urlProvider: self.urlProvider).absoluteString) + XCTAssertEqual(self.root + "/search?q=quinney%20for%20%20president&tt=iosapp", URL.ecosiaSearchWithQuery("quinney for president", urlProvider: self.urlProvider).absoluteString) + XCTAssertEqual(self.root + "/search?q=+?%25&tt=iosapp", URL.ecosiaSearchWithQuery("+?%", urlProvider: self.urlProvider).absoluteString) + XCTAssertEqual(self.root + "/search?q=Hello%2520THEre%2521&tt=iosapp", URL.ecosiaSearchWithQuery("Hello%20THEre%21", urlProvider: self.urlProvider).absoluteString) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testAvoidEcosifyWrongScheme() { + let ecosified = URL(string: "gmsg://ecosia.org")!.ecosified(isIncognitoEnabled: false) + XCTAssertEqual(ecosified, URL(string: "gmsg://ecosia.org")) + } + + func testDontEcosifyIfNotEcosia() { + let ecosified = URL(string: "https://guacamole.org")!.ecosified(isIncognitoEnabled: false) + XCTAssertEqual(ecosified, URL(string: "https://guacamole.org")) + } + + func testPolicyAllow() { + XCTAssertEqual(.allow, URL(string: "ecosia.org")!.policy) + XCTAssertEqual(.allow, URL(string: "http://ecosia.org")!.policy) + XCTAssertEqual(.allow, URL(string: "http://www.ecosia.org")!.policy) + XCTAssertEqual(.allow, URL(string: "https://www.ecosia.org")!.policy) + XCTAssertEqual(.allow, URL(string: "ecosia://ecosia.org")!.policy) + XCTAssertEqual(.allow, URL(string: "maps://ecosia.org")!.policy) + } + + func testPolicyCancel() { + XCTAssertEqual(.cancel, URL(string: "gmsg://mobileads.google.com/appEvent?name=sitedefault&info=true&google.afma.Notify_dt=1625136586354")!.policy) + XCTAssertEqual(.cancel, URL(string: "gmsg://mobileads.google.com")!.policy) + XCTAssertEqual(.cancel, URL(string: "gmsg://something")!.policy) + XCTAssertEqual(.cancel, URL(string: "gmsg://")!.policy) + } + + func testPatchWithAnalyticsId() { + let id = UUID() + User.shared.sendAnonymousUsageData = true + User.shared.cookieConsentValue = "a" + User.shared.analyticsId = id + + let domain = URL(string: "https://ecosia.org")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(domain, URL(string: "https://ecosia.org?_sp=\(id.uuidString)")) + + let search = URL(string: "https://www.www.ecosia.org/search?q=foo")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(search, URL(string: "https://www.www.ecosia.org/search?q=foo&_sp=\(id.uuidString)")) + + let alreadyPatched = URL(string: "https://www.www.ecosia.org/search?q=foo&_sp=12345")!.ecosified(isIncognitoEnabled: false) + XCTAssertEqual(alreadyPatched, URL(string: "https://www.www.ecosia.org/search?q=foo&_sp=12345")) + + let multiPatch = URL(string: "https://ecosia.org")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(multiPatch, URL(string: "https://ecosia.org?_sp=\(id.uuidString)")) + } + + func testPatchWithNULLAnalyticsId() { + let id = UUID() + User.shared.sendAnonymousUsageData = false + User.shared.analyticsId = id + + let domain = URL(string: "https://ecosia.org")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(domain, URL(string: "https://ecosia.org?_sp=\(UUID(uuid: UUID_NULL).uuidString)")) + + let search = URL(string: "https://www.www.ecosia.org/search?q=foo")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(search, URL(string: "https://www.www.ecosia.org/search?q=foo&_sp=\(UUID(uuid: UUID_NULL).uuidString)")) + + let multiPatch = URL(string: "https://ecosia.org")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(multiPatch, URL(string: "https://ecosia.org?_sp=\(UUID(uuid: UUID_NULL).uuidString)")) + } + + func testURLEcosifiedInIncognitoMode() { + let domain = URL(string: "https://ecosia.org")!.ecosified(isIncognitoEnabled: true, urlProvider: self.urlProvider) + XCTAssertEqual(domain, URL(string: "https://ecosia.org?_sp=\(UUID(uuid: UUID_NULL).uuidString)")) + } + + func testURLEcosifiedWithAnonymousUsageDataToggleOFF() { + User.shared.sendAnonymousUsageData = false + let domain = URL(string: "https://ecosia.org")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(domain, URL(string: "https://ecosia.org?_sp=\(UUID(uuid: UUID_NULL).uuidString)")) + } + + func testURLEcosifiedWithRejectedAnalyticsCookies() { + User.shared.cookieConsentValue = "e" + let domain = URL(string: "https://ecosia.org")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(domain, URL(string: "https://ecosia.org?_sp=\(UUID(uuid: UUID_NULL).uuidString)")) + } + + func testURLEcosifiedWithAnonymousUsageDataToggleOFFButRejectedAnalyticsCookies() { + User.shared.sendAnonymousUsageData = false + User.shared.cookieConsentValue = "e" + let domain = URL(string: "https://ecosia.org")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(domain, URL(string: "https://ecosia.org?_sp=\(UUID(uuid: UUID_NULL).uuidString)")) + } + + func testURLEcosifiedWithAnonymousUsageDataToggleONAndRejectedAnalyticsCookies() { + User.shared.sendAnonymousUsageData = true + User.shared.cookieConsentValue = "e" + let domain = URL(string: "https://ecosia.org")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(domain, URL(string: "https://ecosia.org?_sp=\(UUID(uuid: UUID_NULL).uuidString)")) + } + + func testEcosify() { + User.shared.sendAnonymousUsageData = true + User.shared.cookieConsentValue = "a" + let ecosified = URL(string: "https://ecosia.org")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(ecosified, URL(string: "https://ecosia.org?_sp=\(User.shared.analyticsId.uuidString)")) + } + + func testEcosifyWithNULLAnalyticsID() { + User.shared.sendAnonymousUsageData = false + let ecosified = URL(string: "https://ecosia.org")!.ecosified(isIncognitoEnabled: false, urlProvider: self.urlProvider) + XCTAssertEqual(ecosified, URL(string: "https://ecosia.org?_sp=\(UUID(uuid: UUID_NULL).uuidString)")) + } + + func testAssertIsNotEcosiaSearchURLOnNonEcosiaURL() { + let nonEcosiaURL = URL(string: "https://www.non-ecosia.com/search")! + XCTAssertFalse(nonEcosiaURL.isEcosiaSearchQuery(urlProvider)) + } + + func testAssertIsNotEcosiaSearchURLOnNonEcosiaSearchQueryURL() { + let nonSearchEcosiaURL = URL(string: "https://www.ecosia.org/example")! + XCTAssertFalse(nonSearchEcosiaURL.isEcosiaSearchQuery(urlProvider)) + } + + func testAssertIsEcosiaSearchURLOnEcosiaSearchQueryURL() { + let searchEcosiaURL = URL(string: "https://www.ecosia.org/search")! + XCTAssertTrue(searchEcosiaURL.isEcosiaSearchQuery(urlProvider)) + } + + func testAssertShouldEcosifyOnNonEcosiaURL() { + let nonSearchEcosiaURL = URL(string: "https://www.google.com")! + XCTAssertFalse(nonSearchEcosiaURL.shouldEcosify(urlProvider)) + } + + func testAssertShouldEcosifyOnAllEcosiaURLs() { + let ecosiaURLs = [ + "https://ecosia.org", + "https://www.ecosia.org/search?q=foo", + "https://ecosia.org/image?q=test", + "https://ecosia.org/chat?q=test", + "https://ecosia.org/news?q=test", + "https://blog.ecosia.org/", + "https://www.ecosia.org/settings" + ] + ecosiaURLs.forEach { urlString in + XCTAssertTrue(URL(string: urlString)!.shouldEcosify(urlProvider)) + } + } +} diff --git a/EcosiaTests/Core/UnleashFeatureManagementSessionInitializerTests.swift b/EcosiaTests/Core/UnleashFeatureManagementSessionInitializerTests.swift new file mode 100644 index 000000000000..bb5e6a3db008 --- /dev/null +++ b/EcosiaTests/Core/UnleashFeatureManagementSessionInitializerTests.swift @@ -0,0 +1,84 @@ +import XCTest +import Foundation +@testable import Core + +class UnleashFeatureManagementSessionInitializerTests: XCTestCase { + + // MARK: - Test Mocks + + class MockHTTPClient: HTTPClient { + + var performCalled = false + var performRequest: BaseRequest? + var performResult: HTTPClient.Result? + var performError: Error? + + func perform(_ request: BaseRequest) async throws -> HTTPClient.Result { + performCalled = true + performRequest = request + + if let error = performError { + throw error + } + + return performResult ?? (Data(), HTTPURLResponse()) + } + } + + // MARK: - Test Cases + + func testInitializeSession_WithValidData_ReturnsDecodedObject() async throws { + // Arrange + let client = MockHTTPClient() + let request = UnleashTests.stagingUnleashRequest + let expectedData = "{\"etag\": \"a-etag\"}".data(using: .utf8)! + let expectedResponse = HTTPURLResponse(url: URL(string: "https://ecosia.org")!, statusCode: 200, httpVersion: nil, headerFields: ["etag": "a-etag"])! + let model = try await UnleashTests.makeAvailableUnleashModel() + let initializer = UnleashFeatureManagementSessionInitializer(client: client, request: request, model: model) + + client.performResult = (expectedData, expectedResponse) + + // Act + let latestAvailableModel: Unleash.Model = try await initializer.startSession()! + + // Assert + XCTAssertTrue(client.performCalled, "The `perform` method should be called.") + XCTAssertEqual(try? client.performRequest?.makeURLRequest(), try? request.makeURLRequest(), "The request passed to the `perform` method should match the initialized request.") + XCTAssertEqual(latestAvailableModel.etag, "a-etag", "The decoded value should match the expected value.") + } + + func testInitializeSession_WithNoData_ThrowsNoDataError() async throws { + // Arrange + let client = MockHTTPClient() + let request = UnleashTests.stagingUnleashRequest + let model = try await UnleashTests.makeAvailableUnleashModel() + let initializer = UnleashFeatureManagementSessionInitializer(client: client, request: request, model: model) + + let expectedResponse = HTTPURLResponse(url: URL(string: "https://ecosia.org")!, statusCode: 200, httpVersion: nil, headerFields: nil)! + client.performResult = (Data(), expectedResponse) + + // Act & Assert + do { + let _: Unleash.Model = try await initializer.startSession()! + } catch { + XCTAssertEqual(error as? UnleashFeatureManagementSessionInitializer.Error, .noData, "The error should be `.noData`.") + } + } + + func testInitializeSession_WithNetworkError_ThrowsNetworkError() async throws { + // Arrange + let client = MockHTTPClient() + let model = try await UnleashTests.makeAvailableUnleashModel() + let initializer = UnleashFeatureManagementSessionInitializer(client: client, request: UnleashTests.stagingUnleashRequest, model: model) + + let expectedError = UnleashFeatureManagementSessionInitializer.Error.network + client.performError = expectedError + + // Act & Assert + do { + let _: Unleash.Model = try await initializer.startSession()! + } catch { + XCTAssertEqual(error as? UnleashFeatureManagementSessionInitializer.Error, expectedError, "The error should be `.network`.") + } + } +} diff --git a/EcosiaTests/Core/UnleashRefreshConfiguratorTests.swift b/EcosiaTests/Core/UnleashRefreshConfiguratorTests.swift new file mode 100644 index 000000000000..4fcdb6e17d8b --- /dev/null +++ b/EcosiaTests/Core/UnleashRefreshConfiguratorTests.swift @@ -0,0 +1,99 @@ +import Foundation + +@testable import Core +import XCTest + +final class UnleashRefreshConfiguratorTests: XCTestCase { + + override func setUp() { + Unleash.rules = [] + } + + override func tearDown() { + Unleash.rules = [] + } + + func testAppUpdateRuleCheck() async { + // Given + let configurator = UnleashRefreshConfigurator() + configurator.withAppUpdateCheckRule(appVersion: "1.0.0") + + // Simulate App Version update + Unleash.model.appVersion = "1.1.0" + + // Then + XCTAssertTrue(Unleash.shouldRefresh, "Unleash should refresh after an app update.") + } + + func testAppUpdateRuleCheckNoVersionChange() async { + // Given + let configurator = UnleashRefreshConfigurator() + configurator.withAppUpdateCheckRule(appVersion: "1.0.0") + + // Simulate no App Version update (version stays the same) + Unleash.model.appVersion = "1.0.0" + + // Then + XCTAssertFalse(Unleash.shouldRefresh, "Unleash should not refresh when app version has not changed.") + } + + func testTwentyFourHourCacheExpirationRuleMoreThan24h() async { + // Given + let mockTimestampProvider = MockTimestampProvider(currentTimestamp: Date().addingTimeInterval(TimeInterval.twentyFourHoursTimeInterval + 1).timeIntervalSince1970) + let timeRule = TimeBasedRefreshingRule(interval: TimeInterval.twentyFourHoursTimeInterval, timestampProvider: mockTimestampProvider) + Unleash.addRule(timeRule) + + // When + Unleash.model.updated = Date() + + // Then + XCTAssertTrue(Unleash.shouldRefresh, "Unleash should refresh after 24 hours.") + } + + func testTwentyFourHourCacheExpirationRuleLessThan24h() async { + // Given + let configurator = UnleashRefreshConfigurator() + configurator.withTwentyFourHoursCacheExpirationRule() + + // When + Unleash.model.updated = Date().addingTimeInterval(TimeInterval.twentyFourHoursTimeInterval - 1) + + // Then + XCTAssertFalse(Unleash.shouldRefresh, "Unleash should not refresh if less than 24 hours have passed.") + } + + func testDeviceRegionUpdateCheckWithNoDeviceRegionChange() async { + // Given + let configurator = UnleashRefreshConfigurator() + configurator.withDeviceRegionUpdateCheckRule(localeProvider: MockLocale("us")) + + // When + Unleash.model.deviceRegion = "us" + + // Then + XCTAssertFalse(Unleash.shouldRefresh, "Unleash should not refresh when the device region has not changed.") + } + + func testDeviceRegionUpdateCheckWithDeviceRegionChange() async { + // Given + let configurator = UnleashRefreshConfigurator() + configurator.withDeviceRegionUpdateCheckRule(localeProvider: MockLocale("us")) + + // When + Unleash.model.deviceRegion = "uk" + + // Then + XCTAssertTrue(Unleash.shouldRefresh, "Unleash should refresh after a device region change.") + } +} + +extension UnleashRefreshConfiguratorTests { + + struct MockLocale: RegionLocatable { + var regionIdentifierLowercasedWithFallbackValue: String + + init(_ identifier: String) { + self.regionIdentifierLowercasedWithFallbackValue = identifier + } + } +} diff --git a/EcosiaTests/Core/UnleashTests.swift b/EcosiaTests/Core/UnleashTests.swift new file mode 100644 index 000000000000..3ae7dd3b269f --- /dev/null +++ b/EcosiaTests/Core/UnleashTests.swift @@ -0,0 +1,257 @@ +@testable import Core +import XCTest + +final class UnleashTests: XCTestCase { + + static let appVersion = "0.0.0" + + override func setUp() { + Unleash.rules = [] + try? FileManager.default.removeItem(at: FileManager.unleash) + } + + override func tearDown() { + Unleash.rules = [] + try? FileManager.default.removeItem(at: FileManager.unleash) + } + + func testSaveAndLoadFromCache() async throws { + var model = Unleash.Model() + let toggle = Unleash.Toggle(name: Unleash.Toggle.Name.configTest.rawValue, + enabled: true, + variant: .init(name: "control", enabled: true, payload: nil)) + model.toggles.insert(toggle) + try await Unleash.save(model) + + let loaded = await Unleash.load() + Unleash.model = loaded! + + XCTAssertTrue(Unleash.isEnabled(.configTest)) + XCTAssertTrue(Unleash.getVariant(.configTest).name == "control") + XCTAssertTrue(Unleash.getVariant(.configTest).enabled) + } + + func testReset() async throws { + let model = try await Unleash.start(env: .staging, appVersion: Self.appVersion) + let resetModel = try await Unleash.reset(env: .staging, appVersion: Self.appVersion) + + XCTAssertNotEqual(model.id, resetModel.id) + } + + func testMakeURL() { + let base = URL(string: "https://ecosia.org")! + let context = ["foo": "bar"] + var request = UnleashTests.stagingUnleashRequest + request.queryParameters = context + let url = request.baseURL + + XCTAssertTrue(url.absoluteString.hasPrefix(base.absoluteString)) + XCTAssertEqual(URLComponents(string: try request.makeURLRequest().url!.absoluteString)?.queryItems?.count, 1) + } + + func testMakeRequest() { + let stagingRequest = try! UnleashTests.stagingUnleashRequest.makeURLRequest() + XCTAssertNotNil(stagingRequest.value(forHTTPHeaderField: CloudflareKeyProvider.clientId)) + XCTAssertNotNil(stagingRequest.value(forHTTPHeaderField: CloudflareKeyProvider.clientSecret)) + XCTAssertNotNil(stagingRequest.value(forHTTPHeaderField: "If-None-Match")) + + let prodRequest = try! UnleashTests.prodUnleashRequest.makeURLRequest() + XCTAssertNil(prodRequest.value(forHTTPHeaderField: CloudflareKeyProvider.clientId)) + XCTAssertNil(prodRequest.value(forHTTPHeaderField: CloudflareKeyProvider.clientSecret)) + XCTAssertNotNil(stagingRequest.value(forHTTPHeaderField: "If-None-Match")) + } + + func testConfigTestEnabled() { + + let expectedEnabledStatus = true + let toggleName: Unleash.Toggle.Name = .configTest + let exampleToggle = Unleash.Toggle(name: toggleName.rawValue, + enabled: expectedEnabledStatus, + variant: Unleash.Variant(name: "", enabled: false, payload: nil)) + + let mockModel = Unleash.Model(toggles: Set([exampleToggle])) + + Unleash.model = mockModel + + let isEnabled = Unleash.isEnabled(toggleName) + + XCTAssertEqual(isEnabled, expectedEnabledStatus) + } +} + +extension UnleashTests { + + static func makeAvailableUnleashModel() async throws -> Unleash.Model { + try await Unleash.start(client: MockOKHTTPClient(), request: UnleashTests.stagingUnleashRequest, env: .staging, appVersion: Self.appVersion) + } +} + +extension UnleashTests { + + struct MockOKHTTPClient: HTTPClient { + + func perform(_ request: BaseRequest) async throws -> HTTPClient.Result { + let url = URL(string: "https://ecosia.org")! + let okResponse = HTTPURLResponse(url: url, statusCode: 200, httpVersion: nil, headerFields: nil) + let model = Unleash.Model(id: UUID(), toggles: [], updated: Date(), etag: "a-etag") + let modelData = try JSONEncoder().encode(model) + return (modelData, okResponse) + } + } +} + +extension UnleashTests { + + static var stagingUnleashRequest = MockStagingUnleashRequest(etag: "a-tag") + static var prodUnleashRequest = MockProdUnleashRequest(etag: "a-tag") + + static func mockMakeURLRequest(for url: URL, + path: String?, + queryParameters: [String: String]?, + etag: String, + method: HTTPMethod, + body: Data?, + environment: Environment) -> URLRequest { + + var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) + + if let queryParameters { + urlComponents?.queryItems = queryParameters.map({ .init(name: $0.key, value: $0.value ) }) + } + + if let path { + urlComponents?.path = path + } + + var request = URLRequest(url: urlComponents?.url ?? url) + request.httpMethod = method.rawValue + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.setValue(etag, forHTTPHeaderField: "If-None-Match") + request.cachePolicy = .reloadIgnoringLocalCacheData + request.httpBody = body + + if let auth = environment.auth { + request.setValue(auth.id, forHTTPHeaderField: CloudflareKeyProvider.clientId) + request.setValue(auth.secret, forHTTPHeaderField: CloudflareKeyProvider.clientSecret) + } + + return request + } + + struct MockStagingUnleashRequest: BaseRequest { + + var environment: Environment { + .staging + } + + var method: Core.HTTPMethod { + .get + } + + var baseURL: URL { + URL(string: "https://ecosia.org")! + } + + var path: String { + "" + } + + var etag: String + + var queryParameters: [String: String]? + + var additionalHeaders: [String: String]? { + ["If-None-Match": etag] + } + + var body: Data? + + func makeURLRequest() throws -> URLRequest { + UnleashTests.mockMakeURLRequest(for: baseURL, + path: path, + queryParameters: queryParameters, + etag: etag, + method: method, + body: body, + environment: environment) + } + } + + struct MockProdUnleashRequest: BaseRequest { + + var environment: Environment { + .production + } + + var method: Core.HTTPMethod { + .get + } + + var baseURL: URL { + URL(string: "https://ecosia.org")! + } + + var path: String { + "" + } + + var etag: String + + var queryParameters: [String: String]? + + var additionalHeaders: [String: String]? { + ["If-None-Match": etag] + } + + var body: Data? + + func makeURLRequest() throws -> URLRequest { + UnleashTests.mockMakeURLRequest(for: baseURL, + path: path, + queryParameters: queryParameters, + etag: etag, + method: method, + body: body, + environment: environment) + } + } +} + +extension UnleashTests { + + // Need two types of mocks as the `Unleash.addRule` performs a type-safe addition + + struct MockAppUpdateRule: RefreshingRule { + let shouldRefresh: Bool + } + + struct MockDeviceRegionChangeRule: RefreshingRule { + let shouldRefresh: Bool + } + + func testShouldRefreshIfAnyRuleIsTrue() async { + // Given + let rule1 = MockAppUpdateRule(shouldRefresh: false) + let rule2 = MockDeviceRegionChangeRule(shouldRefresh: true) + + // When + Unleash.addRule(rule1) + Unleash.addRule(rule2) + + // Then + XCTAssertTrue(Unleash.shouldRefresh, "Unleash should refresh if any rule returns true.") + } + + func testShouldNotRefreshIfAllRulesAreFalse() async { + // Given + let rule1 = MockAppUpdateRule(shouldRefresh: false) + let rule2 = MockDeviceRegionChangeRule(shouldRefresh: false) + + // When + Unleash.addRule(rule1) + Unleash.addRule(rule2) + + // Then + XCTAssertFalse(Unleash.shouldRefresh, "Unleash should not refresh if all rules return false.") + } +} diff --git a/EcosiaTests/Core/UpgradeTests.swift b/EcosiaTests/Core/UpgradeTests.swift new file mode 100644 index 000000000000..2b4895942f6b --- /dev/null +++ b/EcosiaTests/Core/UpgradeTests.swift @@ -0,0 +1,45 @@ +import XCTest +@testable import Core + +final class UpgradeTests: XCTestCase { + override func setUp() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + func testFrom5_3To6() { + var old = User5_3() + old.install = .init(timeIntervalSince1970: 123) + old.news = .init(timeIntervalSince1970: 456) + old.analyticsId = .init() + old.marketCode = .bg_bg + old.adultFilter = .strict + old.autoComplete = false + old.firstTime = false + old.personalized = true + old.migrated = true + old.id = "hello world" + old.treeCount = 909 + old.state[User5_3.Key.welcomeScreen.rawValue] = "\(false)" + + try! JSONEncoder().encode(old).write(to: FileManager.user, options: .atomic) + + let upgraded = User() + XCTAssertEqual(old.install, upgraded.install) + XCTAssertEqual(old.news, upgraded.news) + XCTAssertEqual(old.analyticsId, upgraded.analyticsId) + XCTAssertEqual(old.marketCode, upgraded.marketCode) + XCTAssertEqual(old.adultFilter, upgraded.adultFilter) + XCTAssertEqual(old.autoComplete, upgraded.autoComplete) + XCTAssertEqual(old.firstTime, upgraded.firstTime) + XCTAssertEqual(old.personalized, upgraded.personalized) + XCTAssertEqual(old.migrated, upgraded.migrated) + XCTAssertEqual(old.id, upgraded.id) + XCTAssertEqual(old.treeCount, upgraded.searchCount) + XCTAssertEqual(old.state, upgraded.state) + XCTAssertEqual(Referrals.Model(), upgraded.referrals) + } +} diff --git a/EcosiaTests/Core/UserStateTests.swift b/EcosiaTests/Core/UserStateTests.swift new file mode 100644 index 000000000000..5c4b2ca4b273 --- /dev/null +++ b/EcosiaTests/Core/UserStateTests.swift @@ -0,0 +1,51 @@ +@testable import Core +import XCTest + +final class UserStateTests: XCTestCase { + private var user: User! + + override func setUp() { + try? FileManager.default.removeItem(at: FileManager.user) + user = .init() + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + func testStoredState() { + let storedState = ["test": "something_stored"] + let expect = expectation(description: "") + User.shared.state = storedState + User.queue.async { + let user = User() + XCTAssertEqual(user.state, storedState) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testShouldShowImpactIntro() { + XCTAssertTrue(user.shouldShowImpactIntro) + + user.state[User.Key.impactIntro.rawValue] = "\(false)" + + XCTAssertFalse(self.user.shouldShowImpactIntro) + } + + func testHideImpactIntro() { + user.state[User.Key.impactIntro.rawValue] = "\(true)" + + user.hideImpactIntro() + + XCTAssertEqual(user.state[User.Key.impactIntro.rawValue], "\(false)") + } + + func testShowImpactIntro() { + user.state[User.Key.impactIntro.rawValue] = "\(false)" + + user.showImpactIntro() + + XCTAssertEqual(user.state[User.Key.impactIntro.rawValue], "\(true)") + } +} diff --git a/EcosiaTests/Core/UserTests.swift b/EcosiaTests/Core/UserTests.swift new file mode 100644 index 000000000000..d699de4ec167 --- /dev/null +++ b/EcosiaTests/Core/UserTests.swift @@ -0,0 +1,370 @@ +@testable import Core +import XCTest + +final class UserTests: XCTestCase { + override func setUp() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + override func tearDown() { + try? FileManager.default.removeItem(at: FileManager.user) + } + + func testFirstTime() { + let expect = expectation(description: "") + XCTAssertTrue(User.shared.firstTime) + let analyticsId = User.shared.analyticsId + User.shared.firstTime = false + User.queue.async { + let user = User() + XCTAssertEqual(analyticsId, user.analyticsId) + XCTAssertFalse(user.firstTime) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testInstall() { + let date = Date() + try? FileManager.default.removeItem(at: FileManager.user) + XCTAssertGreaterThanOrEqual(Int(User().install.timeIntervalSince1970), Int(date.timeIntervalSince1970)) + } + + func testInstallSavesAfterFirst() { + let expect = expectation(description: "") + let user = User() + User.queue.async { + XCTAssertEqual(Int(user.install.timeIntervalSince1970), Int(User().install.timeIntervalSince1970)) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testNotSavingOnLoad() { + let expect = expectation(description: "") + var user = User() + user.firstTime = false + User.shared = user + User.queue.async { + user = User() + try! FileManager.default.removeItem(at: FileManager.user) + XCTAssertFalse(user.firstTime) + User.queue.async { + XCTAssertNotNil(user) + DispatchQueue.main.async { + XCTAssertFalse(FileManager.default.fileExists(atPath: FileManager.user.path)) + expect.fulfill() + } + } + } + waitForExpectations(timeout: 1) + } + + func testAnalyticsId() { + let expect = expectation(description: "") + let id = UUID() + XCTAssertNotEqual(id, User.shared.analyticsId) + User.shared.analyticsId = id + User.queue.async { + let user = User() + XCTAssertEqual(id, user.analyticsId) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testTreeCount() { + let expect = expectation(description: "") + User.shared.searchCount = 123 + User.queue.async { + let user = User() + XCTAssertEqual(123, user.searchCount) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testAdultFilter() { + let expect = expectation(description: "") + User.shared.adultFilter = .off + User.queue.async { + let user = User() + XCTAssertEqual(.off, user.adultFilter) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testMarketCode() { + let expect = expectation(description: "") + User.shared.marketCode = .ar_sa + User.queue.async { + let user = User() + XCTAssertEqual(.ar_sa, user.marketCode) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testAutoComplete() { + let expect = expectation(description: "") + User.shared.autoComplete = false + User.queue.async { + let user = User() + XCTAssertFalse(user.autoComplete) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testState() { + let expect = expectation(description: "") + User.shared.state["lorem"] = "hello" + User.queue.async { + let user = User() + XCTAssertEqual("hello", user.state["lorem"]) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testId() { + let expect = expectation(description: "") + User.shared.id = "hello world" + User.queue.async { + let user = User() + XCTAssertEqual("hello world", user.id) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testPersonalized() { + let expect = expectation(description: "") + User.shared.personalized = true + User.queue.async { + let user = User() + XCTAssertEqual(true, user.personalized) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testSendAnonymousUsageData() { + let expect = expectation(description: "") + User.shared.sendAnonymousUsageData = false + User.queue.async { + let user = User() + XCTAssertEqual(false, user.personalized) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testSendAnonymousUsageDataDefaultsToTrue() { + let user = User() + XCTAssertEqual(true, user.sendAnonymousUsageData) + } + + func testMigrated() { + let expect = expectation(description: "") + XCTAssert(User.shared.migrated == false) + User.shared.migrated = true + User.queue.async { + let user = User() + XCTAssertEqual(true, user.migrated) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testNews() { + let expect = expectation(description: "") + XCTAssertEqual(.distantPast, User.shared.news) + User.shared.news = Date() + User.queue.async { + let user = User() + XCTAssertNotNil(user.news) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testShowTopSites() { + let expect = expectation(description: "") + XCTAssertEqual(true, User.shared.showTopSites) + User.shared.showTopSites = false + User.queue.async { + let user = User() + XCTAssertEqual(false, user.showTopSites) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testTopSitesRows() { + let expect = expectation(description: "") + XCTAssertEqual(4, User.shared.topSitesRows) + User.shared.topSitesRows = 2 + User.queue.async { + let user = User() + XCTAssertEqual(2, user.topSitesRows) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testShowClimateImpact() { + let expect = expectation(description: "") + XCTAssertEqual(true, User.shared.showClimateImpact) + User.shared.showClimateImpact = false + User.queue.async { + let user = User() + XCTAssertEqual(false, user.showClimateImpact) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testShowEcosiaNews() { + let expect = expectation(description: "") + XCTAssertEqual(true, User.shared.showEcosiaNews) + User.shared.showEcosiaNews = false + User.queue.async { + let user = User() + XCTAssertEqual(false, user.showEcosiaNews) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testShowAboutEcosia() { + let expect = expectation(description: "") + XCTAssertEqual(true, User.shared.showAboutEcosia) + User.shared.showAboutEcosia = false + User.queue.async { + let user = User() + XCTAssertEqual(false, user.showAboutEcosia) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testWhatsNewItemsVersions() { + let expect = expectation(description: "") + XCTAssertTrue(User.shared.whatsNewItemsVersionsShown.isEmpty) + User.shared.whatsNewItemsVersionsShown.formUnion(["test", "test1", "test"]) + User.queue.async { + let user = User() + XCTAssertEqual(user.whatsNewItemsVersionsShown, ["test", "test1"]) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } + + func testShowsReferralSpotlight() { + let expect = expectation(description: "") + XCTAssertFalse(User.shared.showsReferralSpotlight) + + // set install to 4 days ago + User.shared.install = Calendar.current.date(byAdding: .day, value: -4, to: .init())! + + User.queue.async { + let user = User() + XCTAssertTrue(user.showsReferralSpotlight) + + User.shared.hideReferralSpotlight() + User.queue.async { + let user = User() + XCTAssertFalse(user.showsReferralSpotlight) + expect.fulfill() + } + } + waitForExpectations(timeout: 1) + } + + func testShowsInactiveTabsTooltip() { + let expect = expectation(description: "") + XCTAssertTrue(User.shared.showsInactiveTabsTooltip) + + User.queue.async { + let user = User() + XCTAssertTrue(user.showsInactiveTabsTooltip) + + User.shared.hideInactiveTabsTooltip() + User.queue.async { + let user = User() + XCTAssertFalse(user.showsInactiveTabsTooltip) + expect.fulfill() + } + } + waitForExpectations(timeout: 1) + } + + func testShowsBookmarksImportExportTooltip() { + let expect = expectation(description: "") + User.shared.state = [:] + + XCTAssertTrue(User.shared.showsBookmarksImportExportTooltip) + + User.queue.async { + let user = User() + XCTAssertTrue(user.showsBookmarksImportExportTooltip) + + User.shared.hideBookmarksImportExportTooltip() + User.queue.async { + let user = User() + XCTAssertFalse(user.showsBookmarksImportExportTooltip) + expect.fulfill() + } + } + waitForExpectations(timeout: 1) + } + + func testCookieCounterConsent() { + let expect = expectation(description: "") + User.queue.async { + let user = User() + XCTAssertNil(user.cookieConsentValue) + User.shared.cookieConsentValue = "eamp" + User.queue.async { + let user = User() + XCTAssertEqual("eamp", user.cookieConsentValue) + expect.fulfill() + } + } + waitForExpectations(timeout: 1) + } + + func testSearchSettingChangeNotifiaction() { + let expect = expectation(description: "") + var count = 0 + + NotificationCenter.default.addObserver(forName: .searchSettingsChanged, object: nil, queue: .main) { _ in + + count += 1 + + if count == 4 { + expect.fulfill() + } + } + + User.shared.personalized = !User.shared.personalized + User.shared.marketCode = .en_ww + User.shared.autoComplete = !User.shared.autoComplete + User.shared.adultFilter = .off + + wait(for: [expect], timeout: 1) + } + + func testAnalyticsUserState() { + let expect = expectation(description: "") + User.shared.analyticsUserState = User.AnalyticsStateContext() + User.queue.async { + let user = User() + XCTAssertEqual(User.PushNotificationState.notDetermined, user.analyticsUserState.pushNotificationState) + expect.fulfill() + } + waitForExpectations(timeout: 1) + } +} diff --git a/EcosiaTests/Core/Versions/User5_3.swift b/EcosiaTests/Core/Versions/User5_3.swift new file mode 100644 index 000000000000..e4e0629f8cf5 --- /dev/null +++ b/EcosiaTests/Core/Versions/User5_3.swift @@ -0,0 +1,27 @@ +import Foundation +@testable import Core + +struct User5_3: Codable { + var install: Date? + var news: Date? + var analyticsId = UUID() + var marketCode = Local.make(for: .current) + var adultFilter = AdultFilter.moderate + var autoComplete = true + var firstTime = true + var personalized: Bool? = false + var topSites: Bool? = true + var migrated: Bool? = false + var id: String? + var treeCount = 0 + var state = [String: String]() + + init() { + install = .init() + } + + enum Key: String { + case + welcomeScreen + } +} diff --git a/Shared/UserAgent.swift b/Shared/UserAgent.swift index 269e2f692ae5..e050b451eb2b 100644 --- a/Shared/UserAgent.swift +++ b/Shared/UserAgent.swift @@ -5,8 +5,8 @@ import Common import WebKit import UIKit -// Ecosia: importing Core -import Core +// Ecosia: Import Ecosia Framework +import Ecosia open class UserAgent { public static let uaBitSafari = "Safari/605.1.15" diff --git a/Storage/DefaultSuggestedSites.swift b/Storage/DefaultSuggestedSites.swift index 0b256ae8230e..f834a3a15a30 100644 --- a/Storage/DefaultSuggestedSites.swift +++ b/Storage/DefaultSuggestedSites.swift @@ -3,8 +3,8 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -// Ecosia: Core import -import Core +// Ecosia: Import Ecosia Framework +import Ecosia open class DefaultSuggestedSites { /* Ecosia: Replace Default Suggested Sites From 3f05fd8477f7f7dcaa048c673c62da451866a5b4 Mon Sep 17 00:00:00 2001 From: Dario Carlomagno Date: Thu, 5 Dec 2024 11:55:02 +0100 Subject: [PATCH 16/59] [MOB-3028] Add Core's ADRs --- ...4-27_Architectural-decision-record-template.md | 12 ++++++++++++ ...2021-04-27_File-based-user-data-persistence.md | 12 ++++++++++++ .../adr/2_2023-06-29_Environment_as_getter.md | 13 +++++++++++++ .../Core/adr/3_2024-11-01_Analytics-Events-Tests | 15 +++++++++++++++ README.md | 12 ++++++++++++ 5 files changed, 64 insertions(+) create mode 100644 Ecosia/Core/adr/0_2021-04-27_Architectural-decision-record-template.md create mode 100644 Ecosia/Core/adr/1_2021-04-27_File-based-user-data-persistence.md create mode 100644 Ecosia/Core/adr/2_2023-06-29_Environment_as_getter.md create mode 100644 Ecosia/Core/adr/3_2024-11-01_Analytics-Events-Tests diff --git a/Ecosia/Core/adr/0_2021-04-27_Architectural-decision-record-template.md b/Ecosia/Core/adr/0_2021-04-27_Architectural-decision-record-template.md new file mode 100644 index 000000000000..1f4864f1fba6 --- /dev/null +++ b/Ecosia/Core/adr/0_2021-04-27_Architectural-decision-record-template.md @@ -0,0 +1,12 @@ +# Architectural Decison Record Template + +- In the context of: `functional requirement` (story, use case or arch. component) +- facing: `non-functional requirement` (for instance a desired quality) +- we decided: `decision outcome` (arguably the most important part) +- and neglected `alternatives not chosen` (not to be forgotten!), +- to achieve: `benefits` (the full or partial satisfaction of requirement(s)) +- accepting that: `drawbacks and other consequences` ( for instance impact on other properties/context and effort/cost (both short term and long term)). + +## Related Code + +- [Package.swift](../Package.swift) diff --git a/Ecosia/Core/adr/1_2021-04-27_File-based-user-data-persistence.md b/Ecosia/Core/adr/1_2021-04-27_File-based-user-data-persistence.md new file mode 100644 index 000000000000..b5db001de414 --- /dev/null +++ b/Ecosia/Core/adr/1_2021-04-27_File-based-user-data-persistence.md @@ -0,0 +1,12 @@ +# File based user data persistence + +- In the context of: `having persistence for user data and settings` +- facing: `loading user data via UserDefaults delayed app launch, lacked the ability to scale and were flaky in unit tests` +- we decided: `to store user data in JSON-encoded files` +- and neglected: `the use of UserDefaults` +- to achieve: `ease of use, extensibility, speed of access, consistency and predictable unit test results` +- accepting that: `we need to implement persistence (storing, loading, caching) of the json-files ourselves` + +## Related Code + +- [User.swift](../Sources/User.swift) diff --git a/Ecosia/Core/adr/2_2023-06-29_Environment_as_getter.md b/Ecosia/Core/adr/2_2023-06-29_Environment_as_getter.md new file mode 100644 index 000000000000..ae354f855451 --- /dev/null +++ b/Ecosia/Core/adr/2_2023-06-29_Environment_as_getter.md @@ -0,0 +1,13 @@ +# Environment as getter + +- In the context of: `making the Environment getter only from the Browser app` ([Jira ticket](https://ecosia.atlassian.net/browse/MOB-1817)) +- facing: `the possibility of update the Environment at any point in the app` +- we decided: `to add a PRODUCTION macro on Release only` +- and neglected `any other workaround and/or code change that would break the SOLID principles`, +- to achieve: `The smallest yet robust code changes between the Core module and the Browser app. As we know, SPM currently provides us with only .debug and .release build configurations. There are many proposals to make it "flavored" but, so far, nothing hasn't even reached beta. The way SPM chooses which configuration to pick, ironically, is purely empirical. It basically picks .debug only in case the hosting build configuration contains Development or Debug (case-insensitive). This PRODUCTION macro is being read within the Core package, and decide which Environment assign to it. Depending on the Environment a set of protocol-based URLs mimicking the older architecture is loaded in memory.` +- accepting that: `unconventionally recognised Build Configuration prefixes have been added to the TestFlight and AppCenter configs in the browser app (e.g.: Development_)` + +## Related Code + +- [Package.swift](../Package.swift) +- [Environment.swift](../Sources/Environment/Environment.swift) diff --git a/Ecosia/Core/adr/3_2024-11-01_Analytics-Events-Tests b/Ecosia/Core/adr/3_2024-11-01_Analytics-Events-Tests new file mode 100644 index 000000000000..51489c833d9b --- /dev/null +++ b/Ecosia/Core/adr/3_2024-11-01_Analytics-Events-Tests @@ -0,0 +1,15 @@ +# Analytics Events Testing + +- In the context of: `testing wether Analytics events are properly tracked troughout the app` ([Jira ticket](https://ecosia.atlassian.net/browse/MOB-2979)) +- facing: `previous issues caused by regression` +- we decided: `to unit test wherever Analytics is called, replacing our shared singleton with a "spy".` +- and neglected `following a protocol-oriented approach, which would require injecting dependencies on every class.`, +- to achieve: `decoupled tests that are easy to maintain and require no change in the classes that use Analytics.` +- accepting that: `making our shared Analytics singleton a variable brings risks and is usually a bad programming practice. To mitigate that, we also set up a SwiftLint rule that flags updating the shared instance outside tests as an error.` + +## Related Code + +- [Pull Request with Initial setup](https://github.com/ecosia/ios-browser/pull/799) +- [AnalyticsSpyTests](https://github.com/ecosia/ios-browser/blob/3bcc8af58bf24e2eb718d27f4b5fd6955db09ad8/EcosiaTests/Analytics/AnalyticsSpyTests.swift) +- [Variable Analytics shared singletion](https://github.com/ecosia/ios-browser/blob/3bcc8af58bf24e2eb718d27f4b5fd6955db09ad8/Client/Ecosia/Analytics/Analytics.swift#L22) +- [SwiftLint custom rule](https://github.com/ecosia/ios-browser/blob/3bcc8af58bf24e2eb718d27f4b5fd6955db09ad8/.swiftlint.yml#L100-L116) diff --git a/README.md b/README.md index e88af1b97216..2164325774f8 100644 --- a/README.md +++ b/README.md @@ -247,3 +247,15 @@ We built our snapshot testing setup with `SnapshotTestHelper` to streamline UI c - **Comparison**: We capture snapshots of the UI and compare them to reference images to spot any unintended changes. More details [here](SNAPSHOT_TESTING_WIKI.md) + +## Ecosia framework + +### Architectural Decision records + +Architectural Decision Records (or ADRs) are a method of documenting important decisions a software team makes, and why the decisions were made. They are similar, but complementary to RFCs (requests for comment). The purpose of ADRs is to build up a terse and easily searchable log of decisions so future generations of engineers can understand why our systems are the way they are. For more information, see the [ADR site](https://adr.github.io).\ +The are listed in numbered order in the [adr](Ecosia/Core/adr/) directory and should follow this [Y-statement-format](Ecosia/Core/adr/0_2021-04-27_Architectural-decision-record-template.md). + +#### Example + +- [1_2021-04-27_File-based-user-data-persistence.md](Ecosia/Core/adr/1_2021-04-27_File-based-user-data-persistence.md) +- [2_2023-06-29_Environment_as_getter.md](Ecosia/Core/adr/2_2023-06-29_Environment_as_getter.md) \ No newline at end of file From d264aa5b305bbd33739935eb97b071e73c8587a5 Mon Sep 17 00:00:00 2001 From: Dario Carlomagno Date: Thu, 5 Dec 2024 12:05:39 +0100 Subject: [PATCH 17/59] [MOB-3028] Remove SeedCounter's CoreData ref --- Client.xcodeproj/project.pbxproj | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index 8804cc32212b..6b5ae330b561 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -697,7 +697,6 @@ 2CD265C72CFE382C00A040A7 /* AboutEcosiaSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265682CFE382C00A040A7 /* AboutEcosiaSection.swift */; }; 2CD265C82CFE382C00A040A7 /* NTPAboutEcosiaCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265692CFE382C00A040A7 /* NTPAboutEcosiaCell.swift */; }; 2CD265C92CFE382C00A040A7 /* NTPAboutEcosiaCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2656A2CFE382C00A040A7 /* NTPAboutEcosiaCellViewModel.swift */; }; - 2CD265CA2CFE382C00A040A7 /* SeedCounter.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2656D2CFE382C00A040A7 /* SeedCounter.xcdatamodeld */; }; 2CD265CB2CFE382C00A040A7 /* SeedProgressManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2656F2CFE382C00A040A7 /* SeedProgressManagerProtocol.swift */; }; 2CD265CC2CFE382C00A040A7 /* UserDefaultsSeedProgressManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265702CFE382C00A040A7 /* UserDefaultsSeedProgressManager.swift */; }; 2CD265CD2CFE382C00A040A7 /* ArcProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD265722CFE382C00A040A7 /* ArcProgressView.swift */; }; @@ -3372,7 +3371,6 @@ 2CD265C02CFE382C00A040A7 /* LoadingScreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingScreen.swift; sourceTree = ""; }; 2CD265C12CFE382C00A040A7 /* MarketsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarketsController.swift; sourceTree = ""; }; 2CD265C22CFE382C00A040A7 /* SemanticColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SemanticColor.swift; sourceTree = ""; }; - 2CD265C42CFE382C00A040A7 /* SeedCounter.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SeedCounter.xcdatamodel; sourceTree = ""; }; 2CD266102CFE38AD00A040A7 /* EcosiaTopSiteItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaTopSiteItemCell.swift; sourceTree = ""; }; 2CD266132CFE38AD00A040A7 /* EcosiaHomepageSectionType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaHomepageSectionType.swift; sourceTree = ""; }; 2CD266162CFE38AD00A040A7 /* EcosiaDebugSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaDebugSettings.swift; sourceTree = ""; }; @@ -10184,14 +10182,6 @@ path = Account; sourceTree = ""; }; - 2CD2656E2CFE382C00A040A7 /* CoreData */ = { - isa = PBXGroup; - children = ( - 2CD2656D2CFE382C00A040A7 /* SeedCounter.xcdatamodeld */, - ); - path = CoreData; - sourceTree = ""; - }; 2CD265712CFE382C00A040A7 /* SeedProgressManager */ = { isa = PBXGroup; children = ( @@ -10204,7 +10194,6 @@ 2CD2657A2CFE382C00A040A7 /* ClimateImpactCounter */ = { isa = PBXGroup; children = ( - 2CD2656E2CFE382C00A040A7 /* CoreData */, 2CD265712CFE382C00A040A7 /* SeedProgressManager */, 2CD265722CFE382C00A040A7 /* ArcProgressView.swift */, 2CD265732CFE382C00A040A7 /* NTPSeedCounterCell.swift */, @@ -15705,7 +15694,6 @@ 2109478928AFD24C00B73D44 /* OnboardingViewControllerProtocol.swift in Sources */, D0FCF7F51FE45842004A7995 /* UserScriptManager.swift in Sources */, 8AB8573027D94CAD0075C173 /* HomepageViewModelProtocol.swift in Sources */, - 2CD265CA2CFE382C00A040A7 /* SeedCounter.xcdatamodeld in Sources */, 5A9F83422B2B796800272819 /* TabPeekState.swift in Sources */, 21E77E522AA8BE5C00FABA10 /* TabTrayFlagManager.swift in Sources */, CA8226F324C11DB7008A6F38 /* PasswordManagerTableViewCell.swift in Sources */, @@ -24784,20 +24772,6 @@ productName = Sentry; }; /* End XCSwiftPackageProductDependency section */ - -/* Begin XCVersionGroup section */ - 2CD2656D2CFE382C00A040A7 /* SeedCounter.xcdatamodeld */ = { - isa = XCVersionGroup; - children = ( - 2CD265C42CFE382C00A040A7 /* SeedCounter.xcdatamodel */, - ); - currentVersion = 2CD265C42CFE382C00A040A7 /* SeedCounter.xcdatamodel */; - name = SeedCounter.xcdatamodeld; - path = "/Users/dariocarlomagno/Workspace/ecosia/ios-browser/Client/Ecosia/UI/NTP/ClimateImpactCounter/CoreData/SeedCounter.xcdatamodeld"; - sourceTree = ""; - versionGroupType = wrapper.xcdatamodel; - }; -/* End XCVersionGroup section */ }; rootObject = F84B21B61A090F8100AAB793 /* Project object */; } From aef2abb9dbd6bcae32c79b306acf48a128bdbbe2 Mon Sep 17 00:00:00 2001 From: Dario Carlomagno Date: Thu, 5 Dec 2024 12:31:05 +0100 Subject: [PATCH 18/59] [MOB-3028] Adapt Ecosia Snapshots and Units Tests --- Client.xcodeproj/project.pbxproj | 1078 +---------------- .../xcschemes/EcosiaBeta.xcscheme | 18 +- EcosiaTests/Core/BookmarkParserTests.swift | 2 +- .../Core/BookmarkSerializerTests.swift | 2 +- EcosiaTests/Core/BookmarkTests.swift | 2 +- EcosiaTests/Core/CookieTests.swift | 2 +- EcosiaTests/Core/FavouritesTests.swift | 2 +- ...atureFlaggingSessionInitializerTests.swift | 2 +- EcosiaTests/Core/FinancialReportsTests.swift | 2 +- EcosiaTests/Core/HistoryTests.swift | 2 +- EcosiaTests/Core/ImagesTests.swift | 2 +- .../Core/InvestmentsProjectionTests.swift | 2 +- EcosiaTests/Core/LanguageTests.swift | 2 +- EcosiaTests/Core/ListTests.swift | 2 +- EcosiaTests/Core/LocalTests.swift | 2 +- EcosiaTests/Core/NewsTests.swift | 2 +- EcosiaTests/Core/PublishersTests.swift | 2 +- EcosiaTests/Core/ReferralsModelTests.swift | 2 +- EcosiaTests/Core/ReferralsTests.swift | 2 +- EcosiaTests/Core/SearchesCounterTests.swift | 2 +- .../Core/SingularAdNetworkHelperTests.swift | 2 +- EcosiaTests/Core/SingularServiceTests.swift | 2 +- EcosiaTests/Core/SingularTests.swift | 2 +- EcosiaTests/Core/SnapshotsTests.swift | 2 +- EcosiaTests/Core/StatisticsTests.swift | 2 +- EcosiaTests/Core/TabsTests.swift | 2 +- EcosiaTests/Core/Tools/HTTPClientMock.swift | 2 +- .../Core/Tools/MockTimestampProvider.swift | 2 +- .../Core/Tools/MockURLSessionProtocol.swift | 2 +- EcosiaTests/Core/TreesProjectionTests.swift | 2 +- .../ProductionURLProviderTests.swift | 2 +- .../StagingURLProviderTests.swift | 2 +- .../URLProviderTests.swift | 2 +- EcosiaTests/Core/URLRequestTests.swift | 2 +- EcosiaTests/Core/URLTests.swift | 2 +- ...ureManagementSessionInitializerTests.swift | 2 +- .../UnleashRefreshConfiguratorTests.swift | 2 +- EcosiaTests/Core/UnleashTests.swift | 2 +- EcosiaTests/Core/UpgradeTests.swift | 2 +- EcosiaTests/Core/UserStateTests.swift | 2 +- EcosiaTests/Core/UserTests.swift | 2 +- EcosiaTests/Core/Versions/User5_3.swift | 2 +- EcosiaTests/EcosiaHomeViewModelTests.swift | 2 +- EcosiaTests/EcosiaInstallTypeTests.swift | 2 +- .../EcosiaNTPTooltipHighlightTests.swift | 2 +- ...ateFeatureManagementIntegrationTests.swift | 2 +- .../WhatsNewLocalDataProviderTests.swift | 2 +- 47 files changed, 71 insertions(+), 1115 deletions(-) diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index 6b5ae330b561..9930afbd4aba 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -340,7 +340,6 @@ 2CAF5BF02D00D1AB00D3DCDD /* ReferralsModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BBC2D00D1A800D3DCDD /* ReferralsModelTests.swift */; }; 2CAF5BF12D00D1AB00D3DCDD /* HistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BBD2D00D1A800D3DCDD /* HistoryTests.swift */; }; 2CAF5BF22D00D1AB00D3DCDD /* BookmarkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BBE2D00D1A800D3DCDD /* BookmarkTests.swift */; }; - 2CAF5BF32D00D1AB00D3DCDD /* SnapshotsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BBF2D00D1A800D3DCDD /* SnapshotsTests.swift */; }; 2CAF5BF42D00D1AB00D3DCDD /* LocalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC02D00D1A800D3DCDD /* LocalTests.swift */; }; 2CAF5BF52D00D1AB00D3DCDD /* SingularAdNetworkHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC12D00D1A900D3DCDD /* SingularAdNetworkHelperTests.swift */; }; 2CAF5BF62D00D1AB00D3DCDD /* TabsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BC22D00D1A900D3DCDD /* TabsTests.swift */; }; @@ -367,272 +366,14 @@ 2CAF5C1F2D01B44400D3DCDD /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 2CAF5C1E2D01B44400D3DCDD /* Sentry */; }; 2CAF5C212D01B5F300D3DCDD /* Common in Frameworks */ = {isa = PBXBuildFile; productRef = 2CAF5C202D01B5F300D3DCDD /* Common */; }; 2CAF5C222D01B62900D3DCDD /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; + 2CAF5C232D01C2F300D3DCDD /* NTPComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261B92CFDC5E900A040A7 /* NTPComponentTests.swift */; }; + 2CAF5C242D01C30B00D3DCDD /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262862CFDC5E900A040A7 /* OnboardingTests.swift */; }; + 2CAF5C252D01C31900D3DCDD /* NTPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261BA2CFDC5E900A040A7 /* NTPTests.swift */; }; + 2CAF5C262D01C32C00D3DCDD /* Welcome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261852CFDC5E900A040A7 /* Welcome.swift */; }; + 2CAF5C272D01C33300D3DCDD /* EcosiaMockThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261842CFDC5E900A040A7 /* EcosiaMockThemeManager.swift */; }; 2CCFB3D72C0FBEE800BEDCA0 /* TabToolbarHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D815A3A724A53F3200AAB221 /* TabToolbarHelperTests.swift */; }; - 2CD262A92CFDC5EB00A040A7 /* EcosiaMockThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261842CFDC5E900A040A7 /* EcosiaMockThemeManager.swift */; }; - 2CD262AA2CFDC5EB00A040A7 /* Welcome.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261852CFDC5E900A040A7 /* Welcome.swift */; }; - 2CD262AB2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261872CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262AC2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261882CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262AD2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261892CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png */; }; - 2CD262AE2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618A2CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png */; }; - 2CD262AF2CFDC5EB00A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618B2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262B02CFDC5EB00A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618C2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262B12CFDC5EB00A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618D2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png */; }; - 2CD262B22CFDC5EB00A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618E2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png */; }; - 2CD262B32CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2618F2CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262B42CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261902CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262B52CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261912CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png */; }; - 2CD262B62CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261922CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png */; }; - 2CD262B72CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261932CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262B82CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261942CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262B92CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261952CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png */; }; - 2CD262BA2CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261962CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png */; }; - 2CD262BB2CFDC5EB00A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261972CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262BC2CFDC5EB00A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261982CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262BD2CFDC5EB00A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261992CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png */; }; - 2CD262BE2CFDC5EB00A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619A2CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png */; }; - 2CD262BF2CFDC5EB00A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619B2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262C02CFDC5EB00A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619C2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262C12CFDC5EB00A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619D2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_en.1.png */; }; - 2CD262C22CFDC5EB00A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619E2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_es.1.png */; }; - 2CD262C32CFDC5EB00A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2619F2CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262C42CFDC5EB00A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A02CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262C52CFDC5EB00A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A12CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_en.1.png */; }; - 2CD262C62CFDC5EB00A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A22CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_es.1.png */; }; - 2CD262C72CFDC5EB00A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A32CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262C82CFDC5EB00A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A42CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262C92CFDC5EB00A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A52CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_en.1.png */; }; - 2CD262CA2CFDC5EB00A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A62CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_es.1.png */; }; - 2CD262CB2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A72CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262CC2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A82CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262CD2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261A92CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png */; }; - 2CD262CE2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AA2CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png */; }; - 2CD262CF2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AB2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262D02CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AC2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262D12CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AD2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png */; }; - 2CD262D22CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AE2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png */; }; - 2CD262D32CFDC5EB00A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261AF2CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262D42CFDC5EB00A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B02CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262D52CFDC5EB00A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B12CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png */; }; - 2CD262D62CFDC5EB00A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B22CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png */; }; - 2CD262D72CFDC5EB00A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B32CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262D82CFDC5EB00A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B42CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262D92CFDC5EB00A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B52CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png */; }; - 2CD262DA2CFDC5EB00A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261B62CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png */; }; - 2CD262DB2CFDC5EB00A040A7 /* NTPComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261B92CFDC5E900A040A7 /* NTPComponentTests.swift */; }; - 2CD262DC2CFDC5EB00A040A7 /* NTPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD261BA2CFDC5E900A040A7 /* NTPTests.swift */; }; - 2CD262DD2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261BC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; - 2CD262DE2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261BD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; - 2CD262DF2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261BE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; - 2CD262E02CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261BF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; - 2CD262E12CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C02CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; - 2CD262E22CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C12CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_de.1.png */; }; - 2CD262E32CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C22CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_en.1.png */; }; - 2CD262E42CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C32CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_es.1.png */; }; - 2CD262E52CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C42CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_it.1.png */; }; - 2CD262E62CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C52CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png */; }; - 2CD262E72CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C62CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png */; }; - 2CD262E82CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C72CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png */; }; - 2CD262E92CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C82CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png */; }; - 2CD262EA2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261C92CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png */; }; - 2CD262EB2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CA2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png */; }; - 2CD262EC2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CB2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png */; }; - 2CD262ED2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png */; }; - 2CD262EE2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png */; }; - 2CD262EF2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png */; }; - 2CD262F02CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261CF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png */; }; - 2CD262F12CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D02CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; - 2CD262F22CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D12CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; - 2CD262F32CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D22CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; - 2CD262F42CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D32CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; - 2CD262F52CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D42CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; - 2CD262F62CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D52CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_de.1.png */; }; - 2CD262F72CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D62CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_en.1.png */; }; - 2CD262F82CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D72CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_es.1.png */; }; - 2CD262F92CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D82CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_it.1.png */; }; - 2CD262FA2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261D92CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_nl.1.png */; }; - 2CD262FB2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DA2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png */; }; - 2CD262FC2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DB2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png */; }; - 2CD262FD2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DC2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png */; }; - 2CD262FE2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DD2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png */; }; - 2CD262FF2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DE2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png */; }; - 2CD263002CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261DF2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png */; }; - 2CD263012CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E02CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png */; }; - 2CD263022CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E12CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png */; }; - 2CD263032CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E22CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png */; }; - 2CD263042CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E32CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png */; }; - 2CD263052CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; - 2CD263062CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; - 2CD263072CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; - 2CD263082CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; - 2CD263092CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E82CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; - 2CD2630A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261E92CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png */; }; - 2CD2630B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261EA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png */; }; - 2CD2630C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261EB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png */; }; - 2CD2630D2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261EC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png */; }; - 2CD2630E2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261ED2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png */; }; - 2CD2630F2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261EE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png */; }; - 2CD263102CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261EF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png */; }; - 2CD263112CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F02CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png */; }; - 2CD263122CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F12CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png */; }; - 2CD263132CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F22CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png */; }; - 2CD263142CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F32CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png */; }; - 2CD263152CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png */; }; - 2CD263162CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png */; }; - 2CD263172CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png */; }; - 2CD263182CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png */; }; - 2CD263192CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F82CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; - 2CD2631A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261F92CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; - 2CD2631B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; - 2CD2631C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; - 2CD2631D2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; - 2CD2631E2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FD2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png */; }; - 2CD2631F2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png */; }; - 2CD263202CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD261FF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png */; }; - 2CD263212CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262002CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png */; }; - 2CD263222CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262012CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png */; }; - 2CD263232CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262022CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png */; }; - 2CD263242CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262032CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png */; }; - 2CD263252CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262042CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png */; }; - 2CD263262CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262052CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png */; }; - 2CD263272CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262062CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png */; }; - 2CD263282CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262072CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png */; }; - 2CD263292CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262082CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png */; }; - 2CD2632A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262092CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png */; }; - 2CD2632B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620A2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png */; }; - 2CD2632C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620B2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png */; }; - 2CD2632D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; - 2CD2632E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; - 2CD2632F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; - 2CD263302CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2620F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; - 2CD263312CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262102CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; - 2CD263322CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262112CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png */; }; - 2CD263332CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262122CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png */; }; - 2CD263342CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262132CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png */; }; - 2CD263352CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262142CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png */; }; - 2CD263362CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262152CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png */; }; - 2CD263372CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262162CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png */; }; - 2CD263382CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262172CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png */; }; - 2CD263392CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262182CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png */; }; - 2CD2633A2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262192CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png */; }; - 2CD2633B2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png */; }; - 2CD2633C2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png */; }; - 2CD2633D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png */; }; - 2CD2633E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png */; }; - 2CD2633F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png */; }; - 2CD263402CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2621F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png */; }; - 2CD263412CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262202CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; - 2CD263422CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262212CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; - 2CD263432CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262222CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; - 2CD263442CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262232CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; - 2CD263452CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262242CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; - 2CD263462CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262252CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png */; }; - 2CD263472CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262262CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png */; }; - 2CD263482CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262272CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png */; }; - 2CD263492CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262282CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png */; }; - 2CD2634A2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262292CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png */; }; - 2CD2634B2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png */; }; - 2CD2634C2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png */; }; - 2CD2634D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png */; }; - 2CD2634E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png */; }; - 2CD2634F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png */; }; - 2CD263502CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2622F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png */; }; - 2CD263512CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262302CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png */; }; - 2CD263522CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262312CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png */; }; - 2CD263532CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262322CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png */; }; - 2CD263542CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262332CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png */; }; - 2CD263552CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262342CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; - 2CD263562CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262352CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; - 2CD263572CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262362CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; - 2CD263582CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262372CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; - 2CD263592CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262382CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; - 2CD2635A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262392CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png */; }; - 2CD2635B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png */; }; - 2CD2635C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png */; }; - 2CD2635D2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png */; }; - 2CD2635E2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png */; }; - 2CD2635F2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png */; }; - 2CD263602CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2623F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png */; }; - 2CD263612CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262402CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png */; }; - 2CD263622CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262412CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png */; }; - 2CD263632CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262422CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png */; }; - 2CD263642CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262432CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png */; }; - 2CD263652CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262442CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png */; }; - 2CD263662CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262452CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png */; }; - 2CD263672CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262462CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png */; }; - 2CD263682CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262472CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png */; }; - 2CD263692CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262482CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; - 2CD2636A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262492CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; - 2CD2636B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; - 2CD2636C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; - 2CD2636D2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; - 2CD2636E2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png */; }; - 2CD2636F2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png */; }; - 2CD263702CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2624F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png */; }; - 2CD263712CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262502CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png */; }; - 2CD263722CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262512CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png */; }; - 2CD263732CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262522CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png */; }; - 2CD263742CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262532CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png */; }; - 2CD263752CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262542CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png */; }; - 2CD263762CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262552CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png */; }; - 2CD263772CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262562CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png */; }; - 2CD263782CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262572CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png */; }; - 2CD263792CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262582CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png */; }; - 2CD2637A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262592CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png */; }; - 2CD2637B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png */; }; - 2CD2637C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png */; }; - 2CD2637D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; - 2CD2637E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; - 2CD2637F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; - 2CD263802CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2625F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; - 2CD263812CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262602CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; - 2CD263822CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262612CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png */; }; - 2CD263832CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262622CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png */; }; - 2CD263842CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262632CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png */; }; - 2CD263852CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262642CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png */; }; - 2CD263862CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262652CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png */; }; - 2CD263872CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262662CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png */; }; - 2CD263882CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262672CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png */; }; - 2CD263892CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262682CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png */; }; - 2CD2638A2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262692CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png */; }; - 2CD2638B2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png */; }; - 2CD2638C2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png */; }; - 2CD2638D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png */; }; - 2CD2638E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png */; }; - 2CD2638F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png */; }; - 2CD263902CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2626F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png */; }; - 2CD263912CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262702CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */; }; - 2CD263922CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262712CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */; }; - 2CD263932CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262722CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */; }; - 2CD263942CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262732CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */; }; - 2CD263952CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262742CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */; }; - 2CD263962CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262752CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png */; }; - 2CD263972CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262762CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png */; }; - 2CD263982CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262772CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png */; }; - 2CD263992CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262782CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png */; }; - 2CD2639A2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262792CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png */; }; - 2CD2639B2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png */; }; - 2CD2639C2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png */; }; - 2CD2639D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png */; }; - 2CD2639E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png */; }; - 2CD2639F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png */; }; - 2CD263A02CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2627F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png */; }; - 2CD263A12CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262802CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png */; }; - 2CD263A22CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262812CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png */; }; - 2CD263A32CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262822CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png */; }; - 2CD263A42CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262832CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png */; }; - 2CD263A52CFDC5EB00A040A7 /* OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262862CFDC5E900A040A7 /* OnboardingTests.swift */; }; - 2CD263A62CFDC5EB00A040A7 /* DeviceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262882CFDC5E900A040A7 /* DeviceType.swift */; }; - 2CD263A72CFDC5EB00A040A7 /* EcosiaSnapshotTests.xctestplan in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262892CFDC5E900A040A7 /* EcosiaSnapshotTests.xctestplan */; }; 2CD263A82CFDC5EB00A040A7 /* environment.json in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2628A2CFDC5E900A040A7 /* environment.json */; }; - 2CD263A92CFDC5EB00A040A7 /* LocaleRetriever.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628B2CFDC5E900A040A7 /* LocaleRetriever.swift */; }; - 2CD263AA2CFDC5EB00A040A7 /* LocalizationOverrideTestingBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628C2CFDC5E900A040A7 /* LocalizationOverrideTestingBundle.swift */; }; - 2CD263AB2CFDC5EB00A040A7 /* snapshot_configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = 2CD2628D2CFDC5E900A040A7 /* snapshot_configuration.json */; }; - 2CD263AC2CFDC5EB00A040A7 /* SnapshotBaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628E2CFDC5E900A040A7 /* SnapshotBaseTests.swift */; }; - 2CD263AD2CFDC5EB00A040A7 /* SnapshotTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628F2CFDC5E900A040A7 /* SnapshotTestHelper.swift */; }; - 2CD263AE2CFDC5EB00A040A7 /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262902CFDC5E900A040A7 /* String+Extension.swift */; }; 2CD263AF2CFDC5EB00A040A7 /* VersionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262922CFDC5E900A040A7 /* VersionTests.swift */; }; - 2CD263B02CFDC5EB00A040A7 /* NTPComponentTests_tests.xcresult in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262932CFDC5E900A040A7 /* NTPComponentTests_tests.xcresult */; }; - 2CD263B12CFDC5EB00A040A7 /* OnboardingTests_tests.xcresult in Resources */ = {isa = PBXBuildFile; fileRef = 2CD262942CFDC5E900A040A7 /* OnboardingTests_tests.xcresult */; }; 2CD263B22CFDC5EB00A040A7 /* WhatsNewLocalDataProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262962CFDC5E900A040A7 /* WhatsNewLocalDataProviderTests.swift */; }; 2CD263B32CFDC5EB00A040A7 /* AppDelegateFeatureManagementIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262972CFDC5EA00A040A7 /* AppDelegateFeatureManagementIntegrationTests.swift */; }; 2CD263B42CFDC5EB00A040A7 /* EcosiaInstallTypeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262992CFDC5EA00A040A7 /* EcosiaInstallTypeTests.swift */; }; @@ -2969,256 +2710,8 @@ 2CCF17522105E4FD00705AE5 /* DisplaySettingsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplaySettingsTests.swift; sourceTree = ""; }; 2CD261842CFDC5E900A040A7 /* EcosiaMockThemeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaMockThemeManager.swift; sourceTree = ""; }; 2CD261852CFDC5E900A040A7 /* Welcome.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Welcome.swift; sourceTree = ""; }; - 2CD261872CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261882CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261892CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD2618A2CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD2618B2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD2618C2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD2618D2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD2618E2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD2618F2CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261902CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261912CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261922CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261932CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261942CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261952CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261962CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261972CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261982CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261992CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD2619A2CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD2619B2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD2619C2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD2619D2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLibraryCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD2619E2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLibraryCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD2619F2CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLogoCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261A02CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLogoCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261A12CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLogoCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261A22CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPLogoCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261A32CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPNewsCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261A42CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPNewsCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261A52CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPNewsCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261A62CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPNewsCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261A72CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261A82CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261A92CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261AA2CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261AB2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261AC2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261AD2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261AE2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261AF2CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261B02CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261B12CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261B22CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261B32CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261B42CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261B52CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261B62CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; 2CD261B92CFDC5E900A040A7 /* NTPComponentTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPComponentTests.swift; sourceTree = ""; }; 2CD261BA2CFDC5E900A040A7 /* NTPTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NTPTests.swift; sourceTree = ""; }; - 2CD261BC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; - 2CD261BD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; - 2CD261BE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; - 2CD261BF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; - 2CD261C02CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; - 2CD261C12CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; - 2CD261C22CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261C32CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261C42CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; - 2CD261C52CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; - 2CD261C62CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; - 2CD261C72CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; - 2CD261C82CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; - 2CD261C92CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; - 2CD261CA2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; - 2CD261CB2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; - 2CD261CC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; - 2CD261CD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; - 2CD261CE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; - 2CD261CF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; - 2CD261D02CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; - 2CD261D12CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; - 2CD261D22CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; - 2CD261D32CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; - 2CD261D42CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; - 2CD261D52CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; - 2CD261D62CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261D72CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261D82CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; - 2CD261D92CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; - 2CD261DA2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; - 2CD261DB2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; - 2CD261DC2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; - 2CD261DD2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; - 2CD261DE2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; - 2CD261DF2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; - 2CD261E02CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; - 2CD261E12CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; - 2CD261E22CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; - 2CD261E32CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; - 2CD261E42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; - 2CD261E52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; - 2CD261E62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; - 2CD261E72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; - 2CD261E82CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; - 2CD261E92CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; - 2CD261EA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261EB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD261EC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; - 2CD261ED2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; - 2CD261EE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; - 2CD261EF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; - 2CD261F02CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; - 2CD261F12CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; - 2CD261F22CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; - 2CD261F32CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; - 2CD261F42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; - 2CD261F52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; - 2CD261F62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; - 2CD261F72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; - 2CD261F82CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; - 2CD261F92CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; - 2CD261FA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; - 2CD261FB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; - 2CD261FC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; - 2CD261FD2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; - 2CD261FE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD261FF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD262002CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; - 2CD262012CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; - 2CD262022CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; - 2CD262032CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; - 2CD262042CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; - 2CD262052CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; - 2CD262062CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; - 2CD262072CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; - 2CD262082CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; - 2CD262092CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; - 2CD2620A2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; - 2CD2620B2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; - 2CD2620C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; - 2CD2620D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; - 2CD2620E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; - 2CD2620F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; - 2CD262102CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; - 2CD262112CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; - 2CD262122CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD262132CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD262142CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; - 2CD262152CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; - 2CD262162CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; - 2CD262172CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; - 2CD262182CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; - 2CD262192CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; - 2CD2621A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; - 2CD2621B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; - 2CD2621C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; - 2CD2621D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; - 2CD2621E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; - 2CD2621F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; - 2CD262202CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; - 2CD262212CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; - 2CD262222CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; - 2CD262232CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; - 2CD262242CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; - 2CD262252CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; - 2CD262262CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD262272CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD262282CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; - 2CD262292CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; - 2CD2622A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; - 2CD2622B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; - 2CD2622C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; - 2CD2622D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; - 2CD2622E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; - 2CD2622F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; - 2CD262302CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; - 2CD262312CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; - 2CD262322CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; - 2CD262332CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; - 2CD262342CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; - 2CD262352CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; - 2CD262362CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; - 2CD262372CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; - 2CD262382CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; - 2CD262392CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; - 2CD2623A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD2623B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD2623C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; - 2CD2623D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; - 2CD2623E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; - 2CD2623F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; - 2CD262402CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; - 2CD262412CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; - 2CD262422CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; - 2CD262432CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; - 2CD262442CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; - 2CD262452CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; - 2CD262462CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; - 2CD262472CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; - 2CD262482CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; - 2CD262492CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; - 2CD2624A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; - 2CD2624B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; - 2CD2624C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; - 2CD2624D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; - 2CD2624E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD2624F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD262502CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; - 2CD262512CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; - 2CD262522CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; - 2CD262532CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; - 2CD262542CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; - 2CD262552CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; - 2CD262562CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; - 2CD262572CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; - 2CD262582CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; - 2CD262592CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; - 2CD2625A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; - 2CD2625B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; - 2CD2625C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; - 2CD2625D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; - 2CD2625E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; - 2CD2625F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; - 2CD262602CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; - 2CD262612CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; - 2CD262622CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD262632CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD262642CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; - 2CD262652CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; - 2CD262662CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; - 2CD262672CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; - 2CD262682CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; - 2CD262692CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; - 2CD2626A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; - 2CD2626B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; - 2CD2626C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; - 2CD2626D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; - 2CD2626E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; - 2CD2626F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; - 2CD262702CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png"; sourceTree = ""; }; - 2CD262712CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png"; sourceTree = ""; }; - 2CD262722CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png"; sourceTree = ""; }; - 2CD262732CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png"; sourceTree = ""; }; - 2CD262742CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png"; sourceTree = ""; }; - 2CD262752CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png"; sourceTree = ""; }; - 2CD262762CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png"; sourceTree = ""; }; - 2CD262772CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png"; sourceTree = ""; }; - 2CD262782CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png"; sourceTree = ""; }; - 2CD262792CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png"; sourceTree = ""; }; - 2CD2627A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png"; sourceTree = ""; }; - 2CD2627B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png"; sourceTree = ""; }; - 2CD2627C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png"; sourceTree = ""; }; - 2CD2627D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png"; sourceTree = ""; }; - 2CD2627E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png"; sourceTree = ""; }; - 2CD2627F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png"; sourceTree = ""; }; - 2CD262802CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png"; sourceTree = ""; }; - 2CD262812CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png"; sourceTree = ""; }; - 2CD262822CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png"; sourceTree = ""; }; - 2CD262832CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png"; sourceTree = ""; }; 2CD262862CFDC5E900A040A7 /* OnboardingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingTests.swift; sourceTree = ""; }; 2CD262882CFDC5E900A040A7 /* DeviceType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceType.swift; sourceTree = ""; }; 2CD262892CFDC5E900A040A7 /* EcosiaSnapshotTests.xctestplan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = EcosiaSnapshotTests.xctestplan; sourceTree = ""; }; @@ -3230,8 +2723,6 @@ 2CD2628F2CFDC5E900A040A7 /* SnapshotTestHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotTestHelper.swift; sourceTree = ""; }; 2CD262902CFDC5E900A040A7 /* String+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Extension.swift"; sourceTree = ""; }; 2CD262922CFDC5E900A040A7 /* VersionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionTests.swift; sourceTree = ""; }; - 2CD262932CFDC5E900A040A7 /* NTPComponentTests_tests.xcresult */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = NTPComponentTests_tests.xcresult; sourceTree = ""; }; - 2CD262942CFDC5E900A040A7 /* OnboardingTests_tests.xcresult */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = OnboardingTests_tests.xcresult; sourceTree = ""; }; 2CD262962CFDC5E900A040A7 /* WhatsNewLocalDataProviderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WhatsNewLocalDataProviderTests.swift; sourceTree = ""; }; 2CD262972CFDC5EA00A040A7 /* AppDelegateFeatureManagementIntegrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegateFeatureManagementIntegrationTests.swift; sourceTree = ""; }; 2CD262992CFDC5EA00A040A7 /* EcosiaInstallTypeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EcosiaInstallTypeTests.swift; sourceTree = ""; }; @@ -8824,7 +8315,6 @@ 2CD262A22CFDC5EA00A040A7 /* ClimateImpactCounter */, 2CD262982CFDC5EA00A040A7 /* IntegrationTests */, 2CD2629C2CFDC5EA00A040A7 /* Mocks */, - 2CD262952CFDC5E900A040A7 /* Results */, 2CD262912CFDC5E900A040A7 /* SnapshotTests */, 2CD2629F2CFDC5EA00A040A7 /* EcosiaHomeViewModelTests.swift */, 2CD262992CFDC5EA00A040A7 /* EcosiaInstallTypeTests.swift */, @@ -9631,298 +9121,18 @@ path = Mocks; sourceTree = ""; }; - 2CD261B72CFDC5E900A040A7 /* NTPComponentTests */ = { - isa = PBXGroup; - children = ( - 2CD261872CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png */, - 2CD261882CFDC5E900A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png */, - 2CD261892CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png */, - 2CD2618A2CFDC5E900A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png */, - 2CD2618B2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png */, - 2CD2618C2CFDC5E900A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png */, - 2CD2618D2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png */, - 2CD2618E2CFDC5E900A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png */, - 2CD2618F2CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png */, - 2CD261902CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png */, - 2CD261912CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png */, - 2CD261922CFDC5E900A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png */, - 2CD261932CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png */, - 2CD261942CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png */, - 2CD261952CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png */, - 2CD261962CFDC5E900A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png */, - 2CD261972CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png */, - 2CD261982CFDC5E900A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png */, - 2CD261992CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png */, - 2CD2619A2CFDC5E900A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png */, - 2CD2619B2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png */, - 2CD2619C2CFDC5E900A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png */, - 2CD2619D2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_en.1.png */, - 2CD2619E2CFDC5E900A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_es.1.png */, - 2CD2619F2CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_en.1.png */, - 2CD261A02CFDC5E900A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_es.1.png */, - 2CD261A12CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_en.1.png */, - 2CD261A22CFDC5E900A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_es.1.png */, - 2CD261A32CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_en.1.png */, - 2CD261A42CFDC5E900A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_es.1.png */, - 2CD261A52CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_en.1.png */, - 2CD261A62CFDC5E900A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_es.1.png */, - 2CD261A72CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png */, - 2CD261A82CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png */, - 2CD261A92CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png */, - 2CD261AA2CFDC5E900A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png */, - 2CD261AB2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png */, - 2CD261AC2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png */, - 2CD261AD2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png */, - 2CD261AE2CFDC5E900A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png */, - 2CD261AF2CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png */, - 2CD261B02CFDC5E900A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png */, - 2CD261B12CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png */, - 2CD261B22CFDC5E900A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png */, - 2CD261B32CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png */, - 2CD261B42CFDC5E900A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png */, - 2CD261B52CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png */, - 2CD261B62CFDC5E900A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png */, - ); - path = NTPComponentTests; - sourceTree = ""; - }; - 2CD261B82CFDC5E900A040A7 /* __Snapshots__ */ = { - isa = PBXGroup; - children = ( - 2CD261B72CFDC5E900A040A7 /* NTPComponentTests */, - ); - path = __Snapshots__; - sourceTree = ""; - }; 2CD261BB2CFDC5E900A040A7 /* NTP */ = { isa = PBXGroup; children = ( - 2CD261B82CFDC5E900A040A7 /* __Snapshots__ */, 2CD261B92CFDC5E900A040A7 /* NTPComponentTests.swift */, 2CD261BA2CFDC5E900A040A7 /* NTPTests.swift */, ); path = NTP; sourceTree = ""; }; - 2CD262842CFDC5E900A040A7 /* OnboardingTests */ = { - isa = PBXGroup; - children = ( - 2CD261BC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, - 2CD261BD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, - 2CD261BE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, - 2CD261BF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, - 2CD261C02CFDC5E900A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, - 2CD261C12CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_de.1.png */, - 2CD261C22CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_en.1.png */, - 2CD261C32CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_es.1.png */, - 2CD261C42CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_it.1.png */, - 2CD261C52CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png */, - 2CD261C62CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png */, - 2CD261C72CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png */, - 2CD261C82CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png */, - 2CD261C92CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png */, - 2CD261CA2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png */, - 2CD261CB2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png */, - 2CD261CC2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png */, - 2CD261CD2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png */, - 2CD261CE2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png */, - 2CD261CF2CFDC5E900A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png */, - 2CD261D02CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, - 2CD261D12CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, - 2CD261D22CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, - 2CD261D32CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, - 2CD261D42CFDC5E900A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, - 2CD261D52CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_de.1.png */, - 2CD261D62CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_en.1.png */, - 2CD261D72CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_es.1.png */, - 2CD261D82CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_it.1.png */, - 2CD261D92CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_nl.1.png */, - 2CD261DA2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png */, - 2CD261DB2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png */, - 2CD261DC2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png */, - 2CD261DD2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png */, - 2CD261DE2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png */, - 2CD261DF2CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png */, - 2CD261E02CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png */, - 2CD261E12CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png */, - 2CD261E22CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png */, - 2CD261E32CFDC5E900A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png */, - 2CD261E42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, - 2CD261E52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, - 2CD261E62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, - 2CD261E72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, - 2CD261E82CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, - 2CD261E92CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png */, - 2CD261EA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png */, - 2CD261EB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png */, - 2CD261EC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png */, - 2CD261ED2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png */, - 2CD261EE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png */, - 2CD261EF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png */, - 2CD261F02CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png */, - 2CD261F12CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png */, - 2CD261F22CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png */, - 2CD261F32CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png */, - 2CD261F42CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png */, - 2CD261F52CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png */, - 2CD261F62CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png */, - 2CD261F72CFDC5E900A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png */, - 2CD261F82CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, - 2CD261F92CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, - 2CD261FA2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, - 2CD261FB2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, - 2CD261FC2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, - 2CD261FD2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png */, - 2CD261FE2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png */, - 2CD261FF2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png */, - 2CD262002CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png */, - 2CD262012CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png */, - 2CD262022CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png */, - 2CD262032CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png */, - 2CD262042CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png */, - 2CD262052CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png */, - 2CD262062CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png */, - 2CD262072CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png */, - 2CD262082CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png */, - 2CD262092CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png */, - 2CD2620A2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png */, - 2CD2620B2CFDC5E900A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png */, - 2CD2620C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, - 2CD2620D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, - 2CD2620E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, - 2CD2620F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, - 2CD262102CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, - 2CD262112CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png */, - 2CD262122CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png */, - 2CD262132CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png */, - 2CD262142CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png */, - 2CD262152CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png */, - 2CD262162CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png */, - 2CD262172CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png */, - 2CD262182CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png */, - 2CD262192CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png */, - 2CD2621A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png */, - 2CD2621B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png */, - 2CD2621C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png */, - 2CD2621D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png */, - 2CD2621E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png */, - 2CD2621F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png */, - 2CD262202CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, - 2CD262212CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, - 2CD262222CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, - 2CD262232CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, - 2CD262242CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, - 2CD262252CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png */, - 2CD262262CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png */, - 2CD262272CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png */, - 2CD262282CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png */, - 2CD262292CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png */, - 2CD2622A2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png */, - 2CD2622B2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png */, - 2CD2622C2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png */, - 2CD2622D2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png */, - 2CD2622E2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png */, - 2CD2622F2CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png */, - 2CD262302CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png */, - 2CD262312CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png */, - 2CD262322CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png */, - 2CD262332CFDC5E900A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png */, - 2CD262342CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, - 2CD262352CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, - 2CD262362CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, - 2CD262372CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, - 2CD262382CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, - 2CD262392CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png */, - 2CD2623A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png */, - 2CD2623B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png */, - 2CD2623C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png */, - 2CD2623D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png */, - 2CD2623E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png */, - 2CD2623F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png */, - 2CD262402CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png */, - 2CD262412CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png */, - 2CD262422CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png */, - 2CD262432CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png */, - 2CD262442CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png */, - 2CD262452CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png */, - 2CD262462CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png */, - 2CD262472CFDC5E900A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png */, - 2CD262482CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, - 2CD262492CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, - 2CD2624A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, - 2CD2624B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, - 2CD2624C2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, - 2CD2624D2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png */, - 2CD2624E2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png */, - 2CD2624F2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png */, - 2CD262502CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png */, - 2CD262512CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png */, - 2CD262522CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png */, - 2CD262532CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png */, - 2CD262542CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png */, - 2CD262552CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png */, - 2CD262562CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png */, - 2CD262572CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png */, - 2CD262582CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png */, - 2CD262592CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png */, - 2CD2625A2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png */, - 2CD2625B2CFDC5E900A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png */, - 2CD2625C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, - 2CD2625D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, - 2CD2625E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, - 2CD2625F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, - 2CD262602CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, - 2CD262612CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png */, - 2CD262622CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png */, - 2CD262632CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png */, - 2CD262642CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png */, - 2CD262652CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png */, - 2CD262662CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png */, - 2CD262672CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png */, - 2CD262682CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png */, - 2CD262692CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png */, - 2CD2626A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png */, - 2CD2626B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png */, - 2CD2626C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png */, - 2CD2626D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png */, - 2CD2626E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png */, - 2CD2626F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png */, - 2CD262702CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png */, - 2CD262712CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png */, - 2CD262722CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png */, - 2CD262732CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png */, - 2CD262742CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png */, - 2CD262752CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png */, - 2CD262762CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png */, - 2CD262772CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png */, - 2CD262782CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png */, - 2CD262792CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png */, - 2CD2627A2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png */, - 2CD2627B2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png */, - 2CD2627C2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png */, - 2CD2627D2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png */, - 2CD2627E2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png */, - 2CD2627F2CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png */, - 2CD262802CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png */, - 2CD262812CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png */, - 2CD262822CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png */, - 2CD262832CFDC5E900A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png */, - ); - path = OnboardingTests; - sourceTree = ""; - }; - 2CD262852CFDC5E900A040A7 /* __Snapshots__ */ = { - isa = PBXGroup; - children = ( - 2CD262842CFDC5E900A040A7 /* OnboardingTests */, - ); - path = __Snapshots__; - sourceTree = ""; - }; 2CD262872CFDC5E900A040A7 /* Onboarding */ = { isa = PBXGroup; children = ( - 2CD262852CFDC5E900A040A7 /* __Snapshots__ */, 2CD262862CFDC5E900A040A7 /* OnboardingTests.swift */, ); path = Onboarding; @@ -9947,15 +9157,6 @@ path = SnapshotTests; sourceTree = ""; }; - 2CD262952CFDC5E900A040A7 /* Results */ = { - isa = PBXGroup; - children = ( - 2CD262932CFDC5E900A040A7 /* NTPComponentTests_tests.xcresult */, - 2CD262942CFDC5E900A040A7 /* OnboardingTests_tests.xcresult */, - ); - path = Results; - sourceTree = ""; - }; 2CD262982CFDC5EA00A040A7 /* IntegrationTests */ = { isa = PBXGroup; children = ( @@ -14597,268 +13798,16 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2CD263702CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD263342CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD262CC2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD262F42CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, - 2CD262FD2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_es.1.png in Resources */, - 2CD2635B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD263452CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, - 2CD2634F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_nl.1.png in Resources */, - 2CD2631A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, - 2CD262EF2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, - 2CD2639F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_nl.1.png in Resources */, - 2CD2635C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD2639A2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_nl.1.png in Resources */, - 2CD2632F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, 2CAF5BE02D00D1AB00D3DCDD /* import_input_bookmark_firefox.html in Resources */, - 2CD2632E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, - 2CD262C22CFDC5EB00A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD263122CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_it.1.png in Resources */, - 2CD263112CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_es.1.png in Resources */, - 2CD262FF2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_nl.1.png in Resources */, - 2CD263002CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_de.1.png in Resources */, - 2CD263B12CFDC5EB00A040A7 /* OnboardingTests_tests.xcresult in Resources */, - 2CD262D32CFDC5EB00A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD2633E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */, - 2CD263612CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_es.1.png in Resources */, - 2CD2631D2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, - 2CD263A42CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */, - 2CD262C62CFDC5EB00A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD262C52CFDC5EB00A040A7 /* testNTPLogoCell_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD263352CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_it.1.png in Resources */, - 2CD262E62CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_nl.1.png in Resources */, - 2CD2638F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, - 2CD263742CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_en.1.png in Resources */, - 2CD2633F2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, 2CAF5BE62D00D1AB00D3DCDD /* referrals.json in Resources */, - 2CD2639B2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_de.1.png in Resources */, - 2CD263662CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */, - 2CD262B42CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD262E32CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD2632B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_it.1.png in Resources */, - 2CD263622CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_it.1.png in Resources */, - 2CD263542CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */, - 2CD262C82CFDC5EB00A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD263162CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */, - 2CD263012CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_en.1.png in Resources */, - 2CD262CF2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD2638A2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_it.1.png in Resources */, - 2CD263442CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, - 2CD2630D2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_it.1.png in Resources */, - 2CD262D82CFDC5EB00A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD262BF2CFDC5EB00A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD263172CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, - 2CD263592CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, - 2CD263382CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_en.1.png in Resources */, - 2CD262B82CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD262F62CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_de.1.png in Resources */, - 2CD2638C2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */, - 2CD2636C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, - 2CD263792CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_en.1.png in Resources */, - 2CD263062CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, - 2CD262BA2CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD262E12CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, - 2CD2639E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_it.1.png in Resources */, - 2CD263722CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_nl.1.png in Resources */, - 2CD262D52CFDC5EB00A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD262DA2CFDC5EB00A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD263802CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, - 2CD263952CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, - 2CD262BC2CFDC5EB00A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD262B62CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD262F02CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */, - 2CD2632D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, - 2CD263882CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_en.1.png in Resources */, - 2CD2633B2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, - 2CD262D02CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD263B02CFDC5EB00A040A7 /* NTPComponentTests_tests.xcresult in Resources */, - 2CD2637C2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */, - 2CD2633C2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */, - 2CD263AB2CFDC5EB00A040A7 /* snapshot_configuration.json in Resources */, - 2CD263292CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_en.1.png in Resources */, - 2CD2638E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */, - 2CD263602CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_en.1.png in Resources */, - 2CD263492CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_it.1.png in Resources */, - 2CD262EB2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, - 2CD263582CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, - 2CD262E22CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_de.1.png in Resources */, - 2CD262E72CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_de.1.png in Resources */, - 2CD2637D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, - 2CD263502CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_de.1.png in Resources */, - 2CD263082CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, - 2CD263572CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, - 2CD262AE2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_es.1.png in Resources */, 2CAF5BDF2D00D1AB00D3DCDD /* import_input_bookmark_chrome.html in Resources */, 2CAF5BE22D00D1AB00D3DCDD /* import_output_bookmark_chrome.txt in Resources */, - 2CD2631F2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD263132CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, - 2CD262E42CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD262BE2CFDC5EB00A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD262D42CFDC5EB00A040A7 /* testNTPTotalInvestedCell_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD262BB2CFDC5EB00A040A7 /* testNTPCustomizationCell_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD263842CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD262CA2CFDC5EB00A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD263072CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, - 2CD262F12CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, - 2CD263212CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_it.1.png in Resources */, - 2CD263092CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, - 2CD263302CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, - 2CD263762CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_it.1.png in Resources */, - 2CD263732CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_de.1.png in Resources */, - 2CD2637F2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, - 2CD263912CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, - 2CD263822CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_de.1.png in Resources */, - 2CD262B72CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD2630B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD262C72CFDC5EB00A040A7 /* testNTPNewsCell_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD262DE2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, - 2CD2636F2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD262B22CFDC5EB00A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD262E92CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_es.1.png in Resources */, - 2CD263262CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_it.1.png in Resources */, - 2CD263782CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_de.1.png in Resources */, - 2CD263852CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_it.1.png in Resources */, - 2CD263812CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, - 2CD263022CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_es.1.png in Resources */, - 2CD262BD2CFDC5EB00A040A7 /* testNTPCustomizationCell_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD263562CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, - 2CD263692CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, - 2CD2635A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_de.1.png in Resources */, - 2CD2635D2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_it.1.png in Resources */, - 2CD263402CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */, - 2CD263182CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */, - 2CD263412CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, - 2CD263772CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_nl.1.png in Resources */, - 2CD263862CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_nl.1.png in Resources */, - 2CD263482CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD2634C2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_en.1.png in Resources */, - 2CD262EC2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */, - 2CD2635F2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_de.1.png in Resources */, - 2CD263462CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_de.1.png in Resources */, - 2CD262D12CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD2634E2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_it.1.png in Resources */, - 2CD2639C2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_en.1.png in Resources */, - 2CD2631E2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_de.1.png in Resources */, - 2CD262D72CFDC5EB00A040A7 /* testNTPTotalTreesCell_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD263252CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_es.1.png in Resources */, - 2CD263272CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_nl.1.png in Resources */, - 2CD262AF2CFDC5EB00A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD262B52CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD262F72CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD263992CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_it.1.png in Resources */, - 2CD263512CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_en.1.png in Resources */, - 2CD2630E2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_nl.1.png in Resources */, - 2CD262CE2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD2636B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, - 2CD262DD2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, - 2CD262E82CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_en.1.png in Resources */, 2CAF5BE12D00D1AB00D3DCDD /* import_input_bookmark_safari.html in Resources */, 2CAF5BE32D00D1AB00D3DCDD /* import_output_bookmark_firefox.txt in Resources */, - 2CD2634A2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_nl.1.png in Resources */, - 2CD263832CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD2634D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_es.1.png in Resources */, - 2CD263242CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_en.1.png in Resources */, - 2CD262CB2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD2636A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, - 2CD262E02CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, - 2CD263142CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */, - 2CD262B32CFDC5EB00A040A7 /* testNTPAboutSection_treesupdate_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD2636E2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_de.1.png in Resources */, - 2CD263932CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, - 2CD262C32CFDC5EB00A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD263A72CFDC5EB00A040A7 /* EcosiaSnapshotTests.xctestplan in Resources */, - 2CD263102CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_en.1.png in Resources */, - 2CD2633D2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */, - 2CD262D92CFDC5EB00A040A7 /* testNTPTotalTreesCell_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD263672CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_it.1.png in Resources */, - 2CD263652CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */, - 2CD263712CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro_it.1.png in Resources */, - 2CD2638D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */, - 2CD263902CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */, - 2CD2631C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, - 2CD2636D2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, - 2CD263922CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, - 2CD263472CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD263552CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, - 2CD262B02CFDC5EB00A040A7 /* testNTPAboutSection_privacy_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD263332CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD263682CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_nl.1.png in Resources */, - 2CD2632C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */, - 2CD263A32CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_it.1.png in Resources */, - 2CD263752CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-14-Pro-Max_es.1.png in Resources */, - 2CD262D22CFDC5EB00A040A7 /* testNTPReferralInvitesCell_single_invite_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD263032CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_it.1.png in Resources */, - 2CD263432CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, - 2CD263392CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_es.1.png in Resources */, 2CD263A82CFDC5EB00A040A7 /* environment.json in Resources */, - 2CD263A12CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_en.1.png in Resources */, - 2CD2637A2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_es.1.png in Resources */, - 2CD262DF2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, - 2CD262C42CFDC5EB00A040A7 /* testNTPLogoCell_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD2630A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_de.1.png in Resources */, - 2CD263152CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */, - 2CD262AC2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD2630C2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD263942CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPad-Pro-12-9-inch-6th-generation-_it.1.png in Resources */, - 2CD262C12CFDC5EB00A040A7 /* testNTPLibraryCell_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD262FA2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_nl.1.png in Resources */, - 2CD262F82CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD263282CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_de.1.png in Resources */, - 2CD263422CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, - 2CD263982CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD262FC2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_en.1.png in Resources */, - 2CD2633A2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_it.1.png in Resources */, - 2CD2635E2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro_nl.1.png in Resources */, - 2CD262C02CFDC5EB00A040A7 /* testNTPLibraryCell_dark_iPhone-14-Pro_es.1.png in Resources */, - 2CD2639D2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro-Max_es.1.png in Resources */, - 2CD263892CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_es.1.png in Resources */, - 2CD263632CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, - 2CD263222CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_nl.1.png in Resources */, - 2CD2632A2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-SE-3rd-generation-_es.1.png in Resources */, - 2CD262AB2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_dark_iPhone-14-Pro_en.1.png in Resources */, - 2CD262F92CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro_it.1.png in Resources */, - 2CD262AD2CFDC5EB00A040A7 /* testNTPAboutSection_financialreports_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD262F32CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, - 2CD262D62CFDC5EB00A040A7 /* testNTPTotalInvestedCell_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD263972CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD263202CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro_es.1.png in Resources */, - 2CD262F22CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, - 2CD262EE2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_es.1.png in Resources */, - 2CD262B12CFDC5EB00A040A7 /* testNTPAboutSection_privacy_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD2637E2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPad-Pro-12-9-inch-6th-generation-_en.1.png in Resources */, - 2CD263362CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_nl.1.png in Resources */, - 2CD2637B2CFDC5EB00A040A7 /* testWelcomeScreen_step_3_light_iPhone-SE-3rd-generation-_it.1.png in Resources */, - 2CD262C92CFDC5EB00A040A7 /* testNTPNewsCell_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD263962CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-14-Pro_de.1.png in Resources */, - 2CD262F52CFDC5EB00A040A7 /* testWelcomeScreen_light_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, - 2CD263A02CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_de.1.png in Resources */, - 2CD262E52CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro_it.1.png in Resources */, - 2CD263052CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, - 2CD262ED2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-SE-3rd-generation-_en.1.png in Resources */, - 2CD263312CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPad-Pro-12-9-inch-6th-generation-_nl.1.png in Resources */, - 2CD263522CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_es.1.png in Resources */, - 2CD2634B2CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-14-Pro-Max_de.1.png in Resources */, - 2CD2630F2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_dark_iPhone-14-Pro-Max_de.1.png in Resources */, - 2CD2638B2CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_nl.1.png in Resources */, - 2CD262CD2CFDC5EB00A040A7 /* testNTPReferralInvitesCell_multiple_invites_light_iPhone-14-Pro_en.1.png in Resources */, 2CAF5BE42D00D1AB00D3DCDD /* import_output_bookmark_safari.txt in Resources */, - 2CD263192CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_de.1.png in Resources */, - 2CD263532CFDC5EB00A040A7 /* testWelcomeScreen_step_2_light_iPhone-SE-3rd-generation-_it.1.png in Resources */, - 2CD263642CFDC5EB00A040A7 /* testWelcomeScreen_step_3_dark_iPhone-SE-3rd-generation-_de.1.png in Resources */, 2CAF5BE52D00D1AB00D3DCDD /* notifications.json in Resources */, - 2CD263042CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-SE-3rd-generation-_nl.1.png in Resources */, - 2CD262FE2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_it.1.png in Resources */, 2CAF5BDE2D00D1AB00D3DCDD /* export_bookmark_ecosia.html in Resources */, - 2CD262B92CFDC5EB00A040A7 /* testNTPBookmarkNudgeCell_light_iPhone-14-Pro_en.1.png in Resources */, - 2CD263322CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro_de.1.png in Resources */, - 2CD263872CFDC5EB00A040A7 /* testWelcomeScreen_step_4_dark_iPhone-14-Pro-Max_de.1.png in Resources */, - 2CD263232CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPhone-14-Pro-Max_de.1.png in Resources */, - 2CD263372CFDC5EB00A040A7 /* testWelcomeScreen_step_2_dark_iPhone-14-Pro-Max_de.1.png in Resources */, - 2CD262FB2CFDC5EB00A040A7 /* testWelcomeScreen_light_iPhone-14-Pro-Max_de.1.png in Resources */, - 2CD2631B2CFDC5EB00A040A7 /* testWelcomeScreen_step_1_light_iPad-Pro-12-9-inch-6th-generation-_es.1.png in Resources */, - 2CD263A22CFDC5EB00A040A7 /* testWelcomeScreen_step_4_light_iPhone-SE-3rd-generation-_es.1.png in Resources */, - 2CD262EA2CFDC5EB00A040A7 /* testWelcomeScreen_dark_iPhone-14-Pro-Max_it.1.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -15320,10 +14269,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2CD263A92CFDC5EB00A040A7 /* LocaleRetriever.swift in Sources */, 2CD263BF2CFDC5EB00A040A7 /* AnalyticsSpyTests.swift in Sources */, 2CAF5BF12D00D1AB00D3DCDD /* HistoryTests.swift in Sources */, - 2CAF5BF32D00D1AB00D3DCDD /* SnapshotsTests.swift in Sources */, 2CAF5BDA2D00D1AB00D3DCDD /* MockURLSessionProtocol.swift in Sources */, 2CAF5BE82D00D1AB00D3DCDD /* SingularServiceTests.swift in Sources */, 2CD263C02CFDC5EB00A040A7 /* AnalyticsTests.swift in Sources */, @@ -15333,17 +14280,13 @@ 2CAF5BD92D00D1AB00D3DCDD /* MockURLSession.swift in Sources */, 2CAF5BEB2D00D1AB00D3DCDD /* BookmarkParserTests.swift in Sources */, 2CAF5BD52D00D1AB00D3DCDD /* User5_3.swift in Sources */, - 2CD263A52CFDC5EB00A040A7 /* OnboardingTests.swift in Sources */, 2CAF5BE92D00D1AB00D3DCDD /* UpgradeTests.swift in Sources */, 2CAF5BDC2D00D1AB00D3DCDD /* URLTests.swift in Sources */, 2CAF5C032D00D1AB00D3DCDD /* UnleashRefreshConfiguratorTests.swift in Sources */, - 2CD263AC2CFDC5EB00A040A7 /* SnapshotBaseTests.swift in Sources */, 2CD263B32CFDC5EB00A040A7 /* AppDelegateFeatureManagementIntegrationTests.swift in Sources */, 1229358D2CE78D5D00EC1297 /* BrazeServiceTests.swift in Sources */, 2CAF5BFE2D00D1AB00D3DCDD /* ReferralsTests.swift in Sources */, - 2CD263AE2CFDC5EB00A040A7 /* String+Extension.swift in Sources */, 2CAF5BED2D00D1AB00D3DCDD /* BookmarkSerializerTests.swift in Sources */, - 2CD262AA2CFDC5EB00A040A7 /* Welcome.swift in Sources */, 2CD263B52CFDC5EB00A040A7 /* EcosiaPerformanceTestHistory.swift in Sources */, 2CAF5C012D00D1AB00D3DCDD /* InvestmentsProjectionTests.swift in Sources */, 2CAF5BDB2D00D1AB00D3DCDD /* ListTests.swift in Sources */, @@ -15366,8 +14309,6 @@ 2CD263BB2CFDC5EB00A040A7 /* UserDefaultsSeedProgressManagerTests.swift in Sources */, 2CD263B22CFDC5EB00A040A7 /* WhatsNewLocalDataProviderTests.swift in Sources */, 2CAF5BFF2D00D1AB00D3DCDD /* FinancialReportsTests.swift in Sources */, - 2CD263A62CFDC5EB00A040A7 /* DeviceType.swift in Sources */, - 2CD263AA2CFDC5EB00A040A7 /* LocalizationOverrideTestingBundle.swift in Sources */, 2CAF5BFA2D00D1AB00D3DCDD /* StagingURLProviderTests.swift in Sources */, 2CAF5BEF2D00D1AB00D3DCDD /* StatisticsTests.swift in Sources */, 2CAF5BF62D00D1AB00D3DCDD /* TabsTests.swift in Sources */, @@ -15375,17 +14316,13 @@ 2CAF5BDD2D00D1AB00D3DCDD /* FeatureFlaggingSessionInitializerTests.swift in Sources */, 2CAF5BF52D00D1AB00D3DCDD /* SingularAdNetworkHelperTests.swift in Sources */, 2CD263B82CFDC5EB00A040A7 /* EcosiaNTPTooltipHighlightTests.swift in Sources */, - 2CD262DB2CFDC5EB00A040A7 /* NTPComponentTests.swift in Sources */, 2CAF5BF42D00D1AB00D3DCDD /* LocalTests.swift in Sources */, 2CAF5BD72D00D1AB00D3DCDD /* HTTPClientMock.swift in Sources */, 2CAF5BFD2D00D1AB00D3DCDD /* SearchesCounterTests.swift in Sources */, - 2CD262DC2CFDC5EB00A040A7 /* NTPTests.swift in Sources */, 2CD263B92CFDC5EB00A040A7 /* EcosiaHomeViewModelTests.swift in Sources */, 2CD263BC2CFDC5EB00A040A7 /* EcosiaTopSitesHelperTests.swift in Sources */, 2CAF5C052D00D1AB00D3DCDD /* LanguageTests.swift in Sources */, 2CD263BA2CFDC5EB00A040A7 /* UnleashUserDefaultsSeedProgressManagerTests.swift in Sources */, - 2CD263AD2CFDC5EB00A040A7 /* SnapshotTestHelper.swift in Sources */, - 2CD262A92CFDC5EB00A040A7 /* EcosiaMockThemeManager.swift in Sources */, 2CAF5BF92D00D1AB00D3DCDD /* ProductionURLProviderTests.swift in Sources */, 2CAF5BD82D00D1AB00D3DCDD /* MockTimestampProvider.swift in Sources */, 2CAF5BFC2D00D1AB00D3DCDD /* UserStateTests.swift in Sources */, @@ -15477,6 +14414,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2CAF5C272D01C33300D3DCDD /* EcosiaMockThemeManager.swift in Sources */, + 2CAF5C262D01C32C00D3DCDD /* Welcome.swift in Sources */, + 2CAF5C252D01C31900D3DCDD /* NTPTests.swift in Sources */, + 2CAF5C242D01C30B00D3DCDD /* OnboardingTests.swift in Sources */, + 2CAF5C232D01C2F300D3DCDD /* NTPComponentTests.swift in Sources */, 2C69DA7D2C6244BE00D7F69F /* MockTabDataStore.swift in Sources */, 2C69DA782C62259D00D7F69F /* MockProfile.swift in Sources */, 2C69DA792C6225AE00D7F69F /* DependencyHelperMock.swift in Sources */, diff --git a/Client.xcodeproj/xcshareddata/xcschemes/EcosiaBeta.xcscheme b/Client.xcodeproj/xcshareddata/xcschemes/EcosiaBeta.xcscheme index 1e00c2e1329f..5f62873cc1f5 100644 --- a/Client.xcodeproj/xcshareddata/xcschemes/EcosiaBeta.xcscheme +++ b/Client.xcodeproj/xcshareddata/xcschemes/EcosiaBeta.xcscheme @@ -107,8 +107,7 @@ + skipped = "NO"> + + + + + + + + diff --git a/EcosiaTests/Core/BookmarkParserTests.swift b/EcosiaTests/Core/BookmarkParserTests.swift index debf9acfbb70..c62fc25d62c2 100644 --- a/EcosiaTests/Core/BookmarkParserTests.swift +++ b/EcosiaTests/Core/BookmarkParserTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class BookmarkParserTests: XCTestCase { diff --git a/EcosiaTests/Core/BookmarkSerializerTests.swift b/EcosiaTests/Core/BookmarkSerializerTests.swift index 88f38494f85b..652c9b512b5d 100644 --- a/EcosiaTests/Core/BookmarkSerializerTests.swift +++ b/EcosiaTests/Core/BookmarkSerializerTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class BookmarkSerializerTests: XCTestCase { diff --git a/EcosiaTests/Core/BookmarkTests.swift b/EcosiaTests/Core/BookmarkTests.swift index 9e12181f686d..4a1383db621a 100644 --- a/EcosiaTests/Core/BookmarkTests.swift +++ b/EcosiaTests/Core/BookmarkTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class BookmarkTests: XCTestCase { diff --git a/EcosiaTests/Core/CookieTests.swift b/EcosiaTests/Core/CookieTests.swift index ee1f0d5e3d95..1a233c7580bb 100644 --- a/EcosiaTests/Core/CookieTests.swift +++ b/EcosiaTests/Core/CookieTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class CookieTests: XCTestCase { diff --git a/EcosiaTests/Core/FavouritesTests.swift b/EcosiaTests/Core/FavouritesTests.swift index b44d484dbe7a..91ca5f261f1e 100644 --- a/EcosiaTests/Core/FavouritesTests.swift +++ b/EcosiaTests/Core/FavouritesTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class FavouritesTests: XCTestCase { diff --git a/EcosiaTests/Core/FeatureFlaggingSessionInitializerTests.swift b/EcosiaTests/Core/FeatureFlaggingSessionInitializerTests.swift index 41bde3b79024..65d7cc94e39b 100644 --- a/EcosiaTests/Core/FeatureFlaggingSessionInitializerTests.swift +++ b/EcosiaTests/Core/FeatureFlaggingSessionInitializerTests.swift @@ -1,6 +1,6 @@ import XCTest import Foundation -@testable import Core +@testable import Ecosia class FeatureManagementSessiontInitializerTests: XCTestCase { diff --git a/EcosiaTests/Core/FinancialReportsTests.swift b/EcosiaTests/Core/FinancialReportsTests.swift index dccd68e6a289..613a90ff1e90 100644 --- a/EcosiaTests/Core/FinancialReportsTests.swift +++ b/EcosiaTests/Core/FinancialReportsTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class FinancialReportsTests: XCTestCase { diff --git a/EcosiaTests/Core/HistoryTests.swift b/EcosiaTests/Core/HistoryTests.swift index 28d302df6181..73104919a48e 100644 --- a/EcosiaTests/Core/HistoryTests.swift +++ b/EcosiaTests/Core/HistoryTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class HistoryTests: XCTestCase { diff --git a/EcosiaTests/Core/ImagesTests.swift b/EcosiaTests/Core/ImagesTests.swift index c743242ba400..742bbdd61d57 100644 --- a/EcosiaTests/Core/ImagesTests.swift +++ b/EcosiaTests/Core/ImagesTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import Core +@testable import Ecosia final class ImagesTests: XCTestCase { private var session: MockURLSession! diff --git a/EcosiaTests/Core/InvestmentsProjectionTests.swift b/EcosiaTests/Core/InvestmentsProjectionTests.swift index 3efa515eab28..6be83bcee67c 100644 --- a/EcosiaTests/Core/InvestmentsProjectionTests.swift +++ b/EcosiaTests/Core/InvestmentsProjectionTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class InvestmentsProjectionTests: XCTestCase { diff --git a/EcosiaTests/Core/LanguageTests.swift b/EcosiaTests/Core/LanguageTests.swift index 550453fc3389..4c3c5c3aea34 100644 --- a/EcosiaTests/Core/LanguageTests.swift +++ b/EcosiaTests/Core/LanguageTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class LanguageTests: XCTestCase { diff --git a/EcosiaTests/Core/ListTests.swift b/EcosiaTests/Core/ListTests.swift index 0bff07066c84..fb76173e4fef 100644 --- a/EcosiaTests/Core/ListTests.swift +++ b/EcosiaTests/Core/ListTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class ListTests: XCTestCase { diff --git a/EcosiaTests/Core/LocalTests.swift b/EcosiaTests/Core/LocalTests.swift index 52c607baf594..c7bf11ca5e34 100644 --- a/EcosiaTests/Core/LocalTests.swift +++ b/EcosiaTests/Core/LocalTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class LocalTests: XCTestCase { diff --git a/EcosiaTests/Core/NewsTests.swift b/EcosiaTests/Core/NewsTests.swift index 667fa0237d24..5fd4b144b8f2 100644 --- a/EcosiaTests/Core/NewsTests.swift +++ b/EcosiaTests/Core/NewsTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class NewsTests: XCTestCase { diff --git a/EcosiaTests/Core/PublishersTests.swift b/EcosiaTests/Core/PublishersTests.swift index c944a627785c..594d904c7959 100644 --- a/EcosiaTests/Core/PublishersTests.swift +++ b/EcosiaTests/Core/PublishersTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class PublishersTests: XCTestCase { diff --git a/EcosiaTests/Core/ReferralsModelTests.swift b/EcosiaTests/Core/ReferralsModelTests.swift index b78cbc9be2dc..ff6027f99f5e 100644 --- a/EcosiaTests/Core/ReferralsModelTests.swift +++ b/EcosiaTests/Core/ReferralsModelTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import Core +@testable import Ecosia final class ReferralsModelTests: XCTestCase { override func setUp() { diff --git a/EcosiaTests/Core/ReferralsTests.swift b/EcosiaTests/Core/ReferralsTests.swift index 8cbe2c440e19..b9cd91424049 100644 --- a/EcosiaTests/Core/ReferralsTests.swift +++ b/EcosiaTests/Core/ReferralsTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import Core +@testable import Ecosia final class ReferralsTests: XCTestCase { diff --git a/EcosiaTests/Core/SearchesCounterTests.swift b/EcosiaTests/Core/SearchesCounterTests.swift index 3c8ddbe33adb..dac06be42a10 100644 --- a/EcosiaTests/Core/SearchesCounterTests.swift +++ b/EcosiaTests/Core/SearchesCounterTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class SearchesCounterTests: XCTestCase { diff --git a/EcosiaTests/Core/SingularAdNetworkHelperTests.swift b/EcosiaTests/Core/SingularAdNetworkHelperTests.swift index cecf57aba5c6..5051e50f6d09 100644 --- a/EcosiaTests/Core/SingularAdNetworkHelperTests.swift +++ b/EcosiaTests/Core/SingularAdNetworkHelperTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import Core +@testable import Ecosia #if os(iOS) diff --git a/EcosiaTests/Core/SingularServiceTests.swift b/EcosiaTests/Core/SingularServiceTests.swift index 5e62b438cdf9..e09366425c0c 100644 --- a/EcosiaTests/Core/SingularServiceTests.swift +++ b/EcosiaTests/Core/SingularServiceTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest #if os(iOS) diff --git a/EcosiaTests/Core/SingularTests.swift b/EcosiaTests/Core/SingularTests.swift index 9fc4a742a4b8..af31172e469c 100644 --- a/EcosiaTests/Core/SingularTests.swift +++ b/EcosiaTests/Core/SingularTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import Core +@testable import Ecosia #if os(iOS) diff --git a/EcosiaTests/Core/SnapshotsTests.swift b/EcosiaTests/Core/SnapshotsTests.swift index 3368f56d5720..6a015712afce 100644 --- a/EcosiaTests/Core/SnapshotsTests.swift +++ b/EcosiaTests/Core/SnapshotsTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class SnapshotsTests: XCTestCase { diff --git a/EcosiaTests/Core/StatisticsTests.swift b/EcosiaTests/Core/StatisticsTests.swift index d49213217b6a..e567514c35c3 100644 --- a/EcosiaTests/Core/StatisticsTests.swift +++ b/EcosiaTests/Core/StatisticsTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class StatisticsTests: XCTestCase { diff --git a/EcosiaTests/Core/TabsTests.swift b/EcosiaTests/Core/TabsTests.swift index 3ce3d284a81a..2b63168c9b96 100644 --- a/EcosiaTests/Core/TabsTests.swift +++ b/EcosiaTests/Core/TabsTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class TabsTests: XCTestCase { diff --git a/EcosiaTests/Core/Tools/HTTPClientMock.swift b/EcosiaTests/Core/Tools/HTTPClientMock.swift index 39f7c0b074d2..8c41fec5a2eb 100644 --- a/EcosiaTests/Core/Tools/HTTPClientMock.swift +++ b/EcosiaTests/Core/Tools/HTTPClientMock.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import Foundation class HTTPClientMock: HTTPClient { diff --git a/EcosiaTests/Core/Tools/MockTimestampProvider.swift b/EcosiaTests/Core/Tools/MockTimestampProvider.swift index f2d06570bccf..472a8da9b941 100644 --- a/EcosiaTests/Core/Tools/MockTimestampProvider.swift +++ b/EcosiaTests/Core/Tools/MockTimestampProvider.swift @@ -1,5 +1,5 @@ import Foundation -@testable import Core +@testable import Ecosia final class MockTimestampProvider: TimestampProvider { diff --git a/EcosiaTests/Core/Tools/MockURLSessionProtocol.swift b/EcosiaTests/Core/Tools/MockURLSessionProtocol.swift index e697a9f64487..75005a327291 100644 --- a/EcosiaTests/Core/Tools/MockURLSessionProtocol.swift +++ b/EcosiaTests/Core/Tools/MockURLSessionProtocol.swift @@ -1,5 +1,5 @@ import Foundation -@testable import Core +@testable import Ecosia // Needed in spite of the already existing MockURLSession // since URLSession's async methods are not open diff --git a/EcosiaTests/Core/TreesProjectionTests.swift b/EcosiaTests/Core/TreesProjectionTests.swift index fd625a4e3226..5670898f795a 100644 --- a/EcosiaTests/Core/TreesProjectionTests.swift +++ b/EcosiaTests/Core/TreesProjectionTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class TreesProjectionTests: XCTestCase { diff --git a/EcosiaTests/Core/URLProviderDependantTests/ProductionURLProviderTests.swift b/EcosiaTests/Core/URLProviderDependantTests/ProductionURLProviderTests.swift index cc1379164283..87804d69dc2c 100644 --- a/EcosiaTests/Core/URLProviderDependantTests/ProductionURLProviderTests.swift +++ b/EcosiaTests/Core/URLProviderDependantTests/ProductionURLProviderTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class ProductionURLProviderTests: XCTestCase { diff --git a/EcosiaTests/Core/URLProviderDependantTests/StagingURLProviderTests.swift b/EcosiaTests/Core/URLProviderDependantTests/StagingURLProviderTests.swift index f2a390f0817f..a8ba879734bb 100644 --- a/EcosiaTests/Core/URLProviderDependantTests/StagingURLProviderTests.swift +++ b/EcosiaTests/Core/URLProviderDependantTests/StagingURLProviderTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class StagingURLProviderTests: XCTestCase { diff --git a/EcosiaTests/Core/URLProviderDependantTests/URLProviderTests.swift b/EcosiaTests/Core/URLProviderDependantTests/URLProviderTests.swift index 98d38834f945..121511d53453 100644 --- a/EcosiaTests/Core/URLProviderDependantTests/URLProviderTests.swift +++ b/EcosiaTests/Core/URLProviderDependantTests/URLProviderTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class URLProviderTests: XCTestCase { diff --git a/EcosiaTests/Core/URLRequestTests.swift b/EcosiaTests/Core/URLRequestTests.swift index 0784defa0df6..9cdb059516ce 100644 --- a/EcosiaTests/Core/URLRequestTests.swift +++ b/EcosiaTests/Core/URLRequestTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import Core +@testable import Ecosia final class URLRequestTests: XCTestCase { diff --git a/EcosiaTests/Core/URLTests.swift b/EcosiaTests/Core/URLTests.swift index aa758847b92b..12b416323659 100644 --- a/EcosiaTests/Core/URLTests.swift +++ b/EcosiaTests/Core/URLTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class URLTests: XCTestCase { diff --git a/EcosiaTests/Core/UnleashFeatureManagementSessionInitializerTests.swift b/EcosiaTests/Core/UnleashFeatureManagementSessionInitializerTests.swift index bb5e6a3db008..d140475647d6 100644 --- a/EcosiaTests/Core/UnleashFeatureManagementSessionInitializerTests.swift +++ b/EcosiaTests/Core/UnleashFeatureManagementSessionInitializerTests.swift @@ -1,6 +1,6 @@ import XCTest import Foundation -@testable import Core +@testable import Ecosia class UnleashFeatureManagementSessionInitializerTests: XCTestCase { diff --git a/EcosiaTests/Core/UnleashRefreshConfiguratorTests.swift b/EcosiaTests/Core/UnleashRefreshConfiguratorTests.swift index 4fcdb6e17d8b..38d8f7cc65a3 100644 --- a/EcosiaTests/Core/UnleashRefreshConfiguratorTests.swift +++ b/EcosiaTests/Core/UnleashRefreshConfiguratorTests.swift @@ -1,6 +1,6 @@ import Foundation -@testable import Core +@testable import Ecosia import XCTest final class UnleashRefreshConfiguratorTests: XCTestCase { diff --git a/EcosiaTests/Core/UnleashTests.swift b/EcosiaTests/Core/UnleashTests.swift index 3ae7dd3b269f..3f63b9e1767e 100644 --- a/EcosiaTests/Core/UnleashTests.swift +++ b/EcosiaTests/Core/UnleashTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class UnleashTests: XCTestCase { diff --git a/EcosiaTests/Core/UpgradeTests.swift b/EcosiaTests/Core/UpgradeTests.swift index 2b4895942f6b..edc46d5e4580 100644 --- a/EcosiaTests/Core/UpgradeTests.swift +++ b/EcosiaTests/Core/UpgradeTests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import Core +@testable import Ecosia final class UpgradeTests: XCTestCase { override func setUp() { diff --git a/EcosiaTests/Core/UserStateTests.swift b/EcosiaTests/Core/UserStateTests.swift index 5c4b2ca4b273..c60d5a21a543 100644 --- a/EcosiaTests/Core/UserStateTests.swift +++ b/EcosiaTests/Core/UserStateTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class UserStateTests: XCTestCase { diff --git a/EcosiaTests/Core/UserTests.swift b/EcosiaTests/Core/UserTests.swift index d699de4ec167..16bcd052f113 100644 --- a/EcosiaTests/Core/UserTests.swift +++ b/EcosiaTests/Core/UserTests.swift @@ -1,4 +1,4 @@ -@testable import Core +@testable import Ecosia import XCTest final class UserTests: XCTestCase { diff --git a/EcosiaTests/Core/Versions/User5_3.swift b/EcosiaTests/Core/Versions/User5_3.swift index e4e0629f8cf5..118b18ca651e 100644 --- a/EcosiaTests/Core/Versions/User5_3.swift +++ b/EcosiaTests/Core/Versions/User5_3.swift @@ -1,5 +1,5 @@ import Foundation -@testable import Core +@testable import Ecosia struct User5_3: Codable { var install: Date? diff --git a/EcosiaTests/EcosiaHomeViewModelTests.swift b/EcosiaTests/EcosiaHomeViewModelTests.swift index 0c372c5048af..9af8758a7bdb 100644 --- a/EcosiaTests/EcosiaHomeViewModelTests.swift +++ b/EcosiaTests/EcosiaHomeViewModelTests.swift @@ -5,7 +5,7 @@ import XCTest @testable import Client -@testable import Core +@testable import Ecosia class EcosiaHomeViewModelTests: XCTestCase { diff --git a/EcosiaTests/EcosiaInstallTypeTests.swift b/EcosiaTests/EcosiaInstallTypeTests.swift index 08d55e9fc26d..91e14a271c7c 100644 --- a/EcosiaTests/EcosiaInstallTypeTests.swift +++ b/EcosiaTests/EcosiaInstallTypeTests.swift @@ -4,7 +4,7 @@ import XCTest @testable import Client -@testable import Core +@testable import Ecosia final class EcosiaInstallTypeTests: XCTestCase { diff --git a/EcosiaTests/EcosiaNTPTooltipHighlightTests.swift b/EcosiaTests/EcosiaNTPTooltipHighlightTests.swift index b7746ee5cb6b..4a412190ab26 100644 --- a/EcosiaTests/EcosiaNTPTooltipHighlightTests.swift +++ b/EcosiaTests/EcosiaNTPTooltipHighlightTests.swift @@ -3,7 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import XCTest -@testable import Core +@testable import Ecosia @testable import Client class EcosiaNTPTooltipHighlightTests: XCTestCase { diff --git a/EcosiaTests/IntegrationTests/AppDelegateFeatureManagementIntegrationTests.swift b/EcosiaTests/IntegrationTests/AppDelegateFeatureManagementIntegrationTests.swift index 367793555a87..d10f86e8e95e 100644 --- a/EcosiaTests/IntegrationTests/AppDelegateFeatureManagementIntegrationTests.swift +++ b/EcosiaTests/IntegrationTests/AppDelegateFeatureManagementIntegrationTests.swift @@ -4,7 +4,7 @@ import XCTest @testable import Client -@testable import Core +@testable import Ecosia final class AppDelegateFeatureManagementIntegrationTests: XCTestCase { var appDelegate: AppDelegate! diff --git a/EcosiaTests/WhatsNewLocalDataProviderTests.swift b/EcosiaTests/WhatsNewLocalDataProviderTests.swift index 434d48f0c8aa..27ac7ccf1740 100644 --- a/EcosiaTests/WhatsNewLocalDataProviderTests.swift +++ b/EcosiaTests/WhatsNewLocalDataProviderTests.swift @@ -4,7 +4,7 @@ import XCTest @testable import Client -@testable import Core +@testable import Ecosia // This tests are dependant on WhatsNewLocalDataProvider.whatsNewItems hardcoded implementation final class WhatsNewLocalDataProviderTests: XCTestCase { From ce9e09a2cc78555b34380259288040674c2e3370 Mon Sep 17 00:00:00 2001 From: Dario Carlomagno Date: Wed, 11 Dec 2024 15:50:42 +0100 Subject: [PATCH 19/59] [MOB-3028] Snowplow's SPM Update --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 61205b01dacf..5130b056a3fd 100644 --- a/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Client.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -140,8 +140,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/snowplow/snowplow-ios-tracker.git", "state" : { - "revision" : "1e16a929cef8e944bd41dc36a1d2779e06bd0a3c", - "version" : "5.2.0" + "revision" : "c105d9f8b875f2442512c3c8b1c8bbe9c209a302", + "version" : "6.0.9" } }, { From 5389ff93b576d95855a673174f201862ddc2bf31 Mon Sep 17 00:00:00 2001 From: Dario Carlomagno Date: Wed, 11 Dec 2024 16:55:05 +0100 Subject: [PATCH 20/59] [MOB-3028] Update proj and swift files to make it a build successful and launch tests --- Client.xcodeproj/project.pbxproj | 52 ++++++++++++++++++- EcosiaTests/Analytics/AnalyticsSpyTests.swift | 1 + EcosiaTests/Analytics/AnalyticsTests.swift | 1 + EcosiaTests/Core/Bundle+EcosiaTests.swift | 11 ++++ EcosiaTests/Core/NewsTests.swift | 4 +- EcosiaTests/Core/ReferralsTests.swift | 2 +- EcosiaTests/Core/Tools/BookmarkFixtures.swift | 7 +-- EcosiaTests/Core/UnleashTests.swift | 4 +- .../EcosiaNTPTooltipHighlightTests.swift | 2 +- .../EcosiaOverlayModeManagerTests.swift | 1 - .../Mocks/MockAppVersionInfoProvider.swift | 1 + .../SnapshotTests/NTP/NTPComponentTests.swift | 2 +- EcosiaTests/SnapshotTests/NTP/NTPTests.swift | 2 +- EcosiaTests/VersionTests.swift | 1 + 14 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 EcosiaTests/Core/Bundle+EcosiaTests.swift diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index 9930afbd4aba..adfb27c725f1 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -207,6 +207,10 @@ 2C1298A72BF5EB1F005AE4E4 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 2C1298A42BF5EB16005AE4E4 /* PrivacyInfo.xcprivacy */; }; 2C1298A82BF5EE23005AE4E4 /* libStorage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FCAE21A1ABB51F800877008 /* libStorage.a */; }; 2C1298AF2BF602D3005AE4E4 /* DefaultSuggestedSites.swift in Sources */ = {isa = PBXBuildFile; fileRef = 394CF6CE1BAA493C00906917 /* DefaultSuggestedSites.swift */; }; + 2C423E272D0202530043D407 /* SnapshotBaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628E2CFDC5E900A040A7 /* SnapshotBaseTests.swift */; }; + 2C423E282D0202530043D407 /* SnapshotTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628F2CFDC5E900A040A7 /* SnapshotTestHelper.swift */; }; + 2C423E292D02029C0043D407 /* LocaleRetriever.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628B2CFDC5E900A040A7 /* LocaleRetriever.swift */; }; + 2C423E2A2D0203190043D407 /* MockProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 281B2BE91ADF4D90002917DC /* MockProfile.swift */; }; 2C49854E206173C800893DAE /* photon-colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C49854D206173C800893DAE /* photon-colors.swift */; }; 2C6189DE2B7B78ED006B70D7 /* LegacyTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9A179A20E69A7E00B12184 /* LegacyTheme.swift */; }; 2C6189E12B7B7922006B70D7 /* LegacyTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = EB9A179A20E69A7E00B12184 /* LegacyTheme.swift */; }; @@ -360,7 +364,6 @@ 2CAF5C052D00D1AB00D3DCDD /* LanguageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BD22D00D1AA00D3DCDD /* LanguageTests.swift */; }; 2CAF5C062D00D1AB00D3DCDD /* FavouritesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BD32D00D1AB00D3DCDD /* FavouritesTests.swift */; }; 2CAF5C072D00D1AB00D3DCDD /* URLRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAF5BD42D00D1AB00D3DCDD /* URLRequestTests.swift */; }; - 2CAF5C162D01B2E200D3DCDD /* Ecosia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; }; 2CAF5C172D01B2E200D3DCDD /* Ecosia.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1229356A2CE78D0A00EC1297 /* Ecosia.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 2CAF5C1D2D01B40B00D3DCDD /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = 2CAF5C1C2D01B40B00D3DCDD /* SwiftSoup */; }; 2CAF5C1F2D01B44400D3DCDD /* Sentry in Frameworks */ = {isa = PBXBuildFile; productRef = 2CAF5C1E2D01B44400D3DCDD /* Sentry */; }; @@ -534,6 +537,22 @@ 2CD266512CFF56CB00A040A7 /* ConnectionStatusImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2664E2CFF56CB00A040A7 /* ConnectionStatusImage.swift */; }; 2CD266522CFF56CB00A040A7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2664F2CFF56CB00A040A7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift */; }; 2CD266552CFF56EA00A040A7 /* WebsiteConnectionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD266532CFF56EA00A040A7 /* WebsiteConnectionStatus.swift */; }; + 2CD7E5F72D09DF5A0003B02B /* MockURLBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A9A09D528B01FD500B6F51E /* MockURLBarView.swift */; }; + 2CD7E5F82D09DF600003B02B /* MockOverlayModeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21B41A1B298B1876008BC0A2 /* MockOverlayModeManager.swift */; }; + 2CD7E5F92D09DF750003B02B /* ProfileTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0BA896491A250E6500C1010C /* ProfileTest.swift */; }; + 2CD7E5FA2D09DF7E0003B02B /* TopSitesHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A5BD9582878871B000FE773 /* TopSitesHelperTests.swift */; }; + 2CD7E5FB2D09DFE30003B02B /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262902CFDC5E900A040A7 /* String+Extension.swift */; }; + 2CD7E5FC2D09DFEA0003B02B /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262902CFDC5E900A040A7 /* String+Extension.swift */; }; + 2CD7E5FD2D09E19E0003B02B /* MockablePinnedSites.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45D5EDBF292D619000311934 /* MockablePinnedSites.swift */; }; + 2CD7E5FE2D09E1A80003B02B /* MockTabManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A36AC2B2886F27F00CDC0AD /* MockTabManager.swift */; }; + 2CD7E6002D09E3A50003B02B /* DependencyHelperMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A70EF18295E2E1600790249 /* DependencyHelperMock.swift */; }; + 2CD7E6012D09E3B30003B02B /* XCTestCaseExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3BA41671BD82F2200DA5457 /* XCTestCaseExtensions.swift */; }; + 2CD7E6022D09E3C20003B02B /* MockThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AA75A622A46272000533F8D /* MockThemeManager.swift */; }; + 2CD7E6032D09E3E30003B02B /* DeviceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD262882CFDC5E900A040A7 /* DeviceType.swift */; }; + 2CD7E6042D09E3ED0003B02B /* LocalizationOverrideTestingBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD2628C2CFDC5E900A040A7 /* LocalizationOverrideTestingBundle.swift */; }; + 2CD7E6052D09E43B0003B02B /* MockTabDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A475E8C29DB888E009C13FD /* MockTabDataStore.swift */; }; + 2CD7E6072D09E47E0003B02B /* Bundle+EcosiaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD7E6062D09E47E0003B02B /* Bundle+EcosiaTests.swift */; }; + 2CD7E6082D09E5DF0003B02B /* RustMozillaAppServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43BE578A278BA4D900491291 /* RustMozillaAppServices.framework */; }; 2F13E79B1AC0C02700D75081 /* StringExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F13E79A1AC0C02700D75081 /* StringExtensionsTests.swift */; }; 2F44FA1B1A9D426A00FD20CC /* TestHashExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F44FA1A1A9D426A00FD20CC /* TestHashExtensions.swift */; }; 2F44FB2C1A9D5D8500FD20CC /* Library.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F84B22261A09127C00AAB793 /* Library.xcassets */; }; @@ -2879,6 +2898,7 @@ 2CD2664E2CFF56CB00A040A7 /* ConnectionStatusImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionStatusImage.swift; sourceTree = ""; }; 2CD2664F2CFF56CB00A040A7 /* ConnectionStatusImage+WebsiteConnectionTypeStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConnectionStatusImage+WebsiteConnectionTypeStatus.swift"; sourceTree = ""; }; 2CD266532CFF56EA00A040A7 /* WebsiteConnectionStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebsiteConnectionStatus.swift; sourceTree = ""; }; + 2CD7E6062D09E47E0003B02B /* Bundle+EcosiaTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+EcosiaTests.swift"; sourceTree = ""; }; 2CE294442B7CDD05006C22B2 /* CoreAudioTypes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreAudioTypes.framework; path = System/Library/Frameworks/CoreAudioTypes.framework; sourceTree = SDKROOT; }; 2CEA6F781E93E3A600D4100E /* SearchSettingsUITest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchSettingsUITest.swift; sourceTree = ""; }; 2CEB48402BE0EE2600498471 /* Production.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Production.xcconfig; sourceTree = ""; }; @@ -8077,6 +8097,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2CD7E6082D09E5DF0003B02B /* RustMozillaAppServices.framework in Frameworks */, 122935742CE78D0A00EC1297 /* Ecosia.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -8107,7 +8128,6 @@ buildActionMask = 2147483647; files = ( 43A878FD27AB4A110071C372 /* RustMozillaAppServices.framework in Frameworks */, - 2CAF5C162D01B2E200D3DCDD /* Ecosia.framework in Frameworks */, 8A88815C2B2103AD009635AE /* WebEngine in Frameworks */, 8A88815A2B20FFE0009635AE /* GCDWebServers in Frameworks */, 5A9FF8492942454600DF9FBB /* Common in Frameworks */, @@ -8737,6 +8757,13 @@ path = Extensions; sourceTree = ""; }; + 2C423E2B2D0203580043D407 /* Tests */ = { + isa = PBXGroup; + children = ( + ); + path = Tests; + sourceTree = ""; + }; 2CABD71A2C11E07300A0750F /* PersistedGenerated */ = { isa = PBXGroup; children = ( @@ -9026,6 +9053,7 @@ 2CAF5BC92D00D1A900D3DCDD /* UserStateTests.swift */, 2CAF5BD12D00D1AA00D3DCDD /* UserTests.swift */, 2CAF5B9E2D00D1A600D3DCDD /* Versions */, + 2CD7E6062D09E47E0003B02B /* Bundle+EcosiaTests.swift */, ); path = Core; sourceTree = ""; @@ -9323,6 +9351,7 @@ 2CD265162CFDCB8A00A040A7 /* Ecosia */ = { isa = PBXGroup; children = ( + 2C423E2B2D0203580043D407 /* Tests */, 2CD266542CFF56EA00A040A7 /* Network */, 2CD266242CFE3E8500A040A7 /* Experiments */, 2CD266222CFE3AD900A040A7 /* Bookmarks */, @@ -14269,20 +14298,27 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2CD7E5F72D09DF5A0003B02B /* MockURLBarView.swift in Sources */, + 2C423E2A2D0203190043D407 /* MockProfile.swift in Sources */, 2CD263BF2CFDC5EB00A040A7 /* AnalyticsSpyTests.swift in Sources */, 2CAF5BF12D00D1AB00D3DCDD /* HistoryTests.swift in Sources */, + 2CD7E6012D09E3B30003B02B /* XCTestCaseExtensions.swift in Sources */, 2CAF5BDA2D00D1AB00D3DCDD /* MockURLSessionProtocol.swift in Sources */, 2CAF5BE82D00D1AB00D3DCDD /* SingularServiceTests.swift in Sources */, 2CD263C02CFDC5EB00A040A7 /* AnalyticsTests.swift in Sources */, + 2CD7E5FE2D09E1A80003B02B /* MockTabManager.swift in Sources */, + 2CD7E6002D09E3A50003B02B /* DependencyHelperMock.swift in Sources */, 2CAF5BF02D00D1AB00D3DCDD /* ReferralsModelTests.swift in Sources */, 2CAF5C022D00D1AB00D3DCDD /* PublishersTests.swift in Sources */, 2CAF5C062D00D1AB00D3DCDD /* FavouritesTests.swift in Sources */, + 2CD7E6022D09E3C20003B02B /* MockThemeManager.swift in Sources */, 2CAF5BD92D00D1AB00D3DCDD /* MockURLSession.swift in Sources */, 2CAF5BEB2D00D1AB00D3DCDD /* BookmarkParserTests.swift in Sources */, 2CAF5BD52D00D1AB00D3DCDD /* User5_3.swift in Sources */, 2CAF5BE92D00D1AB00D3DCDD /* UpgradeTests.swift in Sources */, 2CAF5BDC2D00D1AB00D3DCDD /* URLTests.swift in Sources */, 2CAF5C032D00D1AB00D3DCDD /* UnleashRefreshConfiguratorTests.swift in Sources */, + 2CD7E5FB2D09DFE30003B02B /* String+Extension.swift in Sources */, 2CD263B32CFDC5EB00A040A7 /* AppDelegateFeatureManagementIntegrationTests.swift in Sources */, 1229358D2CE78D5D00EC1297 /* BrazeServiceTests.swift in Sources */, 2CAF5BFE2D00D1AB00D3DCDD /* ReferralsTests.swift in Sources */, @@ -14291,6 +14327,7 @@ 2CAF5C012D00D1AB00D3DCDD /* InvestmentsProjectionTests.swift in Sources */, 2CAF5BDB2D00D1AB00D3DCDD /* ListTests.swift in Sources */, 2CD263B72CFDC5EB00A040A7 /* PrivateModeButtonTests.swift in Sources */, + 2CD7E5F82D09DF600003B02B /* MockOverlayModeManager.swift in Sources */, 2CAF5C042D00D1AB00D3DCDD /* UserTests.swift in Sources */, 2CAF5C002D00D1AB00D3DCDD /* CookieTests.swift in Sources */, 2CAF5BEA2D00D1AB00D3DCDD /* UnleashFeatureManagementSessionInitializerTests.swift in Sources */, @@ -14311,8 +14348,11 @@ 2CAF5BFF2D00D1AB00D3DCDD /* FinancialReportsTests.swift in Sources */, 2CAF5BFA2D00D1AB00D3DCDD /* StagingURLProviderTests.swift in Sources */, 2CAF5BEF2D00D1AB00D3DCDD /* StatisticsTests.swift in Sources */, + 2CD7E5F92D09DF750003B02B /* ProfileTest.swift in Sources */, 2CAF5BF62D00D1AB00D3DCDD /* TabsTests.swift in Sources */, 2CAF5BF82D00D1AB00D3DCDD /* UnleashTests.swift in Sources */, + 2CD7E5FD2D09E19E0003B02B /* MockablePinnedSites.swift in Sources */, + 2CD7E6072D09E47E0003B02B /* Bundle+EcosiaTests.swift in Sources */, 2CAF5BDD2D00D1AB00D3DCDD /* FeatureFlaggingSessionInitializerTests.swift in Sources */, 2CAF5BF52D00D1AB00D3DCDD /* SingularAdNetworkHelperTests.swift in Sources */, 2CD263B82CFDC5EB00A040A7 /* EcosiaNTPTooltipHighlightTests.swift in Sources */, @@ -14324,9 +14364,11 @@ 2CAF5C052D00D1AB00D3DCDD /* LanguageTests.swift in Sources */, 2CD263BA2CFDC5EB00A040A7 /* UnleashUserDefaultsSeedProgressManagerTests.swift in Sources */, 2CAF5BF92D00D1AB00D3DCDD /* ProductionURLProviderTests.swift in Sources */, + 2CD7E5FA2D09DF7E0003B02B /* TopSitesHelperTests.swift in Sources */, 2CAF5BD82D00D1AB00D3DCDD /* MockTimestampProvider.swift in Sources */, 2CAF5BFC2D00D1AB00D3DCDD /* UserStateTests.swift in Sources */, 2CAF5C072D00D1AB00D3DCDD /* URLRequestTests.swift in Sources */, + 2CD7E6052D09E43B0003B02B /* MockTabDataStore.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -14414,11 +14456,17 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2C423E292D02029C0043D407 /* LocaleRetriever.swift in Sources */, + 2C423E272D0202530043D407 /* SnapshotBaseTests.swift in Sources */, + 2C423E282D0202530043D407 /* SnapshotTestHelper.swift in Sources */, + 2CD7E6042D09E3ED0003B02B /* LocalizationOverrideTestingBundle.swift in Sources */, 2CAF5C272D01C33300D3DCDD /* EcosiaMockThemeManager.swift in Sources */, 2CAF5C262D01C32C00D3DCDD /* Welcome.swift in Sources */, 2CAF5C252D01C31900D3DCDD /* NTPTests.swift in Sources */, 2CAF5C242D01C30B00D3DCDD /* OnboardingTests.swift in Sources */, 2CAF5C232D01C2F300D3DCDD /* NTPComponentTests.swift in Sources */, + 2CD7E5FC2D09DFEA0003B02B /* String+Extension.swift in Sources */, + 2CD7E6032D09E3E30003B02B /* DeviceType.swift in Sources */, 2C69DA7D2C6244BE00D7F69F /* MockTabDataStore.swift in Sources */, 2C69DA782C62259D00D7F69F /* MockProfile.swift in Sources */, 2C69DA792C6225AE00D7F69F /* DependencyHelperMock.swift in Sources */, diff --git a/EcosiaTests/Analytics/AnalyticsSpyTests.swift b/EcosiaTests/Analytics/AnalyticsSpyTests.swift index ed8f11e77e89..b0e114d6fbb8 100644 --- a/EcosiaTests/Analytics/AnalyticsSpyTests.swift +++ b/EcosiaTests/Analytics/AnalyticsSpyTests.swift @@ -7,6 +7,7 @@ import Core import Storage import SnowplowTracker @testable import Client +@testable import Ecosia // MARK: - AnalyticsSpy diff --git a/EcosiaTests/Analytics/AnalyticsTests.swift b/EcosiaTests/Analytics/AnalyticsTests.swift index 21bd7c9d7f15..bfaad90f5f6e 100644 --- a/EcosiaTests/Analytics/AnalyticsTests.swift +++ b/EcosiaTests/Analytics/AnalyticsTests.swift @@ -6,6 +6,7 @@ import Foundation import XCTest @testable import Client +@testable import Ecosia final class AnalyticsTests: XCTestCase { diff --git a/EcosiaTests/Core/Bundle+EcosiaTests.swift b/EcosiaTests/Core/Bundle+EcosiaTests.swift new file mode 100644 index 000000000000..b5f340e9e187 --- /dev/null +++ b/EcosiaTests/Core/Bundle+EcosiaTests.swift @@ -0,0 +1,11 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Foundation + +extension Bundle { + static var ecosiaTests: Bundle { + Bundle(identifier: "com.ecosia.framework.EcosiaTests")! + } +} diff --git a/EcosiaTests/Core/NewsTests.swift b/EcosiaTests/Core/NewsTests.swift index 5fd4b144b8f2..efad6344d2f0 100644 --- a/EcosiaTests/Core/NewsTests.swift +++ b/EcosiaTests/Core/NewsTests.swift @@ -65,7 +65,7 @@ final class NewsTests: XCTestCase { let expect = expectation(description: "") let session = MockURLSession() - session.data = [try! .init(contentsOf: Bundle.module.url(forResource: "notifications", withExtension: "json")!)] + session.data = [try! .init(contentsOf: Bundle.ecosiaTests.url(forResource: "notifications", withExtension: "json")!)] let notifications = News() notifications.subscribe(self) { @@ -143,7 +143,7 @@ final class NewsTests: XCTestCase { func testCleanTextFromNetwork() { let expect = expectation(description: "") let session = MockURLSession() - session.data = [try! .init(contentsOf: Bundle.module.url(forResource: "notifications", withExtension: "json")!)] + session.data = [try! .init(contentsOf: Bundle.ecosiaTests.url(forResource: "notifications", withExtension: "json")!)] let notifications = News() notifications.subscribe(self) { $0.forEach { diff --git a/EcosiaTests/Core/ReferralsTests.swift b/EcosiaTests/Core/ReferralsTests.swift index b9cd91424049..47032b1e464c 100644 --- a/EcosiaTests/Core/ReferralsTests.swift +++ b/EcosiaTests/Core/ReferralsTests.swift @@ -15,7 +15,7 @@ final class ReferralsTests: XCTestCase { try? FileManager.default.removeItem(at: FileManager.user) httpClientMock = HTTPClientMock() - httpClientMock.data = try! Data(contentsOf: Bundle.module.url(forResource: "referrals", withExtension: "json")!) + httpClientMock.data = try! Data(contentsOf: Bundle.ecosiaTests.url(forResource: "referrals", withExtension: "json")!) httpClientMock.response = failureResponse // Force clean state diff --git a/EcosiaTests/Core/Tools/BookmarkFixtures.swift b/EcosiaTests/Core/Tools/BookmarkFixtures.swift index 74e0d979f3ba..e44754d03ae0 100644 --- a/EcosiaTests/Core/Tools/BookmarkFixtures.swift +++ b/EcosiaTests/Core/Tools/BookmarkFixtures.swift @@ -1,4 +1,5 @@ import Foundation +@testable import Ecosia enum BookmarkFixtures { enum Browser: String { @@ -11,12 +12,12 @@ enum BookmarkFixtures { switch self { case let .html(browser): return String( - data: try! Data(contentsOf: Bundle.module.url(forResource: "import_input_bookmark_\(browser.rawValue)", withExtension: "html")!), + data: try! Data(contentsOf: Bundle.ecosiaTests.url(forResource: "import_input_bookmark_\(browser.rawValue)", withExtension: "html")!), encoding: .utf8 )!.trimmingCharacters(in: .newlines) case let .debugString(browser): return String( - data: try! Data(contentsOf: Bundle.module.url(forResource: "import_output_bookmark_\(browser.rawValue)", withExtension: "txt")!), + data: try! Data(contentsOf: Bundle.ecosiaTests.url(forResource: "import_output_bookmark_\(browser.rawValue)", withExtension: "txt")!), encoding: .utf8 )!.trimmingCharacters(in: .newlines) } @@ -24,7 +25,7 @@ enum BookmarkFixtures { static var ecosiaExportedHtml: String { String( - data: try! Data(contentsOf: Bundle.module.url(forResource: "export_bookmark_ecosia", withExtension: "html")!), + data: try! Data(contentsOf: Bundle.ecosiaTests.url(forResource: "export_bookmark_ecosia", withExtension: "html")!), encoding: .utf8 )!.trimmingCharacters(in: .newlines) } diff --git a/EcosiaTests/Core/UnleashTests.swift b/EcosiaTests/Core/UnleashTests.swift index 3f63b9e1767e..e5b3fece91a8 100644 --- a/EcosiaTests/Core/UnleashTests.swift +++ b/EcosiaTests/Core/UnleashTests.swift @@ -144,7 +144,7 @@ extension UnleashTests { .staging } - var method: Core.HTTPMethod { + var method: Ecosia.HTTPMethod { .get } @@ -183,7 +183,7 @@ extension UnleashTests { .production } - var method: Core.HTTPMethod { + var method: Ecosia.HTTPMethod { .get } diff --git a/EcosiaTests/EcosiaNTPTooltipHighlightTests.swift b/EcosiaTests/EcosiaNTPTooltipHighlightTests.swift index 4a412190ab26..4eb148a1742f 100644 --- a/EcosiaTests/EcosiaNTPTooltipHighlightTests.swift +++ b/EcosiaTests/EcosiaNTPTooltipHighlightTests.swift @@ -8,7 +8,7 @@ import XCTest class EcosiaNTPTooltipHighlightTests: XCTestCase { - var user: Core.User! + var user: Ecosia.User! override func setUpWithError() throws { try? FileManager().removeItem(at: FileManager.user) diff --git a/EcosiaTests/EcosiaOverlayModeManagerTests.swift b/EcosiaTests/EcosiaOverlayModeManagerTests.swift index 4135b33f7f84..82d2c47f46e6 100644 --- a/EcosiaTests/EcosiaOverlayModeManagerTests.swift +++ b/EcosiaTests/EcosiaOverlayModeManagerTests.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import XCTest - @testable import Client final class EcosiaOverlayModeManagerTests: XCTestCase { diff --git a/EcosiaTests/Mocks/MockAppVersionInfoProvider.swift b/EcosiaTests/Mocks/MockAppVersionInfoProvider.swift index 6ad81ed7d533..4743c9f90e10 100644 --- a/EcosiaTests/Mocks/MockAppVersionInfoProvider.swift +++ b/EcosiaTests/Mocks/MockAppVersionInfoProvider.swift @@ -3,6 +3,7 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ @testable import Client +@testable import Ecosia struct MockAppVersionInfoProvider: AppVersionInfoProvider { diff --git a/EcosiaTests/SnapshotTests/NTP/NTPComponentTests.swift b/EcosiaTests/SnapshotTests/NTP/NTPComponentTests.swift index e2bc87fc40aa..83d7f57fedd2 100644 --- a/EcosiaTests/SnapshotTests/NTP/NTPComponentTests.swift +++ b/EcosiaTests/SnapshotTests/NTP/NTPComponentTests.swift @@ -6,7 +6,7 @@ import SnapshotTesting import XCTest import Common import Shared -import Core +import Ecosia import MozillaAppServices @testable import Client diff --git a/EcosiaTests/SnapshotTests/NTP/NTPTests.swift b/EcosiaTests/SnapshotTests/NTP/NTPTests.swift index c50ce90d95a1..ad58e42c087a 100644 --- a/EcosiaTests/SnapshotTests/NTP/NTPTests.swift +++ b/EcosiaTests/SnapshotTests/NTP/NTPTests.swift @@ -4,7 +4,7 @@ import SnapshotTesting import XCTest -import Core +import Ecosia import Common @testable import Client diff --git a/EcosiaTests/VersionTests.swift b/EcosiaTests/VersionTests.swift index e1b997b66024..5990c161f7b4 100644 --- a/EcosiaTests/VersionTests.swift +++ b/EcosiaTests/VersionTests.swift @@ -4,6 +4,7 @@ import XCTest @testable import Client +@testable import Ecosia final class VersionTests: XCTestCase { From fa133e726f6c14cf86d5684a852a1effc0741587 Mon Sep 17 00:00:00 2001 From: Dario Carlomagno Date: Wed, 11 Dec 2024 16:56:30 +0100 Subject: [PATCH 21/59] [MOB-3028] Add explicit `CFBundleDisplayName` --- Client/Info.plist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Client/Info.plist b/Client/Info.plist index 4f44cc3ff7a1..f5125d76d94f 100644 --- a/Client/Info.plist +++ b/Client/Info.plist @@ -31,6 +31,8 @@ 1 UILaunchStoryboardName EcosiaLaunchScreen.xib + CFBundleDisplayName + $(MOZ_BUNDLE_DISPLAY_NAME)