| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 |
- import Foundation
- /// The environment used when constructing scenes and views. Each scene or view
- /// gets to modify the environment before passing it on to its children, which
- /// is the basis of many view modifiers.
- public struct EnvironmentValues {
- /// A font resolution context derived from the current environment.
- ///
- /// Essentially just a subset of the environment.
- @MainActor
- public var fontResolutionContext: Font.Context {
- Font.Context(
- overlay: fontOverlay,
- deviceClass: backend.deviceClass,
- resolveTextStyle: { backend.resolveTextStyle($0) }
- )
- }
- /// The current font resolved to a form suitable for rendering.
- ///
- /// Just a helper method for our own backends. We haven't made this public
- /// because it would be weird to have two pretty equivalent ways of resolving
- /// fonts.
- @MainActor
- @_spi(Backends) public var resolvedFont: Font.Resolved {
- font.resolve(in: fontResolutionContext)
- }
- /// The suggested foreground color for backends to use.
- ///
- /// Backends don't neccessarily have to obey this when
- /// ``EnvironmentValues/foregroundColor`` is `nil`.
- public var suggestedForegroundColor: Color {
- foregroundColor ?? colorScheme.defaultForegroundColor
- }
- /// Called by view graph nodes when they resize due to an internal state
- /// change and end up changing size.
- ///
- /// Each view graph node sets its own handler when passing the environment
- /// on to its children, setting up a bottom-up update chain up which resize
- /// events can propagate.
- @_spi(Backends) public var onResize: @MainActor (_ newSize: ViewSize) -> Void
- /// Backing storage for extensible subscript
- private var values: [ObjectIdentifier: Any]
- /// An internal environment value used to control whether layout caching is
- /// enabled or not.
- ///
- /// This is set to `true` when computing non-final layouts. E.g. when a stack
- /// computes the minimum and maximum sizes of its children, it should enable
- /// layout caching because those updates are guaranteed to be non-final. The
- /// reason that we can't cache on non-final updates is that the last layout
- /// proposal received by each view must be its intended final proposal.
- var allowLayoutCaching: Bool = false
- /// Backing storage for observable subscript
- private var observableObjects: [ObjectIdentifier: any ObservableObject]
- /// Gets an environment value given an environment key's metatype.
- ///
- /// - Parameter key: The type of the key.
- /// - Returns: The environment value associated with `key`, or the key's
- /// default value if it hasn't been set in the environment yet.
- public subscript<T: EnvironmentKey>(_ key: T.Type) -> T.Value {
- get {
- values[ObjectIdentifier(T.self), default: T.defaultValue] as! T.Value
- }
- set {
- values[ObjectIdentifier(T.self)] = newValue
- }
- }
- public subscript<T: ObservableObject>(observable key: T.Type) -> T? {
- get {
- guard let value = observableObjects[ObjectIdentifier(T.self)] as? T? else {
- let message =
- "EnvironmentValues type mismatch: value for key '\(T.self).self' doesn't match expected type '\(T.self)'"
- fatalError(message)
- }
- return value
- }
- set {
- observableObjects[ObjectIdentifier(T.self)] = newValue
- }
- }
- /// Brings the current window forward.
- ///
- /// This is not guaranteed to always bring the window to the top (due
- /// to focus stealing prevention).
- @MainActor
- func bringWindowForward() {
- func activate<Backend: BaseAppBackend>(with backend: Backend) {
- backend.activate(window: window as! Backend.Window)
- }
- activate(with: backend)
- }
- /// The backend in use.
- ///
- /// Mustn't change throughout the app's lifecycle.
- let backend: any BaseAppBackend
- /// Presents an 'Open file' dialog fit for selecting a single file.
- ///
- /// Displays as a modal for the current window, or the entire app if
- /// accessed outside of a scene's view graph (in which case the backend
- /// can decide whether to make it an app modal, a standalone window, or a
- /// modal for a window of its choosing).
- ///
- /// - Important: GtkBackend, Gtk3Backend, and WinUIBackend will only
- /// enable _either_ files or directories for selection, but won't
- /// enable both types in a single dialog.
- @MainActor
- @available(tvOS, unavailable, message: "tvOS does not provide file system access")
- public var chooseFile: PresentSingleFileOpenDialogAction {
- PresentSingleFileOpenDialogAction(
- backend: backend,
- window: MainActorBox(value: window)
- )
- }
- /// Presents a 'Save file' dialog fit for selecting a save destination.
- ///
- /// Displays as a modal for the current window, or the entire app if
- /// accessed outside of a scene's view graph (in which case the backend
- /// can decide whether to make it an app modal, a standalone window, or a
- /// window of its choosing).
- @MainActor
- public var chooseFileSaveDestination: PresentFileSaveDialogAction {
- PresentFileSaveDialogAction(
- backend: backend,
- window: MainActorBox(value: window)
- )
- }
- /// Presents an alert for the current window, or the entire app if accessed
- /// outside of a scene's view graph (in which case the backend can decide
- /// whether to make it an app modal, a standalone window, or a modal for a
- /// window of its choosing).
- @MainActor
- public var presentAlert: PresentAlertAction {
- PresentAlertAction(environment: self)
- }
- /// Opens a URL with the default application.
- ///
- /// May present an application picker if multiple applications are registered
- /// for the given URL protocol.
- ///
- /// `nil` on platforms that don't support opening external URLS (none at the
- /// moment).
- @MainActor
- public var openURL: OpenURLAction {
- OpenURLAction(backend: backend)
- }
- /// Opens a window with the specified ID.
- @MainActor
- public var openWindow: OpenWindowAction {
- OpenWindowAction(environment: self)
- }
- /// Closes the enclosing window.
- @MainActor
- public var dismissWindow: DismissWindowAction {
- DismissWindowAction(
- backend: backend,
- window: MainActorBox(value: window)
- )
- }
- /// Reveals a file in the system's file manager.
- ///
- /// This opens the file's enclosing directory and highlights the file.
- ///
- /// `nil` on platforms that don't support revealing files, e.g. iOS.
- @MainActor
- public var revealFile: RevealFileAction? {
- RevealFileAction(backend: backend)
- }
- /// Whether the backend can have multiple windows open at once. Mobile
- /// backends generally can't.
- @MainActor
- public var supportsMultipleWindows: Bool {
- backend.supportsMultipleWindows
- }
- /// The display styles supported by ``DatePicker``. ``datePickerStyle`` must be one of these.
- public let supportedDatePickerStyles: [DatePickerStyle]
- /// Checks whether a picker style is supported by the current backend.
- @MainActor
- public var isPickerStyleSupported: PickerSupportedAction {
- PickerSupportedAction(backend: backend)
- }
- /// Creates the default environment.
- ///
- /// - Parameters:
- /// - backend: The app's backend.
- @_spi(Backends) public init<Backend: BaseAppBackend>(backend: Backend) {
- self.backend = backend
- onResize = { _ in }
- values = [:]
- observableObjects = [:]
- if let backend = backend as? any BackendFeatures.DatePickers {
- self.supportedDatePickerStyles = backend.supportedDatePickerStyles
- } else {
- self.supportedDatePickerStyles = [.automatic]
- }
- }
- /// Returns a copy of the environment with the specified property set to the
- /// provided new value.
- ///
- /// - Parameters:
- /// - keyPath: A key path to the property to set.
- /// - newValue: The new value of the property.
- /// - Returns: A copy of the environment with the specified property set to
- /// `newValue`.
- public func with<T>(_ keyPath: WritableKeyPath<Self, T>, _ newValue: T) -> Self {
- var environment = self
- environment[keyPath: keyPath] = newValue
- return environment
- }
- }
- extension EnvironmentValues {
- /// The app storage provider to use for `@AppStorage` property wrappers.
- private struct __Key_appStorageProvider: EnvironmentKey {
- static let defaultValue: any AppStorageProvider = DefaultAppStorageProvider()
- }
- public var appStorageProvider: any AppStorageProvider {
- get { self[__Key_appStorageProvider.self] }
- set { self[__Key_appStorageProvider.self] = newValue }
- }
- /// The current stack orientation.
- ///
- /// Inherited by ``ForEach`` and ``Group`` so that they can be used without
- /// affecting layout.
- private struct __Key_layoutOrientation: EnvironmentKey {
- static let defaultValue: Orientation = .vertical
- }
- public var layoutOrientation: Orientation {
- get { self[__Key_layoutOrientation.self] }
- set { self[__Key_layoutOrientation.self] = newValue }
- }
- /// The current stack alignment.
- ///
- /// Inherited by ``ForEach`` and ``Group`` so that they can be used without
- /// affecting layout.
- private struct __Key_layoutAlignment: EnvironmentKey {
- static let defaultValue: StackAlignment = .center
- }
- public var layoutAlignment: StackAlignment {
- get { self[__Key_layoutAlignment.self] }
- set { self[__Key_layoutAlignment.self] = newValue }
- }
- /// The current stack spacing.
- ///
- /// Inherited by ``ForEach`` and ``Group`` so that they can be used without
- /// affecting layout.
- private struct __Key_layoutSpacing: EnvironmentKey {
- static let defaultValue: Int = 10
- }
- public var layoutSpacing: Int {
- get { self[__Key_layoutSpacing.self] }
- set { self[__Key_layoutSpacing.self] = newValue }
- }
- /// The current font.
- private struct __Key_font: EnvironmentKey {
- static let defaultValue: Font = .body
- }
- public var font: Font {
- get { self[__Key_font.self] }
- set { self[__Key_font.self] = newValue }
- }
- /// A font overlay storing font modifications.
- ///
- /// If these conflict with the font's internal overlay, these win out.
- ///
- /// We keep this separate overlay for modifiers because we want modifiers to
- /// be persisted even if the developer sets a custom font further down the
- /// view hierarchy.
- private struct __Key_fontOverlay: EnvironmentKey {
- static let defaultValue: Font.Overlay = Font.Overlay()
- }
- internal var fontOverlay: Font.Overlay {
- get { self[__Key_fontOverlay.self] }
- set { self[__Key_fontOverlay.self] = newValue }
- }
- /// How lines should be aligned relative to each other when line wrapped.
- private struct __Key_multilineTextAlignment: EnvironmentKey {
- static let defaultValue: HorizontalAlignment = .leading
- }
- public var multilineTextAlignment: HorizontalAlignment {
- get { self[__Key_multilineTextAlignment.self] }
- set { self[__Key_multilineTextAlignment.self] = newValue }
- }
- /// Whether to override the case of displayed ``Text`` views.
- ///
- /// `nil` displays the text without any case changes.
- private struct __Key_textCase: EnvironmentKey {
- static let defaultValue: Text.Case? = nil
- }
- public var textCase: Text.Case? {
- get { self[__Key_textCase.self] }
- set { self[__Key_textCase.self] = newValue }
- }
- /// The current color scheme of the current view scope.
- private struct __Key_colorScheme: EnvironmentKey {
- static let defaultValue: ColorScheme = .light
- }
- public var colorScheme: ColorScheme {
- get { self[__Key_colorScheme.self] }
- set { self[__Key_colorScheme.self] = newValue }
- }
- /// The foreground color.
- ///
- /// `nil` means that the default foreground color of the current color scheme
- /// should be used.
- private struct __Key_foregroundColor: EnvironmentKey {
- static let defaultValue: Color? = nil
- }
- public var foregroundColor: Color? {
- get { self[__Key_foregroundColor.self] }
- set { self[__Key_foregroundColor.self] = newValue }
- }
- /// Called when a text field gets submitted (usually due to the user
- /// pressing Enter/Return).
- private struct __Key_onSubmit: EnvironmentKey {
- static let defaultValue: (@MainActor @Sendable () -> Void)? = nil
- }
- public var onSubmit: (@MainActor @Sendable () -> Void)? {
- get { self[__Key_onSubmit.self] }
- set { self[__Key_onSubmit.self] = newValue }
- }
- /// The scale factor of the current window.
- private struct __Key_windowScaleFactor: EnvironmentKey {
- static let defaultValue: Double = 1
- }
- public var windowScaleFactor: Double {
- get { self[__Key_windowScaleFactor.self] }
- set { self[__Key_windowScaleFactor.self] = newValue }
- }
- /// The type of input that text fields represent.
- ///
- /// This affects autocomplete suggestions, and on devices with no physical keyboard, which
- /// on-screen keyboard to use.
- ///
- /// - Warning: Do not use this in place of validation, even if you only plan on supporting
- /// mobile devices, as this does not restrict copy-paste and many mobile devices support
- /// Bluetooth keyboards.
- private struct __Key_textContentType: EnvironmentKey {
- static let defaultValue: TextContentType = .text
- }
- public var textContentType: TextContentType {
- get { self[__Key_textContentType.self] }
- set { self[__Key_textContentType.self] = newValue }
- }
- /// The way that scrollable content interacts with the software keyboard.
- private struct __Key_scrollDismissesKeyboardMode: EnvironmentKey {
- static let defaultValue: ScrollDismissesKeyboardMode = .automatic
- }
- public var scrollDismissesKeyboardMode: ScrollDismissesKeyboardMode {
- get { self[__Key_scrollDismissesKeyboardMode.self] }
- set { self[__Key_scrollDismissesKeyboardMode.self] = newValue }
- }
- /// The style of list to use.
- private struct __Key_listStyle: EnvironmentKey {
- static let defaultValue: ListStyle = .default
- }
- @_spi(Backends) public var listStyle: ListStyle {
- get { self[__Key_listStyle.self] }
- set { self[__Key_listStyle.self] = newValue }
- }
- /// The style of toggle to use.
- private struct __Key_toggleStyle: EnvironmentKey {
- static let defaultValue: ToggleStyle = .button
- }
- public var toggleStyle: ToggleStyle {
- get { self[__Key_toggleStyle.self] }
- set { self[__Key_toggleStyle.self] = newValue }
- }
- /// Whether the text should be selectable.
- ///
- /// Set by ``View/textSelectionEnabled(_:)``.
- private struct __Key_isTextSelectionEnabled: EnvironmentKey {
- static let defaultValue: Bool = false
- }
- public var isTextSelectionEnabled: Bool {
- get { self[__Key_isTextSelectionEnabled.self] }
- set { self[__Key_isTextSelectionEnabled.self] = newValue }
- }
- /// The resizing behaviour of windows.
- ///
- /// Set by ``Window/windowResizability(_:)->Scene``.
- private struct __Key_windowResizability: EnvironmentKey {
- static let defaultValue: WindowResizability = .automatic
- }
- internal var windowResizability: WindowResizability {
- get { self[__Key_windowResizability.self] }
- set { self[__Key_windowResizability.self] = newValue }
- }
- /// The default launch behavior of windows.
- ///
- /// Set by ``Window/defaultLaunchBehavior(_:)->Scene``.
- private struct __Key_defaultLaunchBehavior: EnvironmentKey {
- static let defaultValue: SceneLaunchBehavior = .automatic
- }
- internal var defaultLaunchBehavior: SceneLaunchBehavior {
- get { self[__Key_defaultLaunchBehavior.self] }
- set { self[__Key_defaultLaunchBehavior.self] = newValue }
- }
- /// The default size of windows.
- ///
- /// Defaults to 900x450.
- ///
- /// Set by ``Window/defaultSize(width:height:)->Scene``.
- private struct __Key_defaultWindowSize: EnvironmentKey {
- static let defaultValue: SIMD2<Int> = SIMD2(900, 450)
- }
- internal var defaultWindowSize: SIMD2<Int> {
- get { self[__Key_defaultWindowSize.self] }
- set { self[__Key_defaultWindowSize.self] = newValue }
- }
- /// The menu ordering to use.
- private struct __Key_menuOrder: EnvironmentKey {
- static let defaultValue: MenuOrder = .automatic
- }
- public var menuOrder: MenuOrder {
- get { self[__Key_menuOrder.self] }
- set { self[__Key_menuOrder.self] = newValue }
- }
- /// Backing store for ``EnvironmentValues/openWindowFunctionsByID``.
- /// Used to resolve "non-sendable type" warnings in Swift 5 and errors in Swift 6 language mode.
- private struct __Key_openWindowFunctionsByIDStore: EnvironmentKey {
- static let defaultValue: UncheckedSendable<Box<[String: @MainActor () -> Void]>> = UncheckedSendable(wrappedValue: Box([:]))
- }
- private var openWindowFunctionsByIDStore: UncheckedSendable<Box<[String: @MainActor () -> Void]>> {
- get { self[__Key_openWindowFunctionsByIDStore.self] }
- set { self[__Key_openWindowFunctionsByIDStore.self] = newValue }
- }
- /// A mapping of window IDs to functions that open the corresponding windows.
- internal var openWindowFunctionsByID: Box<[String: @MainActor () -> Void]> {
- get {
- openWindowFunctionsByIDStore.wrappedValue
- }
- set {
- openWindowFunctionsByIDStore.wrappedValue = newValue
- }
- }
- /// The app's lifecycle phase.
- ///
- /// Unlike in SwiftUI, where the app's lifecycle phase can only be accessed
- /// by using `@Environment(\.scenePhase)` directly on the ``App`` struct, this
- /// environment value can be accessed from anywhere within the application.
- private struct __Key_appPhase: EnvironmentKey {
- static let defaultValue: AppPhase = .active
- }
- public package(set) var appPhase: AppPhase {
- get { self[__Key_appPhase.self] }
- set { self[__Key_appPhase.self] = newValue }
- }
- /// The current scene's lifecycle phase.
- ///
- /// - Important: Unlike SwiftUI, this environment value cannot be accessed from
- /// outside a scene. If you need to access the phase of the entire application,
- /// use ``appPhase`` instead.
- public package(set) var scenePhase: ScenePhase {
- get {
- guard let phase = self[__Key_scenePhase.self] else {
- if window != nil {
- // If there's a window but no scenePhase, we assume that the
- // backend is actively trying to _set_ the scene phase; return
- // a dummy value to prevent a crash.
- return .inactive
- }
- fatalError(
- """
- 'scenePhase' accessed from outside a scene (most likely \
- with an @Environment property on the App struct); you \
- probably meant to use 'appPhase' instead
- """
- )
- }
- return phase
- }
- set { self[__Key_scenePhase.self] = newValue }
- }
- private struct __Key_scenePhase: EnvironmentKey {
- static let defaultValue: ScenePhase? = nil
- }
- /// Backing store for ``EnvironmentValues/window``.
- /// Used to resolve "non-sendable type" warnings in Swift 5 and errors in Swift 6 language mode.
- private struct __Key_windowStore: EnvironmentKey {
- static let defaultValue: UncheckedSendable<Any?> = UncheckedSendable(wrappedValue: nil)
- }
- private var windowStore: UncheckedSendable<Any?> {
- get { self[__Key_windowStore.self] }
- set { self[__Key_windowStore.self] = newValue }
- }
- /// The backend's representation of the window that the current view is
- /// in, if any.
- ///
- /// This is a very internal detail that should never get exposed to users.
- @_spi(Backends) public var window: Any? {
- get {
- windowStore.wrappedValue
- }
- set {
- windowStore.wrappedValue = newValue
- }
- }
- /// Backing store for ``EnvironmentValues/sheet``.
- /// Used to resolve "non-sendable type" warnings in Swift 5 and errors in Swift 6 language mode.
- private struct __Key_sheetStore: EnvironmentKey {
- static let defaultValue: UncheckedSendable<Any?> = UncheckedSendable(wrappedValue: nil)
- }
- private var sheetStore: UncheckedSendable<Any?> {
- get { self[__Key_sheetStore.self] }
- set { self[__Key_sheetStore.self] = newValue }
- }
- /// The backend's representation of the sheet that the current view is
- /// in, if any.
- ///
- /// This is a very internal detail that should never get exposed to users.
- @_spi(Backends) public var sheet: Any? {
- get {
- sheetStore.wrappedValue
- }
- set {
- sheetStore.wrappedValue = newValue
- }
- }
- /// The current calendar that views should use when handling dates.
- private struct __Key_calendar: EnvironmentKey {
- static let defaultValue: Calendar = .current
- }
- public var calendar: Calendar {
- get { self[__Key_calendar.self] }
- set { self[__Key_calendar.self] = newValue }
- }
- /// The current time zone that views should use when handling dates.
- private struct __Key_timeZone: EnvironmentKey {
- static let defaultValue: TimeZone = .current
- }
- public var timeZone: TimeZone {
- get { self[__Key_timeZone.self] }
- set { self[__Key_timeZone.self] = newValue }
- }
- /// The current locale.
- private struct __Key_locale: EnvironmentKey {
- static let defaultValue: Locale = .current
- }
- public var locale: Locale {
- get { self[__Key_locale.self] }
- set { self[__Key_locale.self] = newValue }
- }
- /// The display style used by ``Picker``.
- private struct __Key_pickerStyle: EnvironmentKey {
- static let defaultValue: any PickerStyle = .automatic
- }
- public var pickerStyle: any PickerStyle {
- get { self[__Key_pickerStyle.self] }
- set { self[__Key_pickerStyle.self] = newValue }
- }
- /// The display style used by ``DatePicker``.
- private struct __Key_datePickerStyle: EnvironmentKey {
- static let defaultValue: DatePickerStyle = .automatic
- }
- public var datePickerStyle: DatePickerStyle {
- get { self[__Key_datePickerStyle.self] }
- set { self[__Key_datePickerStyle.self] = newValue }
- }
- /// Whether user interaction is enabled.
- ///
- /// Set by ``View/disabled(_:)``.
- private struct __Key_isEnabled: EnvironmentKey {
- static let defaultValue: Bool = true
- }
- public var isEnabled: Bool {
- get { self[__Key_isEnabled.self] }
- set { self[__Key_isEnabled.self] = newValue }
- }
- /// The number of lines text can occupy and whether to reserve that space.
- private struct __Key_lineLimitSettings: EnvironmentKey {
- static let defaultValue: LineLimit? = nil
- }
- public var lineLimitSettings: LineLimit? {
- get { self[__Key_lineLimitSettings.self] }
- set { self[__Key_lineLimitSettings.self] = newValue }
- }
- /// The maximum number of lines that text can occupy in a view.
- public var lineLimit: Int? {
- lineLimitSettings?.limit
- }
- /// Whether the current device has a circular screen. Primarily Android smart watches.
- private struct __Key_isCircularScreen: EnvironmentKey {
- static let defaultValue: Bool = false
- }
- public var isCircularScreen: Bool {
- get { self[__Key_isCircularScreen.self] }
- set { self[__Key_isCircularScreen.self] = newValue }
- }
- /// The display style used by ``Button``.
- private struct __Key_buttonStyle: EnvironmentKey {
- static let defaultValue: ButtonStyle? = nil
- }
- public var buttonStyle: ButtonStyle? {
- get { self[__Key_buttonStyle.self] }
- set { self[__Key_buttonStyle.self] = newValue }
- }
- /// The default button style as declared by the backend.
- @MainActor
- public var defaultButtonStyle: ButtonStyle {
- backend.defaultButtonStyle()
- }
- /// The resolved ``ButtonStyle``. Either ``buttonStyle``, or ``defaultButtonStyle`` if nil.
- @MainActor
- public var resolvedButtonStyle: ButtonStyle {
- buttonStyle ?? defaultButtonStyle
- }
- /// The amount of padding that the current backend applies to the labels of buttons with the current ``ButtonStyle``.
- @MainActor
- public var buttonPadding: SIMD2<Int> {
- backend.buttonPadding(in: self)
- }
- /// The device class of the current device.
- @MainActor
- public var deviceClass: DeviceClass { backend.deviceClass }
- }
- extension EnvironmentValues {
- func applyingTextTransforms(to string: String) -> String {
- var string = string
- switch textCase {
- case .lowercase: string = string.lowercased()
- case .uppercase: string = string.uppercased()
- case nil: break
- }
- return string
- }
- }
- /// A key that can be used to extend the environment with new properties.
- public protocol EnvironmentKey<Value> {
- /// The type of value the key can hold.
- associatedtype Value
- /// The default value for the key.
- static var defaultValue: Value { get }
- }
|