From 42c304fa97903a66dfa072851fb6d0859e906af4 Mon Sep 17 00:00:00 2001 From: Alessandro Boron Date: Tue, 2 Apr 2024 14:38:27 +1100 Subject: [PATCH] Update Lottie to version 4.4.1 (#2457) Task/Issue URL: https://app.asana.com/0/0/1206884309157951/f **Description**: Replace the DuckDuckGo-managed version of Lottie with [lottie-spm](https://github.com/airbnb/lottie-spm) (< 500kb). --- DuckDuckGo.xcodeproj/project.pbxproj | 78 ++++++++----------- .../xcshareddata/swiftpm/Package.resolved | 8 +- DuckDuckGo/Application/AppDelegate.swift | 1 + .../Common/Extensions/AnimationView.swift | 5 +- .../AppKit/MouseOverAnimationButton.swift | 14 ++-- .../View/Lottie/LottieAnimationCache.swift | 19 ++++- .../View/SwiftUI/FireAnimationView.swift | 4 +- DuckDuckGo/Fire/View/FireViewController.swift | 10 +-- .../AddressBarButtonsViewController.swift | 40 +++++----- .../View/AddressBarViewController.swift | 2 +- 10 files changed, 91 insertions(+), 90 deletions(-) diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 5ad1d2378a..eac447d9e7 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -695,7 +695,6 @@ 3706FCA9293F65D500E42796 /* ContentBlocking in Frameworks */ = {isa = PBXBuildFile; productRef = 3706FA76293F65D500E42796 /* ContentBlocking */; }; 3706FCAA293F65D500E42796 /* UserScript in Frameworks */ = {isa = PBXBuildFile; productRef = 3706FA78293F65D500E42796 /* UserScript */; }; 3706FCAB293F65D500E42796 /* TrackerRadarKit in Frameworks */ = {isa = PBXBuildFile; productRef = 3706FA6B293F65D500E42796 /* TrackerRadarKit */; }; - 3706FCAE293F65D500E42796 /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 3706FA6D293F65D500E42796 /* Lottie */; }; 3706FCAF293F65D500E42796 /* PrivacyDashboard in Frameworks */ = {isa = PBXBuildFile; productRef = 3706FA77293F65D500E42796 /* PrivacyDashboard */; }; 3706FCB4293F65D500E42796 /* CrashReports.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA693E5D2696E5B90007BB78 /* CrashReports.storyboard */; }; 3706FCB5293F65D500E42796 /* trackerData.json in Resources */ = {isa = PBXBuildFile; fileRef = 9833913027AAA4B500DAF119 /* trackerData.json */; }; @@ -1143,7 +1142,6 @@ 4B25377A2A11C01700610219 /* UserText+NetworkProtectionExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D607C2A0B29FA00BCD287 /* UserText+NetworkProtectionExtensions.swift */; }; 4B29759728281F0900187C4E /* FirefoxEncryptionKeyReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B29759628281F0900187C4E /* FirefoxEncryptionKeyReader.swift */; }; 4B2975992828285900187C4E /* FirefoxKeyReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B2975982828285900187C4E /* FirefoxKeyReaderTests.swift */; }; - 4B2AAAF529E70DEA0026AFC0 /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 4B2AAAF429E70DEA0026AFC0 /* Lottie */; }; 4B2D06292A11C0C900DE1F49 /* Bundle+VPN.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605E2A0B29FA00BCD287 /* Bundle+VPN.swift */; }; 4B2D062A2A11C0C900DE1F49 /* NetworkProtectionOptionKeyExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4D605F2A0B29FA00BCD287 /* NetworkProtectionOptionKeyExtension.swift */; }; 4B2D062C2A11C0E100DE1F49 /* Networking in Frameworks */ = {isa = PBXBuildFile; productRef = 4B2D062B2A11C0E100DE1F49 /* Networking */; }; @@ -1954,7 +1952,6 @@ 4B957BDC2AC7AE700062CA31 /* SwiftUIExtensions in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579372AC7AE700062CA31 /* SwiftUIExtensions */; }; 4B957BDD2AC7AE700062CA31 /* UserScript in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579302AC7AE700062CA31 /* UserScript */; }; 4B957BDE2AC7AE700062CA31 /* Configuration in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579322AC7AE700062CA31 /* Configuration */; }; - 4B957BE02AC7AE700062CA31 /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 4B95793A2AC7AE700062CA31 /* Lottie */; }; 4B957BE22AC7AE700062CA31 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579292AC7AE700062CA31 /* Sparkle */; }; 4B957BE32AC7AE700062CA31 /* Navigation in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579332AC7AE700062CA31 /* Navigation */; }; 4B957BE42AC7AE700062CA31 /* DDGSync in Frameworks */ = {isa = PBXBuildFile; productRef = 4B9579352AC7AE700062CA31 /* DDGSync */; }; @@ -2539,6 +2536,9 @@ 9FEE986D2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE986C2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift */; }; 9FEE986E2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE986C2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift */; }; 9FEE986F2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FEE986C2B85BA17002E44E8 /* AddEditBookmarkDialogCoordinatorViewModel.swift */; }; + 9FF521462BAA908500B9819B /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 9FF521452BAA908500B9819B /* Lottie */; }; + 9FF521482BAA909C00B9819B /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 9FF521472BAA909C00B9819B /* Lottie */; }; + 9FF5214A2BAA90C400B9819B /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 9FF521492BAA90C400B9819B /* Lottie */; }; AA06B6B72672AF8100F541C5 /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = AA06B6B62672AF8100F541C5 /* Sparkle */; }; AA0877B826D5160D00B05660 /* SafariVersionReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0877B726D5160D00B05660 /* SafariVersionReaderTests.swift */; }; AA0877BA26D5161D00B05660 /* WebKitVersionProviderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0877B926D5161D00B05660 /* WebKitVersionProviderTests.swift */; }; @@ -4711,6 +4711,7 @@ 4BF97AD32B43C43F00EB4240 /* NetworkProtectionUI in Frameworks */, 7B1459572B7D43E500047F2C /* NetworkProtectionProxy in Frameworks */, B6F7128229F6820A00594A45 /* QuickLookUI.framework in Frameworks */, + 9FF521482BAA909C00B9819B /* Lottie in Frameworks */, 984FD3BF299ACF35007334DD /* Bookmarks in Frameworks */, 37A5E2F0298AA1B20047046B /* Persistence in Frameworks */, 9DC70B1A2AA1FA5B005A844B /* LoginItems in Frameworks */, @@ -4733,7 +4734,6 @@ 4BF97AD52B43C43F00EB4240 /* NetworkProtection in Frameworks */, 3739326529AE4B39009346AE /* DDGSync in Frameworks */, 37DF000729F9C061002B7D3E /* SyncDataProviders in Frameworks */, - 3706FCAE293F65D500E42796 /* Lottie in Frameworks */, 37BA812F29B3CD6E0053F1A3 /* SyncUI in Frameworks */, 3706FCAF293F65D500E42796 /* PrivacyDashboard in Frameworks */, ); @@ -4861,7 +4861,6 @@ F1D43AF72B98E48F00BAB743 /* BareBonesBrowserKit in Frameworks */, 7B31FD902AD1257B0086AA24 /* NetworkProtectionIPC in Frameworks */, 4B957BDE2AC7AE700062CA31 /* Configuration in Frameworks */, - 4B957BE02AC7AE700062CA31 /* Lottie in Frameworks */, 4B957BE22AC7AE700062CA31 /* Sparkle in Frameworks */, 373FB4B52B4D6C57004C88D6 /* PreferencesViews in Frameworks */, 4B957BE32AC7AE700062CA31 /* Navigation in Frameworks */, @@ -4870,6 +4869,7 @@ 4B957BE52AC7AE700062CA31 /* OpenSSL in Frameworks */, 85E2BBD22B8F536F00DBEC7A /* History in Frameworks */, 4B957BE62AC7AE700062CA31 /* PrivacyDashboard in Frameworks */, + 9FF5214A2BAA90C400B9819B /* Lottie in Frameworks */, 7B8C083C2AE1268E00F4C67F /* PixelKit in Frameworks */, 85D44B8A2BA08D3B001B4AB5 /* Suggestions in Frameworks */, 4B957BE72AC7AE700062CA31 /* SyncDataProviders in Frameworks */, @@ -4950,13 +4950,13 @@ CBC83E3629B63D380008E19C /* Configuration in Frameworks */, 7B31FD8C2AD125620086AA24 /* NetworkProtectionIPC in Frameworks */, 37269EFB2B332F9E005E8E46 /* Common in Frameworks */, - 4B2AAAF529E70DEA0026AFC0 /* Lottie in Frameworks */, AA06B6B72672AF8100F541C5 /* Sparkle in Frameworks */, 1EA7B8D52B7E078C000330A4 /* Subscription in Frameworks */, B6B77BE8297973D4001E68A1 /* Navigation in Frameworks */, 3739326729AE4B42009346AE /* DDGSync in Frameworks */, 7BA59C9B2AE18B49009A97B1 /* SystemExtensionManager in Frameworks */, 371D00E129D8509400EC8598 /* OpenSSL in Frameworks */, + 9FF521462BAA908500B9819B /* Lottie in Frameworks */, 1E950E412912A10D0051A99B /* PrivacyDashboard in Frameworks */, 85D44B862BA08D29001B4AB5 /* Suggestions in Frameworks */, 37DF000529F9C056002B7D3E /* SyncDataProviders in Frameworks */, @@ -8738,7 +8738,6 @@ name = "DuckDuckGo Privacy Browser App Store"; packageProductDependencies = ( 3706FA6B293F65D500E42796 /* TrackerRadarKit */, - 3706FA6D293F65D500E42796 /* Lottie */, 3706FA71293F65D500E42796 /* BrowserServicesKit */, 3706FA76293F65D500E42796 /* ContentBlocking */, 3706FA77293F65D500E42796 /* PrivacyDashboard */, @@ -8766,6 +8765,7 @@ 4BCBE4572BA7E17800FC75A1 /* SubscriptionUI */, 85D44B872BA08D30001B4AB5 /* Suggestions */, 4BCBE4592BA7E17800FC75A1 /* Subscription */, + 9FF521472BAA909C00B9819B /* Lottie */, ); productName = DuckDuckGo; productReference = 3706FD05293F65D500E42796 /* DuckDuckGo App Store.app */; @@ -9040,7 +9040,6 @@ 4B9579362AC7AE700062CA31 /* SyncUI */, 4B9579372AC7AE700062CA31 /* SwiftUIExtensions */, 4B9579382AC7AE700062CA31 /* OpenSSL */, - 4B95793A2AC7AE700062CA31 /* Lottie */, 4B95793C2AC7AE700062CA31 /* SyncDataProviders */, 4B95793D2AC7AE700062CA31 /* NetworkProtectionUI */, 4B95793E2AC7AE700062CA31 /* NetworkProtection */, @@ -9056,6 +9055,7 @@ 85E2BBD12B8F536F00DBEC7A /* History */, F1D43AF62B98E48F00BAB743 /* BareBonesBrowserKit */, 85D44B892BA08D3B001B4AB5 /* Suggestions */, + 9FF521492BAA90C400B9819B /* Lottie */, ); productName = DuckDuckGo; productReference = 4B957C412AC7AE700062CA31 /* DuckDuckGo Privacy Pro.app */; @@ -9210,7 +9210,6 @@ 37BA812C29B3CD690053F1A3 /* SyncUI */, 378F44E329B4BDE900899924 /* SwiftUIExtensions */, 371D00E029D8509400EC8598 /* OpenSSL */, - 4B2AAAF429E70DEA0026AFC0 /* Lottie */, 37DF000429F9C056002B7D3E /* SyncDataProviders */, 4B4D60B02A0C83B900BCD287 /* NetworkProtectionUI */, EE7295E22A545B9A008C0991 /* NetworkProtection */, @@ -9228,6 +9227,7 @@ 1EA7B8D42B7E078C000330A4 /* Subscription */, F1D43AF22B98E47800BAB743 /* BareBonesBrowserKit */, 85D44B852BA08D29001B4AB5 /* Suggestions */, + 9FF521452BAA908500B9819B /* Lottie */, ); productName = DuckDuckGo; productReference = AA585D7E248FD31100E9A3E2 /* DuckDuckGo.app */; @@ -9364,10 +9364,10 @@ 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */, B6EC37F529B5DAAC001ACE79 /* XCRemoteSwiftPackageReference "swifter" */, 371D00DF29D8509400EC8598 /* XCRemoteSwiftPackageReference "OpenSSL-XCFramework" */, - 4B2AAAF329E70DEA0026AFC0 /* XCRemoteSwiftPackageReference "lottie-ios" */, B65CD8C92B316DF100A595BB /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, B6F997B92B8F352500476735 /* XCRemoteSwiftPackageReference "apple-toolbox" */, F1D43AF12B98E47800BAB743 /* XCRemoteSwiftPackageReference "BareBonesBrowser" */, + 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */, ); productRefGroup = AA585D7F248FD31100E9A3E2 /* Products */; projectDirPath = ""; @@ -14102,14 +14102,6 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 3706FA6E293F65D500E42796 /* XCRemoteSwiftPackageReference "lottie-ios" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/airbnb/lottie-ios"; - requirement = { - kind = exactVersion; - version = 3.3.0; - }; - }; 3706FA72293F65D500E42796 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; @@ -14134,14 +14126,6 @@ version = 3.1.4000; }; }; - 4B2AAAF329E70DEA0026AFC0 /* XCRemoteSwiftPackageReference "lottie-ios" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/duckduckgo/lottie-ios.git"; - requirement = { - kind = exactVersion; - version = 3.3.0; - }; - }; 4B95792A2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "Sparkle" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/sparkle-project/Sparkle.git"; @@ -14166,20 +14150,20 @@ version = 3.1.2000; }; }; - 4B95793B2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "lottie-ios" */ = { + 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/duckduckgo/lottie-ios.git"; + repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 3.3.0; + version = 132.0.1; }; }; - 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */ = { + 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; + repositoryURL = "https://github.com/airbnb/lottie-spm.git"; requirement = { kind = exactVersion; - version = 132.0.1; + version = 4.4.1; }; }; AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */ = { @@ -14288,11 +14272,6 @@ package = 3706FA6C293F65D500E42796 /* XCRemoteSwiftPackageReference "TrackerRadarKit" */; productName = TrackerRadarKit; }; - 3706FA6D293F65D500E42796 /* Lottie */ = { - isa = XCSwiftPackageProductDependency; - package = 3706FA6E293F65D500E42796 /* XCRemoteSwiftPackageReference "lottie-ios" */; - productName = Lottie; - }; 3706FA71293F65D500E42796 /* BrowserServicesKit */ = { isa = XCSwiftPackageProductDependency; package = 3706FA72293F65D500E42796 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14435,11 +14414,6 @@ isa = XCSwiftPackageProductDependency; productName = PixelKit; }; - 4B2AAAF429E70DEA0026AFC0 /* Lottie */ = { - isa = XCSwiftPackageProductDependency; - package = 4B2AAAF329E70DEA0026AFC0 /* XCRemoteSwiftPackageReference "lottie-ios" */; - productName = Lottie; - }; 4B2D062B2A11C0E100DE1F49 /* Networking */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14553,11 +14527,6 @@ package = 4B9579392AC7AE700062CA31 /* XCRemoteSwiftPackageReference "OpenSSL-XCFramework" */; productName = OpenSSL; }; - 4B95793A2AC7AE700062CA31 /* Lottie */ = { - isa = XCSwiftPackageProductDependency; - package = 4B95793B2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "lottie-ios" */; - productName = Lottie; - }; 4B95793C2AC7AE700062CA31 /* SyncDataProviders */ = { isa = XCSwiftPackageProductDependency; package = 4B95792C2AC7AE700062CA31 /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; @@ -14803,6 +14772,21 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Networking; }; + 9FF521452BAA908500B9819B /* Lottie */ = { + isa = XCSwiftPackageProductDependency; + package = 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */; + productName = Lottie; + }; + 9FF521472BAA909C00B9819B /* Lottie */ = { + isa = XCSwiftPackageProductDependency; + package = 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */; + productName = Lottie; + }; + 9FF521492BAA90C400B9819B /* Lottie */ = { + isa = XCSwiftPackageProductDependency; + package = 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */; + productName = Lottie; + }; AA06B6B62672AF8100F541C5 /* Sparkle */ = { isa = XCSwiftPackageProductDependency; package = AA06B6B52672AF8100F541C5 /* XCRemoteSwiftPackageReference "Sparkle" */; diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 50e682cf78..cb0773b436 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -64,12 +64,12 @@ } }, { - "identity" : "lottie-ios", + "identity" : "lottie-spm", "kind" : "remoteSourceControl", - "location" : "https://github.com/duckduckgo/lottie-ios.git", + "location" : "https://github.com/airbnb/lottie-spm.git", "state" : { - "revision" : "abf5510e261c85ffddd29de0bca9b72592ea2bdd", - "version" : "3.3.0" + "revision" : "3bd43e12d6fb54654366a61f7cfaca787318b8ce", + "version" : "4.4.1" } }, { diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift index a76b942094..e80ea137b2 100644 --- a/DuckDuckGo/Application/AppDelegate.swift +++ b/DuckDuckGo/Application/AppDelegate.swift @@ -31,6 +31,7 @@ import PixelKit import ServiceManagement import SyncDataProviders import UserNotifications +import Lottie #if NETWORK_PROTECTION import NetworkProtection diff --git a/DuckDuckGo/Common/Extensions/AnimationView.swift b/DuckDuckGo/Common/Extensions/AnimationView.swift index 548086307d..b38b5845bf 100644 --- a/DuckDuckGo/Common/Extensions/AnimationView.swift +++ b/DuckDuckGo/Common/Extensions/AnimationView.swift @@ -18,11 +18,12 @@ import Foundation import Lottie +import AppKit -extension AnimationView { +extension LottieAnimationView { convenience init?(named animationName: String, imageProvider: AnimationImageProvider? = nil) { - guard let animation = Animation.named(animationName, animationCache: LottieAnimationCache.shared) else { + guard let animation = LottieAnimation.named(animationName, animationCache: LottieAnimationCache.shared) else { return nil } diff --git a/DuckDuckGo/Common/View/AppKit/MouseOverAnimationButton.swift b/DuckDuckGo/Common/View/AppKit/MouseOverAnimationButton.swift index bcd8494624..31fcde1ebf 100644 --- a/DuckDuckGo/Common/View/AppKit/MouseOverAnimationButton.swift +++ b/DuckDuckGo/Common/View/AppKit/MouseOverAnimationButton.swift @@ -78,16 +78,16 @@ final class MouseOverAnimationButton: AddressBarButton { } struct AnimationViews { - let aqua: AnimationView - let dark: AnimationView + let aqua: LottieAnimationView + let dark: LottieAnimationView } private var animationViewCache: AnimationViews? private func loadAnimationViews() { guard let animationNames = animationNames, - let aquaAnimationView = AnimationView(named: animationNames.aqua), - let darkAnimationView = AnimationView(named: animationNames.dark) else { + let aquaAnimationView = LottieAnimationView(named: animationNames.aqua), + let darkAnimationView = LottieAnimationView(named: animationNames.dark) else { assertionFailure("Missing animation names or animation files in the bundle") return } @@ -97,7 +97,7 @@ final class MouseOverAnimationButton: AddressBarButton { dark: darkAnimationView) } - private var currentAnimationView: AnimationView? + private var currentAnimationView: LottieAnimationView? private func updateAnimationView() { guard let animationViewCache = animationViewCache else { @@ -105,12 +105,12 @@ final class MouseOverAnimationButton: AddressBarButton { } let isAquaMode = NSApp.effectiveAppearance.name == .aqua - let newAnimationView: AnimationView + let newAnimationView: LottieAnimationView // Animation view causes problems in tests if case .normal = NSApp.runType { newAnimationView = isAquaMode ? animationViewCache.aqua : animationViewCache.dark } else { - newAnimationView = AnimationView() + newAnimationView = LottieAnimationView() } guard currentAnimationView?.identifier != newAnimationView.identifier else { diff --git a/DuckDuckGo/Common/View/Lottie/LottieAnimationCache.swift b/DuckDuckGo/Common/View/Lottie/LottieAnimationCache.swift index b8fc5091d2..209b2db7df 100644 --- a/DuckDuckGo/Common/View/Lottie/LottieAnimationCache.swift +++ b/DuckDuckGo/Common/View/Lottie/LottieAnimationCache.swift @@ -22,21 +22,32 @@ import Lottie final class LottieAnimationCache: AnimationCacheProvider { static let shared = LottieAnimationCache() + private let lock = NSRecursiveLock() - private var cache = [String: Animation]() + private var cache: [String: LottieAnimation] = [:] - func animation(forKey: String) -> Animation? { + func animation(forKey: String) -> LottieAnimation? { + lock.lock() + defer { lock.unlock() } return cache[forKey] } - func setAnimation(_ animation: Animation, forKey: String) { + func setAnimation(_ animation: LottieAnimation, forKey: String) { + lock.lock() + defer { lock.unlock() } if cache[forKey] == nil { cache[forKey] = animation } } func clearCache() { - cache = [String: Animation]() + lock.lock() + defer { lock.unlock() } + cache = [String: LottieAnimation]() } } + +// `AnimationCacheProvider` conforms now to `Sendable`. This generates the warning `Stored property 'cache' of 'Sendable'-conforming class 'LottieAnimationCache' is mutable`. +// Implemented a lock mechanism and removed compiler strict check for Sendable requirement. +extension LottieAnimationCache: @unchecked Sendable {} diff --git a/DuckDuckGo/Common/View/SwiftUI/FireAnimationView.swift b/DuckDuckGo/Common/View/SwiftUI/FireAnimationView.swift index 28798afbe0..d70c4cdb61 100644 --- a/DuckDuckGo/Common/View/SwiftUI/FireAnimationView.swift +++ b/DuckDuckGo/Common/View/SwiftUI/FireAnimationView.swift @@ -21,12 +21,12 @@ import Lottie struct FireAnimation: NSViewRepresentable { - static let animation = Animation.named("01_Fire_really_small", animationCache: LottieAnimationCache.shared) + static let animation = LottieAnimation.named("01_Fire_really_small", animationCache: LottieAnimationCache.shared) func makeNSView(context: NSViewRepresentableContext) -> NSView { let view = NSView(frame: .zero) - let animationView = AnimationView(animation: Self.animation) + let animationView = LottieAnimationView(animation: Self.animation) animationView.contentMode = .scaleAspectFill animationView.loopMode = .playOnce animationView.play { _ in diff --git a/DuckDuckGo/Fire/View/FireViewController.swift b/DuckDuckGo/Fire/View/FireViewController.swift index 1529734b5b..1b82d96eb8 100644 --- a/DuckDuckGo/Fire/View/FireViewController.swift +++ b/DuckDuckGo/Fire/View/FireViewController.swift @@ -41,7 +41,7 @@ final class FireViewController: NSViewController { @IBOutlet weak var progressIndicatorWrapper: NSView! @IBOutlet weak var progressIndicator: NSProgressIndicator! @IBOutlet weak var progressIndicatorWrapperBG: NSView! - private var fireAnimationView: AnimationView? + private var fireAnimationView: LottieAnimationView? private var fireAnimationViewLoadingTask: Task<(), Never>? static func create(tabCollectionViewModel: TabCollectionViewModel, fireViewModel: FireViewModel? = nil) -> FireViewController { @@ -226,11 +226,11 @@ private actor FireAnimationViewLoader { static let shared: FireAnimationViewLoader = .init(animationName: FireViewController.Const.animationName) @MainActor - func createAnimationView() async -> AnimationView? { + func createAnimationView() async -> LottieAnimationView? { guard let animation = await animation else { return nil } - let view = AnimationView(animation: animation) + let view = LottieAnimationView(animation: animation) view.identifier = .init(rawValue: animationName) return view } @@ -241,7 +241,7 @@ private actor FireAnimationViewLoader { private let animationName: String - private var animation: Animation? { - Animation.named(animationName, animationCache: LottieAnimationCache.shared) + private var animation: LottieAnimation? { + LottieAnimation.named(animationName, animationCache: LottieAnimationCache.shared) } } diff --git a/DuckDuckGo/NavigationBar/View/AddressBarButtonsViewController.swift b/DuckDuckGo/NavigationBar/View/AddressBarButtonsViewController.swift index 2457def59b..7afc044118 100644 --- a/DuckDuckGo/NavigationBar/View/AddressBarButtonsViewController.swift +++ b/DuckDuckGo/NavigationBar/View/AddressBarButtonsViewController.swift @@ -90,11 +90,11 @@ final class AddressBarButtonsViewController: NSViewController { @IBOutlet weak var buttonsContainer: NSStackView! @IBOutlet weak var animationWrapperView: NSView! - var trackerAnimationView1: AnimationView! - var trackerAnimationView2: AnimationView! - var trackerAnimationView3: AnimationView! - var shieldAnimationView: AnimationView! - var shieldDotAnimationView: AnimationView! + var trackerAnimationView1: LottieAnimationView! + var trackerAnimationView2: LottieAnimationView! + var trackerAnimationView3: LottieAnimationView! + var shieldAnimationView: LottieAnimationView! + var shieldDotAnimationView: LottieAnimationView! @IBOutlet weak var notificationAnimationView: NavigationBarBadgeAnimationView! @IBOutlet weak var permissionButtons: NSView! @@ -532,13 +532,13 @@ final class AddressBarButtonsViewController: NSViewController { externalSchemeButton.sendAction(on: .leftMouseDown) } - private var animationViewCache = [String: AnimationView]() - private func getAnimationView(for animationName: String) -> AnimationView? { + private var animationViewCache = [String: LottieAnimationView]() + private func getAnimationView(for animationName: String) -> LottieAnimationView? { if let animationView = animationViewCache[animationName] { return animationView } - guard let animationView = AnimationView(named: animationName, + guard let animationView = LottieAnimationView(named: animationName, imageProvider: trackerAnimationImageProvider) else { assertionFailure("Missing animation file") return nil @@ -553,20 +553,21 @@ final class AddressBarButtonsViewController: NSViewController { } private func setupAnimationViews() { - func addAndLayoutAnimationViewIfNeeded(animationView: AnimationView?, animationName: String) -> AnimationView { + func addAndLayoutAnimationViewIfNeeded(animationView: LottieAnimationView?, animationName: String, renderingEngine: Lottie.RenderingEngineOption = .automatic) -> LottieAnimationView { if let animationView = animationView, animationView.identifier?.rawValue == animationName { return animationView } animationView?.removeFromSuperview() - let newAnimationView: AnimationView + let newAnimationView: LottieAnimationView // For unknown reason, this caused infinite execution of various unit tests. if NSApp.runType.requiresEnvironment { - newAnimationView = getAnimationView(for: animationName) ?? AnimationView() + newAnimationView = getAnimationView(for: animationName) ?? LottieAnimationView() } else { - newAnimationView = AnimationView() + newAnimationView = LottieAnimationView() } + newAnimationView.configuration = LottieConfiguration(renderingEngine: renderingEngine) animationWrapperView.addAndLayout(newAnimationView) newAnimationView.isHidden = true return newAnimationView @@ -575,11 +576,14 @@ final class AddressBarButtonsViewController: NSViewController { let isAquaMode = NSApp.effectiveAppearance.name == .aqua trackerAnimationView1 = addAndLayoutAnimationViewIfNeeded(animationView: trackerAnimationView1, - animationName: isAquaMode ? "trackers-1" : "dark-trackers-1") + animationName: isAquaMode ? "trackers-1" : "dark-trackers-1", + renderingEngine: .mainThread) trackerAnimationView2 = addAndLayoutAnimationViewIfNeeded(animationView: trackerAnimationView2, - animationName: isAquaMode ? "trackers-2" : "dark-trackers-2") + animationName: isAquaMode ? "trackers-2" : "dark-trackers-2", + renderingEngine: .mainThread) trackerAnimationView3 = addAndLayoutAnimationViewIfNeeded(animationView: trackerAnimationView3, - animationName: isAquaMode ? "trackers-3" : "dark-trackers-3") + animationName: isAquaMode ? "trackers-3" : "dark-trackers-3", + renderingEngine: .mainThread) shieldAnimationView = addAndLayoutAnimationViewIfNeeded(animationView: shieldAnimationView, animationName: isAquaMode ? "shield" : "dark-shield") shieldDotAnimationView = addAndLayoutAnimationViewIfNeeded(animationView: shieldDotAnimationView, @@ -819,7 +823,7 @@ final class AddressBarButtonsViewController: NSViewController { break } - var animationView: AnimationView + var animationView: LottieAnimationView if url.scheme == "http" { animationView = shieldDotAnimationView } else { @@ -838,7 +842,7 @@ final class AddressBarButtonsViewController: NSViewController { let lastTrackerImages = PrivacyIconViewModel.trackerImages(from: trackerInfo) trackerAnimationImageProvider.lastTrackerImages = lastTrackerImages - let trackerAnimationView: AnimationView? + let trackerAnimationView: LottieAnimationView? switch lastTrackerImages.count { case 0: trackerAnimationView = nil case 1: trackerAnimationView = trackerAnimationView1 @@ -862,7 +866,7 @@ final class AddressBarButtonsViewController: NSViewController { private func stopAnimations(trackerAnimations: Bool = true, shieldAnimations: Bool = true, badgeAnimations: Bool = true) { - func stopAnimation(_ animationView: AnimationView) { + func stopAnimation(_ animationView: LottieAnimationView) { if animationView.isAnimationPlaying || !animationView.isHidden { animationView.isHidden = true animationView.stop() diff --git a/DuckDuckGo/NavigationBar/View/AddressBarViewController.swift b/DuckDuckGo/NavigationBar/View/AddressBarViewController.swift index 256138f56e..04cd4cb362 100644 --- a/DuckDuckGo/NavigationBar/View/AddressBarViewController.swift +++ b/DuckDuckGo/NavigationBar/View/AddressBarViewController.swift @@ -521,7 +521,7 @@ extension AddressBarViewController: AddressBarButtonsViewControllerDelegate { fileprivate extension NSView { var shouldShowArrowCursor: Bool { - self is NSButton || self is AnimationView + self is NSButton || self is LottieAnimationView } }