Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ let openSwiftUITarget = Target.target(
name: "OpenSwiftUI",
dependencies: [
"OpenSwiftUICore",
"COpenSwiftUI",
.target(name: "CoreServices", condition: .when(platforms: [.iOS])),
.product(name: "OpenGraphShims", package: "OpenGraph"),
],
Expand Down Expand Up @@ -205,6 +206,16 @@ let package = Package(
.define("_WASI_EMULATED_SIGNAL", .when(platforms: [.wasi])),
]
),
.target(
name: "COpenSwiftUI",
publicHeadersPath: ".",
cSettings: [
.unsafeFlags(["-I", includePath], .when(platforms: .nonDarwinPlatforms)),
.define("__COREFOUNDATION_FORSWIFTFOUNDATIONONLY__", to: "1", .when(platforms: .nonDarwinPlatforms)),
.define("_WASI_EMULATED_SIGNAL", .when(platforms: [.wasi])),
.headerSearchPath("../OpenSwiftUI_SPI"),
]
),
.binaryTarget(name: "CoreServices", path: "PrivateFrameworks/CoreServices.xcframework"),
openSwiftUICoreTarget,
openSwiftUITarget,
Expand Down
33 changes: 33 additions & 0 deletions Sources/COpenSwiftUI/UIKit/OpenSwiftUI+UIColor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// OpenSwiftUI+UIColor.h
// COpenSwiftUI
//
// Audited for iOS 18.0
// Status: Complete

#ifndef OpenSwiftUI_UIColor_h
#define OpenSwiftUI_UIColor_h

#include "OpenSwiftUIBase.h"

#if OPENSWIFTUI_TARGET_OS_IOS

#import <UIKit/UIKit.h>

OPENSWIFTUI_ASSUME_NONNULL_BEGIN

OPENSWIFTUI_EXPORT
BOOL _UIColorDependsOnTraitCollection(UIColor *color);

@interface UIColor (OpenSwiftUI)

// Workaround Swift initializer limitation
- (instancetype)initWithColor__openSwiftUI__:(UIColor *)color;

@end

OPENSWIFTUI_ASSUME_NONNULL_END

#endif

#endif /* OpenSwiftUI_UIColor_h */
31 changes: 31 additions & 0 deletions Sources/COpenSwiftUI/UIKit/OpenSwiftUI+UIColor.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// OpenSwiftUI+UIColor.m
// COpenSwiftUI
//
// Audited for iOS 18.0
// Status: Complete

#import "OpenSwiftUI+UIColor.h"

#if OPENSWIFTUI_TARGET_OS_IOS

BOOL _UIColorDependsOnTraitCollection(UIColor *color) {
static IMP UIColor_imp = nil;
static dispatch_once_t once;

SEL selector = @selector(resolvedColorWithTraitCollection:);
dispatch_once(&once, ^{
UIColor_imp = [UIColor instanceMethodForSelector:selector];
});
return [color methodForSelector:selector] != UIColor_imp;
}

@implementation UIColor (OpenSwiftUI)

- (instancetype)initWithColor__openSwiftUI__:(UIColor *)color {
self = color;
}

@end

#endif
38 changes: 38 additions & 0 deletions Sources/OpenSwiftUI/EventHandling/Focus/FocusedValueKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,44 @@
// Audited for iOS 15.5
// Status: Complete

import OpenSwiftUICore

/// A protocol for identifier types used when publishing and observing focused
/// values.
///
/// Unlike ``EnvironmentKey``, `FocusedValueKey` has no default value
/// requirement, because the default value for a key is always `nil`.
public protocol FocusedValueKey {
associatedtype Value
}

