Skip to content

Commit

Permalink
Merge release/1.111.0 into main
Browse files Browse the repository at this point in the history
  • Loading branch information
daxmobile authored Oct 23, 2024
2 parents f6cbb0f + f0e812e commit 3618f63
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 33 deletions.
2 changes: 1 addition & 1 deletion Configuration/BuildNumber.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
CURRENT_PROJECT_VERSION = 286
CURRENT_PROJECT_VERSION = 287
11 changes: 1 addition & 10 deletions DuckDuckGo/Bookmarks/Services/BookmarkStoreMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,7 @@ final class BookmarkStoreMock: BookmarkStore {
}
}
var indexInFavoritesArray = 0
store?.save(
entitiesAtIndices: entities.map { entity in
if let bookmark = entity as? Bookmark, bookmark.isFavorite {
let result: (BaseBookmarkEntity, Int?, Int?) = (bookmark, nil, indexInFavoritesArray)
indexInFavoritesArray += 1
return result
}

return (entity, nil, nil)
}, completion: { _ in })
store?.save(entitiesAtIndices: entities.map { ($0, nil, nil) }, completion: { _ in })
}
}

Expand Down
78 changes: 68 additions & 10 deletions DuckDuckGo/Bookmarks/Services/LocalBookmarkStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ final class LocalBookmarkStore: BookmarkStore {
move(entities: managedObjects, to: insertionIndices, within: parentEntity)
}

