diff --git a/Sources/App/Utilities/Spotlight/HAAppEntityAppIntentEntityQuery+IndexedEntityQuery.swift b/Sources/App/Utilities/Spotlight/HAAppEntityAppIntentEntityQuery+IndexedEntityQuery.swift new file mode 100644 index 0000000000..8853f53f6c --- /dev/null +++ b/Sources/App/Utilities/Spotlight/HAAppEntityAppIntentEntityQuery+IndexedEntityQuery.swift @@ -0,0 +1,20 @@ +import AppIntents +import CoreSpotlight +import Foundation +import Shared + +/// Lets the system ask for a Spotlight refresh instead of waiting for the app's own pass, which only +/// runs when the database changes or the app comes to the foreground. +@available(iOS 27.0, *) +extension HAAppEntityAppIntentEntityQuery: IndexedEntityQuery { + func reindexEntities( + for identifiers: [String], + indexDescription: CSSearchableIndexDescription + ) async throws { + try await SpotlightEntityIndexer.shared.reindex(entityIds: identifiers) + } + + func reindexAllEntities(indexDescription: CSSearchableIndexDescription) async throws { + await SpotlightEntityIndexer.shared.reindexEverything() + } +} diff --git a/Sources/App/Utilities/Spotlight/SpotlightEntityIndexer.swift b/Sources/App/Utilities/Spotlight/SpotlightEntityIndexer.swift index 56a8b51360..998db8ed34 100644 --- a/Sources/App/Utilities/Spotlight/SpotlightEntityIndexer.swift +++ b/Sources/App/Utilities/Spotlight/SpotlightEntityIndexer.swift @@ -104,6 +104,25 @@ final class SpotlightEntityIndexer: ServerObserver { needsReindexOnForeground = true } + /// Reindexes the named entities on request from the system, which asks when it notices the index + /// may be stale rather than waiting for the next database change. + @available(iOS 27.0, *) + func reindex(entityIds: [String]) async throws { + let wanted = Set(entityIds) + guard let snapshot = await Task.detached(priority: .utility) { Self.makeSnapshot() }.value else { + return + } + let entities = snapshot.entities.filter { wanted.contains($0.id) } + guard !entities.isEmpty else { return } + try await index.indexAppEntities(entities) + } + + /// Rebuilds the whole index on request from the system. + @available(iOS 27.0, *) + func reindexEverything() async { + await reindex(reason: "system asked for a reindex") + } + private func reindexAfterForegroundIfNeeded() { guard needsReindexOnForeground else { return } needsReindexOnForeground = false