public struct FocusedValues {
struct StorageOptions {
let rawValue: UInt8
}

var plist: PropertyList
var storageOptions: StorageOptions
var seed: VersionSeed

@usableFromInline
internal init() {
plist = PropertyList()
storageOptions = StorageOptions(rawValue: 0)
seed = .empty

Check warning on line 32 in Sources/OpenSwiftUI/EventHandling/Focus/FocusedValueKey.swift

View check run for this annotation

Codecov / codecov/patch

Sources/OpenSwiftUI/EventHandling/Focus/FocusedValueKey.swift#L29-L32

Added lines #L29 - L32 were not covered by tests
}

/// Reads and writes values associated with a given focused value key.
public subscript<Key>(key: Key.Type) -> Key.Value? where Key: FocusedValueKey {
preconditionFailure("TODO")

Check warning on line 37 in Sources/OpenSwiftUI/EventHandling/Focus/FocusedValueKey.swift

View check run for this annotation

Codecov / codecov/patch

Sources/OpenSwiftUI/EventHandling/Focus/FocusedValueKey.swift#L36-L37

Added lines #L36 - L37 were not covered by tests
}
}

@available(*, unavailable)
extension FocusedValues: Sendable {}

extension FocusedValues: Equatable {
public static func == (lhs: FocusedValues, rhs: FocusedValues) -> Bool {
lhs.seed.matches(rhs.seed)

Check warning on line 46 in Sources/OpenSwiftUI/EventHandling/Focus/FocusedValueKey.swift

View check run for this annotation

Codecov / codecov/patch

Sources/OpenSwiftUI/EventHandling/Focus/FocusedValueKey.swift#L45-L46

Added lines #L45 - L46 were not covered by tests
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
//
// OpenSwiftUI+UIKit.swift
// OpenSwiftUI
//
// Audited for iOS 18.0
// Status: WIP
// ID: 6DC24D5146AF4B80347A1025025F68EE (SwiftUI?)

#if canImport(UIKit)

public import OpenSwiftUICore
public import UIKit
import COpenSwiftUI

// MARK: - Color + UIColor

@available(*, deprecated, message: "Use Color(uiColor:) when converting a UIColor, or create a standard Color directly")
@available(macOS, unavailable)
extension Color {
/// Creates a color from a UIKit color.
///
/// Use this method to create a SwiftUI color from a
/// [UIColor](https://developer.apple.com/documentation/UIKit/UIColor) instance.
/// The new color preserves the adaptability of the original.
/// For example, you can create a rectangle using
/// [link](https://developer.apple.com/documentation/uikit/uicolor/3173132-link)
/// to see how the shade adjusts to match the user's system settings:
///
/// struct Box: View {
/// var body: some View {
/// Color(UIColor.link)
/// .frame(width: 200, height: 100)
/// }
/// }
///
/// The `Box` view defined above automatically changes its
/// appearance when the user turns on Dark Mode. With the light and dark
/// appearances placed side by side, you can see the subtle difference
/// in shades:
///
/// ![A side by side comparison of light and dark appearance screenshots of
/// rectangles rendered with the link color. The light variant appears on
/// the left, and the dark variant on the right.](Color-init-3)
///
/// > Note: Use this initializer only if you need to convert an existing
/// [UIColor](https://developer.apple.com/documentation/UIKit/UIColor) to a
/// OpenSwiftUI color. Otherwise, create an OpenSwiftUI ``Color`` using an
/// initializer like ``init(_:red:green:blue:opacity:)``, or use a system
/// color like ``ShapeStyle/blue``.
///
/// - Parameter color: A
/// [UIColor](https://developer.apple.com/documentation/UIKit/UIColor) instance
/// from which to create a color.
@_disfavoredOverload
public init(_ color: UIColor) {
self.init(uiColor: color)
}
}

@available(macOS, unavailable)
extension Color {
/// Creates a color from a UIKit color.
///
/// Use this method to create a SwiftUI color from a
/// [UIColor](https://developer.apple.com/documentation/UIKit/UIColor) instance.
/// The new color preserves the adaptability of the original.
/// For example, you can create a rectangle using
/// [link](https://developer.apple.com/documentation/uikit/uicolor/3173132-link)
/// to see how the shade adjusts to match the user's system settings:
///
/// struct Box: View {
/// var body: some View {
/// Color(UIColor.link)
/// .frame(width: 200, height: 100)
/// }
/// }
///
/// The `Box` view defined above automatically changes its
/// appearance when the user turns on Dark Mode. With the light and dark
/// appearances placed side by side, you can see the subtle difference
/// in shades:
///
/// ![A side by side comparison of light and dark appearance screenshots of
/// rectangles rendered with the link color. The light variant appears on
/// the left, and the dark variant on the right.](Color-init-3)
///
/// > Note: Use this initializer only if you need to convert an existing
/// [UIColor](https://developer.apple.com/documentation/UIKit/UIColor) to a
/// OpenSwiftUI color. Otherwise, create an OpenSwiftUI ``Color`` using an
/// initializer like ``init(_:red:green:blue:opacity:)``, or use a system
/// color like ``ShapeStyle/blue``.
///
/// - Parameter color: A
/// [UIColor](https://developer.apple.com/documentation/UIKit/UIColor) instance
/// from which to create a color.
public init(uiColor: UIColor) {
self.init(provider: uiColor)
}
}

extension UIColor: ColorProvider {
private static var dynamicColorCache: NSMapTable<ObjcColor, UIColor> = NSMapTable.strongToWeakObjects()

@available(macOS, unavailable)
convenience public init(_ color: Color) {
if let cgColor = color.provider.staticColor {
self.init(cgColor: cgColor)
} else {
let objCColor = ObjcColor(color)
let cache = Self.dynamicColorCache
if let color = cache.object(forKey: objCColor) {
self.init(color__openSwiftUI__: color)
} else {
let value: UIColor
if let kitColor = color.provider.kitColor {
value = kitColor as! UIColor
} else {
value = UIColor { trait in
// TODO: trait
let resolved = Color.Resolved.clear
return resolved.kitColor as! UIColor
}
}
self.init(color__openSwiftUI__: value)
cache.setObject(value, forKey: objCColor)
}
}
}

package func resolve(in environment: EnvironmentValues) -> Color.Resolved {
if _UIColorDependsOnTraitCollection(self) {
let trait = UITraitCollection.current.byOverriding(with: environment, viewPhase: .init(), focusedValues: .init())
let color = resolvedColor(with: trait)
return Color.Resolved(platformColor: color) ?? .clear
} else {
return Color.Resolved(cgColor)
}
}

package var staticColor: CGColor? {
if _UIColorDependsOnTraitCollection(self) {
nil
} else {
cgColor
}
}
}

public extension ColorScheme {
/// Creates a color scheme from its user interface style equivalent.
@available(macOS, unavailable)
@available(watchOS, unavailable)
init?(_ uiUserInterfaceStyle: UIUserInterfaceStyle) {
switch uiUserInterfaceStyle {
case .unspecified: return nil
case .light: self = .light
case .dark: self = .dark
@unknown default: return nil
}
}
}

public extension UIUserInterfaceStyle {
/// Creates a user interface style from its ColorScheme equivalent.
@available(macOS, unavailable)
@available(watchOS, unavailable)
init(_ colorScheme: ColorScheme?) {
switch colorScheme {
case .light: self = .light
case .dark: self = .dark
case nil: self = .unspecified
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// OpenSwiftUI+UITraitCollection.swift
// OpenSwiftUI
//
// Audited for iOS 18.0
// Status: WIP
// ID: 05A2BB2D44F4D559B7E508DC5B95FFB (OpenSwiftUI?)

#if canImport(UIKit)

import OpenSwiftUICore
import UIKit

extension UITraitCollection {
func byOverriding(with: EnvironmentValues, viewPhase: _GraphInputs.Phase, focusedValues: FocusedValues) -> UITraitCollection {
// TODO
self
}
}

#endif
2 changes: 1 addition & 1 deletion Sources/OpenSwiftUICore/Graphic/Color/Color.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public struct Color: Hashable, CustomStringConvertible, Sendable {
///
/// You can get a
/// [CGColor](https://developer.apple.com/documentation/CoreGraphics/CGColor)
/// instance from a constant SwiftUI color. This includes colors you create
/// instance from a constant OpenSwiftUI color. This includes colors you create
/// from a Core Graphics color, from RGB or HSB components, or from constant
/// UIKit and AppKit colors.
///
Expand Down
Loading