diff --git a/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index e227c65b8..22b8ef97e 100644 --- a/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Example/Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "34ec164994f4a7193f54a6829aeb133fff6d99ebe00bfbf67e2ac554c7ea9724", + "originHash" : "c7e770eca4f57decd049cfbd48df537df88fad4eb98858a526f2bf297292e5be", "pins" : [ { "identity" : "equatable", diff --git a/Sources/COpenSwiftUI/Shims/UIKit/UIBacklightLuminance.h b/Sources/COpenSwiftUI/Shims/UIKit/UIBacklightLuminance.h new file mode 100644 index 000000000..799416db1 --- /dev/null +++ b/Sources/COpenSwiftUI/Shims/UIKit/UIBacklightLuminance.h @@ -0,0 +1,20 @@ +// +// UIBacklightLuminance.h +// COpenSwiftUI + +#include "OpenSwiftUIBase.h" + +#if __has_include() && !__has_include() + +#import + +NS_HEADER_AUDIT_BEGIN(nullability, sendability) + +typedef NS_ENUM(NSInteger, _UIBacklightLuminance) { + _UIBacklightLuminanceNormal = 0, + _UIBacklightLuminanceReduced = 1, +}; + +NS_HEADER_AUDIT_END(nullability, sendability) + +#endif diff --git a/Sources/COpenSwiftUI/Shims/UIKit/UITraitCollection+Private.h b/Sources/COpenSwiftUI/Shims/UIKit/UITraitCollection+Private.h new file mode 100644 index 000000000..8d69a9225 --- /dev/null +++ b/Sources/COpenSwiftUI/Shims/UIKit/UITraitCollection+Private.h @@ -0,0 +1,44 @@ +// +// UITraitCollection+Private.h +// COpenSwiftUI +// +// Status: Complete + +#ifndef UITraitCollection_Private_h +#define UITraitCollection_Private_h + +#include "OpenSwiftUIBase.h" + +#if __has_include() + +#import +#include "Shims/UIKit/UIUserInterfaceVibrancy.h" +#include "Shims/UIKit/UIBacklightLuminance.h" +#if OPENSWIFTUI_LINK_BACKLIGHTSERVICES +#import +#endif + +NS_HEADER_AUDIT_BEGIN(nullability, sendability) + +@interface UITraitCollection (OpenSwiftUI_Private) + +@property (nonatomic, readonly) UITraitCollection *_traitCollectionByRemovingEnvironmentWrapper_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(_traitCollectionByRemovingEnvironmentWrapper); +@property (nonatomic, readonly) _UIBacklightLuminance _backlightLuminance_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(_backlightLuminance); +@property (nonatomic, readonly) NSInteger _userInterfaceRenderingMode_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(_userInterfaceRenderingMode); +@property (nonatomic, readonly) CGFloat displayCornerRadius_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(displayCornerRadius); +@property (nonatomic, readonly) _UIUserInterfaceVibrancy _vibrancy_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(_vibrancy); + +#if OPENSWIFTUI_LINK_BACKLIGHTSERVICES +@property (nonatomic, readonly) BLSUpdateFidelity _updateFidelity_openswiftui_safe_wrapper OPENSWIFTUI_SWIFT_NAME(_updateFidelity); +#endif + +@end + +OPENSWIFTUI_EXPORT +const CGFloat _UITraitCollectionDisplayCornerRadiusUnspecified; + +NS_HEADER_AUDIT_END(nullability, sendability) + +#endif /* __has_include() */ + +#endif /* UITraitCollection_Private_h */ diff --git a/Sources/COpenSwiftUI/Shims/UIKit/UITraitCollection+Private.m b/Sources/COpenSwiftUI/Shims/UIKit/UITraitCollection+Private.m new file mode 100644 index 000000000..4bd20d2ac --- /dev/null +++ b/Sources/COpenSwiftUI/Shims/UIKit/UITraitCollection+Private.m @@ -0,0 +1,49 @@ +// +// UITraitCollection+Private.m +// COpenSwiftUI +// +// Status: Complete + +#import "UITraitCollection+Private.h" +#import "Shims/OpenSwiftUIShims.h" + +#if __has_include() +#import + +@implementation UITraitCollection (OpenSwiftUI_Private) + +- (UITraitCollection *)_traitCollectionByRemovingEnvironmentWrapper_openswiftui_safe_wrapper { + OPENSWIFTUI_SAFE_WRAPPER_IMP(UITraitCollection *, @"_traitCollectionByRemovingEnvironmentWrapper", self); + return func(self, selector); +} + +- (_UIBacklightLuminance)_backlightLuminance_openswiftui_safe_wrapper { + OPENSWIFTUI_SAFE_WRAPPER_IMP(_UIBacklightLuminance, @"_backlightLuminance", _UIBacklightLuminanceNormal); + return func(self, selector); +} + +- (NSInteger)_userInterfaceRenderingMode_openswiftui_safe_wrapper { + OPENSWIFTUI_SAFE_WRAPPER_IMP(NSInteger, @"_userInterfaceRenderingMode", 0); + return func(self, selector); +} + +- (CGFloat)displayCornerRadius_openswiftui_safe_wrapper { + OPENSWIFTUI_SAFE_WRAPPER_IMP(CGFloat, @"displayCornerRadius", 0.0); + return func(self, selector); +} + +- (_UIUserInterfaceVibrancy)_vibrancy_openswiftui_safe_wrapper { + OPENSWIFTUI_SAFE_WRAPPER_IMP(_UIUserInterfaceVibrancy, @"_vibrancy", _UIUserInterfaceVibrancyUnspecified); + return func(self, selector); +} + +#if OPENSWIFTUI_LINK_BACKLIGHTSERVICES +- (BLSUpdateFidelity)_updateFidelity_openswiftui_safe_wrapper { + OPENSWIFTUI_SAFE_WRAPPER_IMP(BLSUpdateFidelity, @"_updateFidelity", BLSUpdateFidelityUnspecified); + return func(self, selector); +} +#endif + +@end + +#endif /* __has_include() */ diff --git a/Sources/COpenSwiftUI/Shims/UIKit/UIUserInterfaceVibrancy.h b/Sources/COpenSwiftUI/Shims/UIKit/UIUserInterfaceVibrancy.h new file mode 100644 index 000000000..1927a78c2 --- /dev/null +++ b/Sources/COpenSwiftUI/Shims/UIKit/UIUserInterfaceVibrancy.h @@ -0,0 +1,21 @@ +// +// UIUserInterfaceVibrancy.h +// COpenSwiftUI + +#include "OpenSwiftUIBase.h" + +#if __has_include() && !__has_include() + +#import + +NS_HEADER_AUDIT_BEGIN(nullability, sendability) + +typedef NS_ENUM(NSInteger, _UIUserInterfaceVibrancy) { + _UIUserInterfaceVibrancyUnspecified = -1, + _UIUserInterfaceVibrancyNone = 0, + _UIUserInterfaceVibrancyVibrant = 1, +}; + +NS_HEADER_AUDIT_END(nullability, sendability) + +#endif diff --git a/Sources/OpenSwiftUI/Animation/Timeline/DateSequenceTimeline.swift b/Sources/OpenSwiftUI/Animation/Timeline/DateSequenceTimeline.swift index a11742052..8b8f9ab26 100644 --- a/Sources/OpenSwiftUI/Animation/Timeline/DateSequenceTimeline.swift +++ b/Sources/OpenSwiftUI/Animation/Timeline/DateSequenceTimeline.swift @@ -138,13 +138,21 @@ private struct UpdateFidelityKey: EnvironmentKey { static var defaultValue: BLSUpdateFidelity = .seconds } +extension EnvironmentValues { + @inline(__always) + var updateFidelity: BLSUpdateFidelity { + get { self[UpdateFidelityKey.self] } + set { self[UpdateFidelityKey.self] = newValue } + } +} + extension CachedEnvironment.ID { static let updateFidelity: CachedEnvironment.ID = .init() } extension _GraphInputs { var updateFidelity: Attribute { - mapEnvironment(id: .updateFidelity) { $0[UpdateFidelityKey.self] } + mapEnvironment(id: .updateFidelity) { $0.updateFidelity } } } diff --git a/Sources/OpenSwiftUI/Data/Environment/UIKitEnvironment.swift b/Sources/OpenSwiftUI/Data/Environment/UIKitEnvironment.swift index db19d87ba..34868bab5 100644 --- a/Sources/OpenSwiftUI/Data/Environment/UIKitEnvironment.swift +++ b/Sources/OpenSwiftUI/Data/Environment/UIKitEnvironment.swift @@ -7,7 +7,9 @@ // ID: 005A2BB2D44F4D559B7E508DC5B95FFB (SwiftUI) #if canImport(UIKit) - +import COpenSwiftUI +@_spi(ClarityBoard) +@_spi(Private) package import OpenSwiftUICore package import UIKit @@ -58,8 +60,44 @@ extension UITraitCollection { if displayScale != mutableTraits.displayScale { mutableTraits.displayScale = displayScale } - // TODO - _openSwiftUIUnimplementedWarning() + let sizeCategory = UIContentSizeCategory(dynamicTypeSize: environment.dynamicTypeSize) + if sizeCategory != mutableTraits.preferredContentSizeCategory { + mutableTraits.preferredContentSizeCategory = sizeCategory + } + let userInterfaceStyle = UIUserInterfaceStyle(environment.colorScheme) + if userInterfaceStyle != mutableTraits.userInterfaceStyle { + mutableTraits.userInterfaceStyle = userInterfaceStyle + } + let displayGamut = UIDisplayGamut(rawValue: environment.displayGamut.rawValue)! + if displayGamut != mutableTraits.displayGamut { + mutableTraits.displayGamut = displayGamut + } + if _SemanticFeature_v5.isEnabled, environment.backgroundMaterial != nil { + if mutableTraits._vibrancy == .vibrant || mutableTraits._vibrancy == .none { + mutableTraits._vibrancy = .vibrant + } + } + let accessibilityContrast = UIAccessibilityContrast(environment._colorSchemeContrast) + if accessibilityContrast != mutableTraits.accessibilityContrast { + mutableTraits.accessibilityContrast = accessibilityContrast + } + let horizontalSizeClass = UIUserInterfaceSizeClass(environment.horizontalSizeClass) + if horizontalSizeClass != mutableTraits.horizontalSizeClass { + mutableTraits.horizontalSizeClass = horizontalSizeClass + } + let verticalSizeClass = UIUserInterfaceSizeClass(environment.verticalSizeClass) + if verticalSizeClass != mutableTraits.verticalSizeClass { + mutableTraits.verticalSizeClass = verticalSizeClass + } + if !forImageAssetsOnly { + let userInterfaceLevel = UIUserInterfaceLevel(rawValue: environment.backgroundInfo.layer)! + if userInterfaceLevel != mutableTraits.userInterfaceLevel { + mutableTraits.userInterfaceLevel = userInterfaceLevel + } + } + TypesettingConfigurationKey.write(to: &mutableTraits, value: environment.typesettingConfiguration) + let activeAppearance = UIUserInterfaceActiveAppearance(rawValue: environment.appearsActive ? 1 : 0)! + mutableTraits.activeAppearance = activeAppearance } } @@ -77,9 +115,54 @@ extension UITraitCollection { } func resolvedEnvironment(base environment: EnvironmentValues) -> EnvironmentValues { - // TODO + var result = environment + if !result.bridgedEnvironmentKeys.isEmpty { + result.bridgedEnvironmentKeys = [] + } + result.inheritedTraitCollection = _traitCollectionByRemovingEnvironmentWrapper + if let layoutDirection = LayoutDirection(layoutDirection) { + result.layoutDirection = layoutDirection + } + if let dynamicTypeSize = DynamicTypeSize(uiSizeCategory: preferredContentSizeCategory) { + result.dynamicTypeSize = dynamicTypeSize + } + if let legibilityWeight = LegibilityWeight(legibilityWeight) { + result.legibilityWeight = legibilityWeight + } + if let gamut = DisplayGamut(rawValue: displayGamut.rawValue) { + result.displayGamut = gamut + } + let backlightLuminance = _backlightLuminance + result.isLuminanceReduced = backlightLuminance == .reduced + if backlightLuminance == .reduced { + result.redactionReasons.insert(.privacy) + } + #if OPENSWIFTUI_LINK_BACKLIGHTSERVICES + result.updateFidelity = _updateFidelity + #endif + if let colorSchemeContrast = ColorSchemeContrast(accessibilityContrast) { + result._colorSchemeContrast = colorSchemeContrast + } + result.colorScheme = effectiveColorScheme + result.displayScale = displayScale + result.horizontalSizeClass = UserInterfaceSizeClass(horizontalSizeClass) + result.verticalSizeClass = UserInterfaceSizeClass(verticalSizeClass) + result.backgroundInfo.layer = userInterfaceLevel.rawValue + let displayCornerRadius = displayCornerRadius + if displayCornerRadius != _UITraitCollectionDisplayCornerRadiusUnspecified { + result.displayCornerRadius = displayCornerRadius + } + if _userInterfaceRenderingMode == 2 { + result.backgroundMaterial = .thick + result.vibrantColorStyle = SystemVibrantColorStyle.self + } + if _vibrancy == .vibrant, + _SemanticFeature_v5.isEnabled, + result.backgroundMaterial == nil { + result.backgroundMaterial = .thick + } _openSwiftUIUnimplementedWarning() - return environment + return result } var viewPhase: ViewPhase { @@ -90,6 +173,14 @@ extension UITraitCollection { .init() } } + + var effectiveColorScheme: ColorScheme { + switch userInterfaceStyle { + case .light: .light + case .dark: .dark + default: .light + } + } } @objc(OpenSwiftUIEnvironmentWrapper) @@ -132,8 +223,24 @@ extension UITraitCollection { ) -> UITraitCollection } +extension UIMutableTraits { + var _vibrancy: _UIUserInterfaceVibrancy { + @_silgen_name("$s5UIKit15UIMutableTraitsPAAE9_vibrancySo24_UIUserInterfaceVibrancyVvg") + get + @_silgen_name("$s5UIKit15UIMutableTraitsPAAE9_vibrancySo24_UIUserInterfaceVibrancyVvs") + set + } +} + struct InheritedTraitCollectionKey: EnvironmentKey { static var defaultValue: UITraitCollection? { nil } } +extension EnvironmentValues { + var inheritedTraitCollection: UITraitCollection? { + get { self[InheritedTraitCollectionKey.self] } + set { self[InheritedTraitCollectionKey.self] = newValue } + } +} + #endif diff --git a/Sources/OpenSwiftUI/Integration/Graphic/UIKit/UIKitConversions.swift b/Sources/OpenSwiftUI/Integration/Graphic/UIKit/UIKitConversions.swift index 362963841..60a27aea7 100644 --- a/Sources/OpenSwiftUI/Integration/Graphic/UIKit/UIKitConversions.swift +++ b/Sources/OpenSwiftUI/Integration/Graphic/UIKit/UIKitConversions.swift @@ -252,6 +252,10 @@ extension DynamicTypeSize { /// Create a Dynamic Type size from its `UIContentSizeCategory` equivalent. public init?(_ uiSizeCategory: UIContentSizeCategory) { + self.init(uiSizeCategory: uiSizeCategory) + } + + package init?(uiSizeCategory: UIContentSizeCategory) { switch uiSizeCategory { case .extraSmall: self = .xSmall case .small: self = .small @@ -299,6 +303,10 @@ extension UIContentSizeCategory { @available(macOS, unavailable) @available(watchOS, unavailable) public init(_ dynamicTypeSize: DynamicTypeSize?) { + self.init(dynamicTypeSize: dynamicTypeSize) + } + + package init(dynamicTypeSize: DynamicTypeSize?) { switch dynamicTypeSize { case .xSmall: self = .extraSmall case .small: self = .small diff --git a/Sources/OpenSwiftUI/View/Image/UIImageConversions.swift b/Sources/OpenSwiftUI/View/Image/UIImageConversions.swift index cd75cac10..d2e1ddc6e 100644 --- a/Sources/OpenSwiftUI/View/Image/UIImageConversions.swift +++ b/Sources/OpenSwiftUI/View/Image/UIImageConversions.swift @@ -132,7 +132,7 @@ extension GraphicsImage { case .privateSystem: return UIImage(_systemName: name) @unknown default: - _openSwiftUIUnimplementedFailure() + _openSwiftUIUnreachableCode() } } } diff --git a/Sources/OpenSwiftUI/View/Text/Typesetting/TypesettingConfiguration.swift b/Sources/OpenSwiftUI/View/Text/Typesetting/TypesettingConfiguration.swift new file mode 100644 index 000000000..983307390 --- /dev/null +++ b/Sources/OpenSwiftUI/View/Text/Typesetting/TypesettingConfiguration.swift @@ -0,0 +1,33 @@ +// +// TypesettingConfiguration.swift +// OpenSwiftUI +// +// Audited for 6.5.4 +// Status: Complete + +#if canImport(UIKit) +package import UIKit + +// MARK: - TypesettingConfigurationKey + UITraitBridgedEnvironmentKey + +extension TypesettingConfigurationKey: UITraitBridgedEnvironmentKey { + package static func read(from traitCollection: UITraitCollection) -> TypesettingConfiguration { + if let language = traitCollection.typesettingLanguage { + TypesettingConfiguration(language: .explicit(language)) + } else { + TypesettingConfiguration(language: .automatic) + } + } + + package static func write(to mutableTraits: inout any UIMutableTraits, value: TypesettingConfiguration) { + switch value.language.storage { + case .explicit(let language, _): + mutableTraits.typesettingLanguage = language + case .automatic, .contentAware: + mutableTraits.typesettingLanguage = nil + @unknown default: + _openSwiftUIUnreachableCode() + } + } +} +#endif diff --git a/Sources/OpenSwiftUICore/Graphic/Color/ColorScheme.swift b/Sources/OpenSwiftUICore/Graphic/Color/ColorScheme.swift index 95b470dde..720a2dd7c 100644 --- a/Sources/OpenSwiftUICore/Graphic/Color/ColorScheme.swift +++ b/Sources/OpenSwiftUICore/Graphic/Color/ColorScheme.swift @@ -169,7 +169,8 @@ extension EnvironmentValues { public var colorSchemeContrast: ColorSchemeContrast { self[ColorSchemeContrastKey.self] } - + + /// The contrast associated with the color scheme of this environment. public var _colorSchemeContrast: ColorSchemeContrast { get { self[ColorSchemeContrastKey.self] } set { self[ColorSchemeContrastKey.self] = newValue } diff --git a/Sources/OpenSwiftUICore/Shape/ShapeStyle/Material.swift b/Sources/OpenSwiftUICore/Shape/ShapeStyle/Material.swift index 877e566be..5192db656 100644 --- a/Sources/OpenSwiftUICore/Shape/ShapeStyle/Material.swift +++ b/Sources/OpenSwiftUICore/Shape/ShapeStyle/Material.swift @@ -187,7 +187,9 @@ public struct Material: Sendable { extension Material: ShapeStyle { // FIXME - static let regular = Material(id: .regular) + package static let regular = Material(id: .regular) + + package static let thick = Material(id: .thick) } package struct ForegroundMaterialStyle: ShapeStyle, PrimitiveShapeStyle { diff --git a/Sources/OpenSwiftUICore/View/Text/Typesetting/TypesettingConfiguration.swift b/Sources/OpenSwiftUICore/View/Text/Typesetting/TypesettingConfiguration.swift index 30e818169..3d7cf0fcc 100644 --- a/Sources/OpenSwiftUICore/View/Text/Typesetting/TypesettingConfiguration.swift +++ b/Sources/OpenSwiftUICore/View/Text/Typesetting/TypesettingConfiguration.swift @@ -21,7 +21,9 @@ package struct TypesettingConfiguration: Equatable { } } -package struct TypesettingConfigurationKey: EnvironmentKey { +// MARK: - TypesettingConfigurationKey + +package struct TypesettingConfigurationKey: BridgedEnvironmentKey { package static let defaultValue: TypesettingConfiguration = .init() }