Last active
February 10, 2025 21:48
-
-
Save kylebshr/0f94d216994e33dedf8c2b45a286add2 to your computer and use it in GitHub Desktop.
How to conditionally build widget configuration parameters based on UserDefaults or other conditions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ConditionalDefaultEntity.swift | |
// Mercury | |
// | |
// Created by Kyle Bashour on 2/10/25. | |
// Copyright © 2025 Kyle Bashour. All rights reserved. | |
// | |
import AppIntents | |
/// Provides a way to conditionally build widget configuration parameters based on "external" values. | |
/// | |
/// You can't use if statements or other conditions inside the result builders, but you can query | |
/// whether an entity exists. This is a bit of a hack that conditionally provides a default entity | |
/// based on value returned from a closure, so you can read a boolean value out of something like | |
/// UserDefaults, Keychain, or elsewhere. | |
@available(iOS 17, *) | |
struct ConditionalDefaultEntity: AppEntity { | |
static let typeDisplayRepresentation: TypeDisplayRepresentation = "Has queried value" | |
static let defaultQuery = ConditionalDefaultEntityQuery() | |
let displayRepresentation = DisplayRepresentation(title: "Has queried value") | |
let id: UUID | |
init(id: UUID) { | |
self.id = UUID() | |
} | |
} | |
@available(iOS 17, *) | |
struct ConditionalDefaultEntityQuery: EntityQuery { | |
let valueProvider: @Sendable () -> Bool | |
init() { | |
valueProvider = { false } | |
} | |
init(valueProvider: @escaping @Sendable () -> Bool) { | |
self.valueProvider = valueProvider | |
} | |
func entities(for identifiers: [ConditionalDefaultEntity.ID]) async throws -> [ConditionalDefaultEntity] { | |
identifiers.map { ConditionalDefaultEntity(id: $0) } | |
} | |
func defaultResult() async -> ConditionalDefaultEntity? { | |
valueProvider() ? ConditionalDefaultEntity(id: UUID()) : nil | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ExampleWidgetIntent.swift | |
// MercuryWidgetExtension | |
// | |
// Created by Kyle Bashour on 2/10/25. | |
// Copyright © 2025 Kyle Bashour. All rights reserved. | |
// | |
import AppIntents | |
import WidgetKit | |
@available(iOS 17, *) | |
struct ExampleWidgetIntent: WidgetConfigurationIntent { | |
static var title: LocalizedStringResource = "My cool widget" | |
static var isDiscoverable: Bool = false | |
@Parameter( | |
title: "Is value true", | |
query: ConditionalDefaultEntityQuery { | |
UserDefaults.standard.bool(forKey: "my-cool-value") | |
} | |
) | |
var isValueTrue: ConditionalDefaultEntity? | |
@Parameter(title: "Relevant if value is true") | |
var trueRelevantValue: MyEntity? | |
@Parameter(title: "Relevant if value is false") | |
var falseRelevantValue: MyOtherEntity? | |
static var parameterSummary: some ParameterSummary { | |
When(\.$isValueTrue, .hasAnyValue) { | |
Summary { | |
\.$trueRelevantValue | |
} | |
} otherwise: { | |
Summary { | |
\.$falseRelevantValue | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment