@@ -26,7 +26,7 @@ protocol BookmarksPanelViewModelProtocol: Sendable, CanRemoveQuickActionBookmark
2626 func resetSearch( )
2727 func searchBookmarks( query: String , completion: @escaping @MainActor @Sendable ( ) -> Void )
2828 func moveBookmarkToFolder( bookmark: FxBookmarkNode , withGUID parentFolderGUID: String )
29- func remove( bookmark: FxBookmarkNode )
29+ func remove( bookmark: FxBookmarkNode , afterAsyncRemoval completion : @escaping @ MainActor ( ) -> Void )
3030 func getSiteDetails( for bookmark: FxBookmarkNode , completion: @escaping @MainActor ( Site ? ) -> Void )
3131 func moveRow( at sourceIndexPath: IndexPath , to destinationIndexPath: IndexPath )
3232 func createPinUnpinAction(
@@ -50,6 +50,10 @@ final class BookmarksPanelViewModel: BookmarksPanelViewModelProtocol {
5050 case bookmarks
5151 }
5252
53+ private var isBookmarksSearchEnabled : Bool {
54+ LegacyFeatureFlagsManager . shared. isFeatureEnabled ( . bookmarksSearchFeature, checking: . buildOnly)
55+ }
56+
5357 var isRootNode : Bool {
5458 return bookmarkFolderGUID == BookmarkRoots . MobileFolderGUID
5559 }
@@ -62,6 +66,7 @@ final class BookmarksPanelViewModel: BookmarksPanelViewModelProtocol {
6266 let bookmarkFolderGUID : GUID
6367 var bookmarkFolder : FxBookmarkNode ?
6468 var isShowingSearchResults = false
69+ private var currentSearchQuery : String ?
6570
6671 /// Backing data array of all bookmarks
6772 private var allBookmarkNodes = [ FxBookmarkNode] ( )
@@ -99,19 +104,38 @@ final class BookmarksPanelViewModel: BookmarksPanelViewModelProtocol {
99104 return true
100105 }
101106
107+ /// Reloads all the bookmarks data (and search results data, if the user is currently searching bookmarks).
102108 func reloadData( completion: @escaping @MainActor ( ) -> Void ) {
103109 // Can be called while app backgrounded and the db closed, don't try to reload the data source in this case
104110 if profile. isShutdown {
105111 completion ( )
106112 return
107113 }
108114
115+ // After reloading bookmarks, we should also reload our active search results as well, if applicable
116+ // That is because our bookmarks results are fetched recursively and backed by a separate data array
117+ let completionAfterSetup : @MainActor ( ) -> Void = { [ weak self] in
118+ guard let self else {
119+ completion ( )
120+ return
121+ }
122+
123+ // If search results are present, we need to refresh those, too
124+ if self . isShowingSearchResults, let currentSearchQuery = self . currentSearchQuery {
125+ self . searchBookmarks ( query: currentSearchQuery) {
126+ completion ( )
127+ }
128+ } else {
129+ completion ( )
130+ }
131+ }
132+
109133 if bookmarkFolderGUID == BookmarkRoots . MobileFolderGUID {
110- setupMobileFolderData ( completion: completion )
134+ setupMobileFolderData ( completion: completionAfterSetup )
111135 } else if bookmarkFolderGUID == LocalDesktopFolder . localDesktopFolderGuid {
112- setupLocalDesktopFolderData ( completion: completion )
136+ setupLocalDesktopFolderData ( completion: completionAfterSetup )
113137 } else {
114- setupSubfolderData ( completion: completion )
138+ setupSubfolderData ( completion: completionAfterSetup )
115139 }
116140 }
117141
@@ -197,6 +221,8 @@ final class BookmarksPanelViewModel: BookmarksPanelViewModelProtocol {
197221 return
198222 }
199223
224+ currentSearchQuery = query
225+
200226 bookmarksHandler
201227 . getBookmarksTree ( rootGUID: bookmarkFolderGUID, recursive: true )
202228 . uponQueue ( . main) { [ weak self] result in
@@ -398,25 +424,49 @@ final class BookmarksPanelViewModel: BookmarksPanelViewModelProtocol {
398424
399425 /// Deletes the bookmark. Deletion of the bookmark in places happens asynchronously, but tableView source arrays are
400426 /// updated immediately for UI responsiveness.
401- func remove( bookmark: FxBookmarkNode ) {
427+ /// - Parameters:
428+ /// - bookmark: The bookmark to delete.
429+ /// - completion: The completion handler to call after the bookmark has been asynchronously removed from the backing
430+ /// store.
431+ func remove( bookmark: FxBookmarkNode , afterAsyncRemoval completion: @escaping @MainActor ( ) -> Void ) {
432+ let removalCompletion : @MainActor ( ) -> Void = { [ weak self] in
433+ if let self, self . isBookmarksSearchEnabled, self . isShowingSearchResults {
434+ // Reload the bookmarks tree for the current folder. If a bookmark was deleted via search, there is a chance
435+ // a subfolder becomes empty that was previously non-empty. We need to know whether folders in the current
436+ // folder contain bookmarks or not because we show an alert when deleting folders with non-empty contents.
437+ //
438+ // Note: A race condition exists where the user might try to delete a folder before this refresh happens,
439+ // since we optimistically update the UI but can't synchronously update the bookmarks tree local copy (at
440+ // least not easily).
441+ self . reloadData {
442+ completion ( )
443+ }
444+ }
445+ }
402446 // Remove the bookmark from places (async background work)
403447 profile. places. deleteBookmarkNode ( guid: bookmark. guid) . uponQueue ( . main) { _ in
404448 // FXIOS-13228 It should be safe to assumeIsolated here because of `.main` queue above
405449 MainActor . assumeIsolated {
450+ // Remove this bookmark from quick actions
451+ self . removeBookmarkShortcut ( )
452+
406453 // Remove this bookmark out of recent places
407454 if let recentBookmarkFolderGuid = self . profile. prefs. stringForKey ( PrefsKeys . RecentBookmarkFolder) {
408455 self . profile. places. getBookmark ( guid: recentBookmarkFolderGuid) . uponQueue ( . main) { node in
409456 // FXIOS-13228 It should be safe to assumeIsolated here because of `.main` queue above
410457 MainActor . assumeIsolated {
411- guard let nodeValue = node. successValue, nodeValue == nil else { return }
458+ guard let nodeValue = node. successValue, nodeValue == nil else {
459+ removalCompletion ( )
460+ return
461+ }
412462
413463 self . profile. prefs. removeObjectForKey ( PrefsKeys . RecentBookmarkFolder)
464+ removalCompletion ( )
414465 }
415466 }
467+ } else {
468+ removalCompletion ( )
416469 }
417-
418- // Remove this bookmark from quick actions
419- self . removeBookmarkShortcut ( )
420470 }
421471 }
422472
0 commit comments