mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 15:51:00 +00:00
fe7847fc08
Widgets followed the dashboard's trip only, which is the one under way, so a packing list or to-dos for a trip still being planned could not sit on the home screen. The trip, today, bookings, to-dos, packing and group widgets now take a trip in Edit Widget (an AppIntent with the trips running or ahead, Automatic by default, which keeps following the dashboard); the world map needs none. - The app writes a snapshot per trip running or ahead (at most six, the dashboard's order) and the list to pick from, under their own keys (feature widgetTrips, so an older binary never mistakes one for the dashboard's); bags, chat and polls are kept ten minutes, covers per trip - The widget extension targets iOS 17, which configurable widgets need; the apps are not released, so no installed widget goes away - The choices and their texts in the 28 languages of the gallery
73 lines
2.6 KiB
Swift
73 lines
2.6 KiB
Swift
import AppIntents
|
|
import WidgetKit
|
|
|
|
/// The trip a widget shows, picked in "Edit Widget": the dashboard's trip by
|
|
/// default ("Automatic"), or any trip the app listed in widget.trips.
|
|
struct TripChoice: AppEntity {
|
|
static var typeDisplayRepresentation: TypeDisplayRepresentation = "widget.intent.trip"
|
|
static var defaultQuery = TripChoiceQuery()
|
|
|
|
/// The id of the automatic choice, which follows the dashboard's trip.
|
|
static let automaticID = "auto"
|
|
|
|
var id: String
|
|
var title: String
|
|
var dates: String?
|
|
|
|
var displayRepresentation: DisplayRepresentation {
|
|
if id == TripChoice.automaticID {
|
|
return DisplayRepresentation(title: "widget.intent.auto", subtitle: "widget.intent.autoHint")
|
|
}
|
|
return DisplayRepresentation(title: "\(title)", subtitle: dates.map { "\($0)" })
|
|
}
|
|
|
|
static var automatic: TripChoice { TripChoice(id: automaticID, title: "", dates: nil) }
|
|
}
|
|
|
|
struct TripChoiceQuery: EntityQuery {
|
|
func entities(for identifiers: [TripChoice.ID]) async throws -> [TripChoice] {
|
|
all().filter { identifiers.contains($0.id) }
|
|
}
|
|
|
|
func suggestedEntities() async throws -> [TripChoice] {
|
|
all()
|
|
}
|
|
|
|
func defaultResult() async -> TripChoice? {
|
|
.automatic
|
|
}
|
|
|
|
/// Automatic first, then the trips the app sent, soonest first.
|
|
private func all() -> [TripChoice] {
|
|
[.automatic] + WidgetSnapshot.tripIndex().map {
|
|
TripChoice(id: String($0.id), title: $0.title, dates: RelativeDay.range($0.start, $0.end))
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SelectTripIntent: WidgetConfigurationIntent {
|
|
static var title: LocalizedStringResource = "widget.intent.title"
|
|
static var description = IntentDescription("widget.intent.description")
|
|
|
|
@Parameter(title: "widget.intent.trip")
|
|
var trip: TripChoice?
|
|
}
|
|
|
|
/// Like TrekProvider, for the widgets that show one trip: the snapshot of the
|
|
/// trip picked for the widget, or the dashboard's.
|
|
struct TrekTripProvider: AppIntentTimelineProvider {
|
|
func placeholder(in context: Context) -> TrekEntry {
|
|
TrekEntry(date: Date(), snapshot: .sample(running: false))
|
|
}
|
|
|
|
func snapshot(for configuration: SelectTripIntent, in context: Context) async -> TrekEntry {
|
|
let stored = WidgetSnapshot.load(trip: configuration.trip?.id)
|
|
let snapshot: WidgetSnapshot? = (stored?.trip != nil || !context.isPreview) ? stored : WidgetSnapshot.sample(running: false)
|
|
return TrekEntry(date: Date(), snapshot: snapshot)
|
|
}
|
|
|
|
func timeline(for configuration: SelectTripIntent, in context: Context) async -> Timeline<TrekEntry> {
|
|
TrekProvider.timeline(WidgetSnapshot.load(trip: configuration.trip?.id))
|
|
}
|
|
}
|