Before iOS17, when we implement "Edit widget" feature with dynamic data, we are using the following ways.
- Using an intent definition file
- Using an intent extension
Here's the outcome.
- A searchable view controller
- Multi sectioned data view controller
Here is the implementation
intent definition file + intent extension
class IntentHandler: INExtension, ConfigurationIntentHandling {
func provideStickyNoteWidgetItemOptionsCollection(for intent: ConfigurationIntent, with completion: @escaping (INObjectCollection<StickyNoteWidgetItem>?, Error?) -> Void) {
var stickyNoteWidgetItems = [StickyNoteWidgetItem]()
var archivedStickyNoteWidgetItems = [StickyNoteWidgetItem]()
let allStickyNoteWidgetItems = NSPlainNoteRepository.getStickyNoteWidgetItemsWithoutTrash()
for allStickyNoteWidgetItem in allStickyNoteWidgetItems {
if allStickyNoteWidgetItem.archived == 1 {
archivedStickyNoteWidgetItems.append(allStickyNoteWidgetItem)
} else {
stickyNoteWidgetItems.append(allStickyNoteWidgetItem)
}
}
var sections = [INObjectSection<StickyNoteWidgetItem>]()
if !stickyNoteWidgetItems.isEmpty {
let section = INObjectSection(title: nil, items: stickyNoteWidgetItems)
sections.append(section)
}
if !archivedStickyNoteWidgetItems.isEmpty {
let archivedSection = INObjectSection(title: "archive".localized, items: archivedStickyNoteWidgetItems)
sections.append(archivedSection)
}
let collection = INObjectCollection(sections: sections)
completion(collection, nil)
}
override func handler(for intent: INIntent) -> Any {
// This is the default implementation. If you want different objects to handle different intents,
// you can override this and return the handler you want for that particular intent.
return self
}
}
However, if I were using AppIntent
in iOS17, I can only achieve the following
- Not searchable.
- Not section-able.
Using AppIntent
import Foundation
import AppIntents
@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *)
struct StickyNoteWidgetItemAppEntity: AppEntity {
static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "StickyNoteWidgetItem")
@Property(title: "archived")
var archived: Bool?
struct StickyNoteWidgetItemAppEntityQuery: EntityQuery {
func entities(for identifiers: [StickyNoteWidgetItemAppEntity.ID]) async throws -> [StickyNoteWidgetItemAppEntity] {
// TODO: return StickyNoteWidgetItemAppEntity entities with the specified identifiers here.
return []
}
func suggestedEntities() async throws -> [StickyNoteWidgetItemAppEntity] {
// TODO: return likely StickyNoteWidgetItemAppEntity entities here.
// This method is optional; the default implementation returns an empty array.
return [
StickyNoteWidgetItemAppEntity(id: "id0", displayString: "note 0"),
StickyNoteWidgetItemAppEntity(id: "id1", displayString: "note 1"),
StickyNoteWidgetItemAppEntity(id: "id2", displayString: "note 2")
]
}
}
static var defaultQuery = StickyNoteWidgetItemAppEntityQuery()
var id: String // if your identifier is not a String, conform the entity to EntityIdentifierConvertible.
var displayString: String
var displayRepresentation: DisplayRepresentation {
DisplayRepresentation(title: "\(displayString)")
}
init(id: String, displayString: String) {
self.id = id
self.displayString = displayString
}
}
By using AppIntent
, I would like to achieve what is previously achievable using intent defination file + intent extension
Is that ever possible?
Thanks.