try restoreFavorites(entitiesAtIndices, entitiesByUUID: entitiesByUUID, in: context)
try handleFavorites(entitiesAtIndices, entitiesByUUID: entitiesByUUID, in: context)
}, onError: { [weak self] error in
self?.commonOnSaveErrorHandler(error)
DispatchQueue.main.async { completion(error) }
Expand Down Expand Up @@ -974,18 +974,41 @@ final class LocalBookmarkStore: BookmarkStore {
return (entitiesByUUID, objectsToInsertIntoParent)
}

/// Restores entities marked as favorites into the appropriate favorites folder.
private func handleFavorites(_ entitiesAtIndices: [BookmarkEntityAtIndex],
entitiesByUUID: [String: BookmarkEntity],
in context: NSManagedObjectContext) throws {
let displayedFavoritesFolder = try fetchDisplayedFavoritesFolder(in: context)
let favoritesFoldersWithoutDisplayed = fetchOtherFavoritesFolders(in: context)

try restoreFavorites(entitiesAtIndices,
entitiesByUUID: entitiesByUUID,
displayedFavoritesFolder: displayedFavoritesFolder,
favoritesFoldersWithoutDisplayed: favoritesFoldersWithoutDisplayed,
in: context)

try insertNewFavorites(entitiesAtIndices,
entitiesByUUID: entitiesByUUID,
displayedFavoritesFolder: displayedFavoritesFolder,
favoritesFoldersWithoutDisplayed: favoritesFoldersWithoutDisplayed,
in: context)
}

/// Restores favorite bookmark entities to their correct positions within the favorites list.
///
/// - Parameters:
/// - entitiesAtIndices: An array of `BookmarkEntityAtIndex`, containing entities with their target indices.
/// - entitiesByUUID: A dictionary mapping UUID strings to corresponding `BookmarkEntity` objects.
/// - context: The managed object context for interacting with Core Data.
/// - Throws: An error if the displayed favorites folder cannot be retrieved.
/// - entitiesAtIndices: An array of `BookmarkEntityAtIndex` objects, containing bookmark entities along with their respective indices.
/// - entitiesByUUID: A dictionary mapping UUID strings to `BookmarkEntity` objects, providing quick access to entities by their unique identifiers.
/// - displayedFavoritesFolder: The `BookmarkEntity` representing the currently displayed folder of favorites.
/// - favoritesFoldersWithoutDisplayed: An array of `BookmarkEntity` objects representing all other favorites folders, excluding the currently displayed folder.
/// - context: The `NSManagedObjectContext` used to perform Core Data operations.
///
/// - Throws: This function can throw errors if adding an entity to the favorites fails during Core Data operations.
///
private func restoreFavorites(_ entitiesAtIndices: [BookmarkEntityAtIndex],
entitiesByUUID: [String: BookmarkEntity],
displayedFavoritesFolder: BookmarkEntity,
favoritesFoldersWithoutDisplayed: [BookmarkEntity],
in context: NSManagedObjectContext) throws {
let displayedFavoritesFolder = try fetchDisplayedFavoritesFolder(in: context)
let favoritesFoldersWithoutDisplayed = fetchOtherFavoritesFolders(in: context)

let sortedEntitiesByFavoritesIndex = sortEntitiesByFavoritesIndex(entitiesAtIndices)
let adjustedIndices = calculateAdjustedIndices(for: sortedEntitiesByFavoritesIndex, in: displayedFavoritesFolder)

Expand All @@ -1003,6 +1026,41 @@ final class LocalBookmarkStore: BookmarkStore {
}
}

/// Inserts new favorite bookmark entities into the favorites list if they meet certain conditions.
///
/// - Parameters:
/// - entitiesAtIndices: An array of `BookmarkEntityAtIndex` objects, which contain bookmark entities and their respective indices.
/// - entitiesByUUID: A dictionary mapping UUID strings to `BookmarkEntity` objects, providing quick access to entities by their unique identifiers.
/// - displayedFavoritesFolder: The `BookmarkEntity` representing the currently displayed folder of favorites.
/// - favoritesFoldersWithoutDisplayed: An array of `BookmarkEntity` objects representing all other favorites folders, excluding the currently displayed folder.
/// - context: The `NSManagedObjectContext` used to perform Core Data operations.
///
/// - Throws: This function can throw errors if adding an entity to the favorites fails during the Core Data operations.
///
/// - Discussion:
/// This function iterates through the list of entities with their respective indices (`entitiesAtIndices`). For each entity:
/// - If the entity is a `Bookmark`, is marked as a favorite (`isFavorite`), and does not have an index in the favorites array (`indexInFavoritesArray == nil`), it is considered new, so we need to insert it.
/// - The `addEntityToFavorites` function is then called to add the bookmark to the list of favorites. The entity is added without specifying an index (`at: nil`), allowing it to be inserted at a default position (last position).
/// - The function uses `entitiesByUUID` to resolve relationships between entities, as well as the `displayedFavoritesFolder` and `favoritesFoldersWithoutDisplayed` to ensure that the entity is added correctly to the appropriate folder structure.
private func insertNewFavorites(_ entitiesAtIndices: [BookmarkEntityAtIndex],
entitiesByUUID: [String: BookmarkEntity],
displayedFavoritesFolder: BookmarkEntity,
favoritesFoldersWithoutDisplayed: [BookmarkEntity],
in context: NSManagedObjectContext) throws {
try entitiesAtIndices.forEach { (entity, _, indexInFavoritesArray) in
if let bookmark = entity as? Bookmark,
bookmark.isFavorite,
indexInFavoritesArray == nil {
try addEntityToFavorites(
entity,
at: nil,
entitiesByUUID: entitiesByUUID,
displayedFavoritesFolder: displayedFavoritesFolder,
otherFavoritesFolders: favoritesFoldersWithoutDisplayed)
}
}
}

private func fetchDisplayedFavoritesFolder(in context: NSManagedObjectContext) throws -> BookmarkEntity {
let displayedFavoritesFolderUUID = favoritesDisplayMode.displayedFolder.rawValue
guard let displayedFavoritesFolder = BookmarkUtils.fetchFavoritesFolder(withUUID: displayedFavoritesFolderUUID, in: context) else {
Expand Down Expand Up @@ -1034,7 +1092,7 @@ final class LocalBookmarkStore: BookmarkStore {
}

private func addEntityToFavorites(_ entity: BaseBookmarkEntity,
at index: Int,
at index: Int?,
entitiesByUUID: [String: BookmarkEntity],
displayedFavoritesFolder: BookmarkEntity,
otherFavoritesFolders: [BookmarkEntity]) throws {
Expand Down
24 changes: 12 additions & 12 deletions UnitTests/Bookmarks/Services/LocalBookmarkStoreTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ final class LocalBookmarkStoreTests: XCTestCase {

let bookmark = Bookmark(id: UUID().uuidString, url: URL.duckDuckGo.absoluteString, title: "DuckDuckGo", isFavorite: true, parentFolderUUID: "bookmarks_root")

bookmarkStore.save(bookmark: bookmark, index: nil, indexInFavoritesArray: 0) { error in
bookmarkStore.save(bookmark: bookmark, index: nil) { error in
XCTAssertNil(error)

savingExpectation.fulfill()
Expand Down Expand Up @@ -953,9 +953,9 @@ final class LocalBookmarkStoreTests: XCTestCase {
// Save the initial bookmarks state:

_ = try await bookmarkStore.save(folder: folder)
_ = try await bookmarkStore.save(bookmark: bookmark1, index: nil, indexInFavoritesArray: 0)
_ = try await bookmarkStore.save(bookmark: bookmark2, index: nil, indexInFavoritesArray: 1)
_ = try await bookmarkStore.save(bookmark: bookmark3, index: nil, indexInFavoritesArray: 2)
_ = try await bookmarkStore.save(bookmark: bookmark1, index: nil)
_ = try await bookmarkStore.save(bookmark: bookmark2, index: nil)
_ = try await bookmarkStore.save(bookmark: bookmark3, index: nil)

// Fetch persisted favorites back from the store:

Expand Down Expand Up @@ -1084,9 +1084,9 @@ final class LocalBookmarkStoreTests: XCTestCase {
// Save the initial bookmarks state:

_ = try await bookmarkStore.save(folder: initialParentFolder)
_ = try await bookmarkStore.save(bookmark: bookmark1, index: nil, indexInFavoritesArray: 0)
_ = try await bookmarkStore.save(bookmark: bookmark2, index: nil, indexInFavoritesArray: 1)
_ = try await bookmarkStore.save(bookmark: bookmark3, index: nil, indexInFavoritesArray: 2)
_ = try await bookmarkStore.save(bookmark: bookmark1, index: nil)
_ = try await bookmarkStore.save(bookmark: bookmark2, index: nil)
_ = try await bookmarkStore.save(bookmark: bookmark3, index: nil)

// Fetch persisted favorites back from the store:

Expand Down Expand Up @@ -1127,9 +1127,9 @@ final class LocalBookmarkStoreTests: XCTestCase {
// Save the initial bookmarks state:

_ = try await bookmarkStore.save(folder: folder)
_ = try await bookmarkStore.save(bookmark: bookmark1, index: nil, indexInFavoritesArray: 0)
_ = try await bookmarkStore.save(bookmark: bookmark2, index: nil, indexInFavoritesArray: 1)
_ = try await bookmarkStore.save(bookmark: bookmark3, index: nil, indexInFavoritesArray: 2)
_ = try await bookmarkStore.save(bookmark: bookmark1, index: nil)
_ = try await bookmarkStore.save(bookmark: bookmark2, index: nil)
_ = try await bookmarkStore.save(bookmark: bookmark3, index: nil)

// Fetch persisted favorites back from the store:

Expand Down Expand Up @@ -1213,7 +1213,7 @@ final class LocalBookmarkStoreTests: XCTestCase {
bookmarkStore.applyFavoritesDisplayMode(.displayNative(.desktop))

let bookmark = Bookmark(id: UUID().uuidString, url: "https://example1.com", title: "Example", isFavorite: true)
_ = try await bookmarkStore.save(bookmark: bookmark, index: nil, indexInFavoritesArray: 0)
_ = try await bookmarkStore.save(bookmark: bookmark, index: nil)

context.performAndWait {
let rootFolder = BookmarkUtils.fetchRootFolder(context)!
Expand Down Expand Up @@ -1315,7 +1315,7 @@ final class LocalBookmarkStoreTests: XCTestCase {
bookmarkStore.applyFavoritesDisplayMode(.displayUnified(native: .desktop))

let bookmark = Bookmark(id: UUID().uuidString, url: "https://example1.com", title: "Example", isFavorite: true)
_ = try await bookmarkStore.save(bookmark: bookmark, index: nil, indexInFavoritesArray: 0)
_ = try await bookmarkStore.save(bookmark: bookmark, index: nil)

context.performAndWait {
let rootFolder = BookmarkUtils.fetchRootFolder(context)!
Expand Down

0 comments on commit 3618f63

Please sign in to comment.