diff --git a/DuckDuckGo/FavoritesViewModel.swift b/DuckDuckGo/FavoritesViewModel.swift index fac9571bd4..2853813183 100644 --- a/DuckDuckGo/FavoritesViewModel.swift +++ b/DuckDuckGo/FavoritesViewModel.swift @@ -37,6 +37,10 @@ protocol NewTabPageFavoriteDataSource { func removeFavorite(_ favorite: Favorite) } +protocol FavoritesFaviconCaching { + func populateFavicon(for domain: String, intoCache: FaviconsCacheType, fromCache: FaviconsCacheType?) +} + struct FavoritesSlice { let items: [FavoriteItem] let isCollapsible: Bool @@ -52,6 +56,7 @@ class FavoritesViewModel: ObservableObject { private var cancellables = Set() private let favoriteDataSource: NewTabPageFavoriteDataSource + private let faviconsCache: FavoritesFaviconCaching private let pixelFiring: PixelFiring.Type private let dailyPixelFiring: DailyPixelFiring.Type @@ -64,6 +69,7 @@ class FavoritesViewModel: ObservableObject { init(isNewTabPageCustomizationEnabled: Bool = false, favoriteDataSource: NewTabPageFavoriteDataSource, faviconLoader: FavoritesFaviconLoading, + faviconsCache: FavoritesFaviconCaching = Favicons.shared, pixelFiring: PixelFiring.Type = Pixel.self, dailyPixelFiring: DailyPixelFiring.Type = DailyPixel.self) { self.favoriteDataSource = favoriteDataSource @@ -71,6 +77,7 @@ class FavoritesViewModel: ObservableObject { self.dailyPixelFiring = dailyPixelFiring self.isNewTabPageCustomizationEnabled = isNewTabPageCustomizationEnabled self.isCollapsed = isNewTabPageCustomizationEnabled + self.faviconsCache = faviconsCache self.faviconLoader = MissingFaviconWrapper(loader: faviconLoader, onFaviconMissing: { [weak self] in guard let self else { return } @@ -130,7 +137,9 @@ class FavoritesViewModel: ObservableObject { pixelFiring.fire(.favoriteLaunchedNTP, withAdditionalParameters: [:]) dailyPixelFiring.fireDaily(.favoriteLaunchedNTPDaily) - Favicons.shared.loadFavicon(forDomain: url.host, intoCache: .fireproof, fromCache: .tabs) + if let host = url.host { + faviconsCache.populateFavicon(for: host, intoCache: .fireproof, fromCache: .tabs) + } onFavoriteURLSelected?(url) } @@ -231,3 +240,9 @@ private extension FavoriteItem { } } } + +extension Favicons: FavoritesFaviconCaching { + func populateFavicon(for domain: String, intoCache: FaviconsCacheType, fromCache: FaviconsCacheType?) { + loadFavicon(forDomain: domain, intoCache: intoCache, fromCache: fromCache) + } +} diff --git a/DuckDuckGoTests/NewTabPageFavoritesModelTests.swift b/DuckDuckGoTests/NewTabPageFavoritesModelTests.swift index 758ddde88e..d157929625 100644 --- a/DuckDuckGoTests/NewTabPageFavoritesModelTests.swift +++ b/DuckDuckGoTests/NewTabPageFavoritesModelTests.swift @@ -166,7 +166,8 @@ final class NewTabPageFavoritesModelTests: XCTestCase { private func createSUT(isNewTabPageCustomizationEnabled: Bool = true) -> FavoritesViewModel { FavoritesViewModel(isNewTabPageCustomizationEnabled: isNewTabPageCustomizationEnabled, favoriteDataSource: favoriteDataSource, - faviconLoader: FavoritesFaviconLoader(), + faviconLoader: MockFavoritesFaviconLoading(), + faviconsCache: MockFavoritesFaviconCaching(), pixelFiring: PixelFiringMock.self, dailyPixelFiring: PixelFiringMock.self) } @@ -205,3 +206,23 @@ private extension FavoriteItem { } } } + +private final class MockFavoritesFaviconLoading: FavoritesFaviconLoading { + func loadFavicon(for favorite: Favorite, size: CGFloat) async -> Favicon? { + nil + } + + func fakeFavicon(for favorite: Favorite, size: CGFloat) -> Favicon { + Favicon(image: .init(), isUsingBorder: false, isFake: false) + } + + func existingFavicon(for favorite: Favorite, size: CGFloat) -> Favicon? { + nil + } +} + +private final class MockFavoritesFaviconCaching: FavoritesFaviconCaching { + func populateFavicon(for domain: String, intoCache: FaviconsCacheType, fromCache: FaviconsCacheType?) { + + } +}