Skip to content

Update Transaction and EnvironmentValues #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 1, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
//
// EnvironmentValues.swift
// OpenSwiftUI
//
// Created by Kyle on 2023/9/22.
// Lastest Version: iOS 15.5
// Status: Complete
// ID: 83E729E7BD00420AB79EFD8DF557072A

/// A collection of environment values propagated through a view hierarchy.
///
/// OpenSwiftUI exposes a collection of values to your app's views in an
/// `EnvironmentValues` structure. To read a value from the structure,
/// declare a property using the ``Environment`` property wrapper and
/// specify the value's key path. For example, you can read the current locale:
///
/// @Environment(\.locale) var locale: Locale
///
/// Use the property you declare to dynamically control a view's layout.
/// OpenSwiftUI automatically sets or updates many environment values, like
/// ``EnvironmentValues/pixelLength``, ``EnvironmentValues/scenePhase``, or
/// ``EnvironmentValues/locale``, based on device characteristics, system state,
/// or user settings. For others, like ``EnvironmentValues/lineLimit``, OpenSwiftUI
/// provides a reasonable default value.
///
/// You can set or override some values using the ``View/environment(_:_:)``
/// view modifier:
///
/// MyView()
/// .environment(\.lineLimit, 2)
///
/// The value that you set affects the environment for the view that you modify
/// --- including its descendants in the view hierarchy --- but only up to the
/// point where you apply a different environment modifier.
///
/// OpenSwiftUI provides dedicated view modifiers for setting some values, which
/// typically makes your code easier to read. For example, rather than setting
/// the ``EnvironmentValues/lineLimit`` value directly, as in the previous
/// example, you should instead use the ``View/lineLimit(_:)-513mb`` modifier:
///
/// MyView()
/// .lineLimit(2)
///
/// In some cases, using a dedicated view modifier provides additional
/// functionality. For example, you must use the
/// ``View/preferredColorScheme(_:)`` modifier rather than setting
/// ``EnvironmentValues/colorScheme`` directly to ensure that the new
/// value propagates up to the presenting container when presenting a view
/// like a popover:
///
/// MyView()
/// .popover(isPresented: $isPopped) {
/// PopoverContent()
/// .preferredColorScheme(.dark)
/// }
///
/// Create custom environment values by defining a type that
/// conforms to the ``EnvironmentKey`` protocol, and then extending the
/// environment values structure with a new property. Use your key to get and
/// set the value, and provide a dedicated modifier for clients to use when
/// setting the value:
///
/// private struct MyEnvironmentKey: EnvironmentKey {
/// static let defaultValue: String = "Default value"
/// }
///
/// extension EnvironmentValues {
/// var myCustomValue: String {
/// get { self[MyEnvironmentKey.self] }
/// set { self[MyEnvironmentKey.self] = newValue }
/// }
/// }
///
/// extension View {
/// func myCustomValue(_ myCustomValue: String) -> some View {
/// environment(\.myCustomValue, myCustomValue)
/// }
/// }
///
/// Clients of your value then access the value in the usual way, reading it
/// with the ``Environment`` property wrapper, and setting it with the
/// `myCustomValue` view modifier.
public struct EnvironmentValues: CustomStringConvertible {
/// Creates an environment values instance.
///
/// You don't typically create an instance of ``EnvironmentValues``
/// directly. Doing so would provide access only to default values that
/// don't update based on system settings or device characteristics.
/// Instead, you rely on an environment values' instance
/// that OpenSwiftUI manages for you when you use the ``Environment``
/// property wrapper and the ``View/environment(_:_:)`` view modifier.
public init() {
_plist = PropertyList()
tracker = nil
}

/// Accesses the environment value associated with a custom key.
///
/// Create custom environment values by defining a key
/// that conforms to the ``EnvironmentKey`` protocol, and then using that
/// key with the subscript operator of the ``EnvironmentValues`` structure
/// to get and set a value for that key:
///
/// private struct MyEnvironmentKey: EnvironmentKey {
/// static let defaultValue: String = "Default value"
/// }
///
/// extension EnvironmentValues {
/// var myCustomValue: String {
/// get { self[MyEnvironmentKey.self] }
/// set { self[MyEnvironmentKey.self] = newValue }
/// }
/// }
///
/// You use custom environment values the same way you use system-provided
/// values, setting a value with the ``View/environment(_:_:)`` view
/// modifier, and reading values with the ``Environment`` property wrapper.
/// You can also provide a dedicated view modifier as a convenience for
/// setting the value:
///
/// extension View {
/// func myCustomValue(_ myCustomValue: String) -> some View {
/// environment(\.myCustomValue, myCustomValue)
/// }
/// }
///
public subscript<K: EnvironmentKey>(key: K.Type) -> K.Value {
get {
if let tracker {
tracker.value(_plist, for: EnvironmentPropertyKey<K>.self)
} else {
_plist[EnvironmentPropertyKey<K>.self]
}
}
set {
_plist[EnvironmentPropertyKey<K>.self] = newValue
if let tracker {
tracker.invalidateValue(
for: EnvironmentPropertyKey<K>.self,
from: _plist,
to: _plist
)
}
}
}

/// A string that represents the contents of the environment values
/// instance.
public var description: String { _plist.description }

private var _plist: PropertyList
private let tracker: PropertyList.Tracker?

init(plist: PropertyList) {
_plist = plist
tracker = nil
}
}

private struct EnvironmentPropertyKey<EnvKey: EnvironmentKey>: PropertyKey {
static var defaultValue: EnvKey.Value { EnvKey.defaultValue }
}

private struct DerivedEnvironmentPropertyKey<EnvKey: DerivedEnvironmentKey>: DerivedPropertyKey {
static func value(in plist: PropertyList) -> some Equatable {
EnvKey.value(in: EnvironmentValues(plist: plist))
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ struct PropertyList: CustomStringConvertible {
return
}
elements.forEach { element, stop in
fatalError("TODO")
let element = element.takeUnretainedValue()
guard element.keyType == Key.self else {
return
}
body((element as! TypedElement<Key>).value, &stop)
}
}

Expand Down
43 changes: 43 additions & 0 deletions Sources/OpenSwiftUI/Views/Transaction/Transaction+Animation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Transaction+Animation.swift
// OpenSwiftUI
//
// Created by Kyle on 2024/1/1.
// Lastest Version: iOS 15.5
// Status: Complete
// ID: 39EC6D46662E6D7A6963F5C611934B0A

private struct AnimationKey: TransactionKey {
static let defaultValue: Animation? = nil
}

private struct DisablesAnimationsKey: TransactionKey {
static var defaultValue: Bool { false }
}

extension Transaction {
/// Creates a transaction and assigns its animation property.
///
/// - Parameter animation: The animation to perform when the current state
/// changes.
public init(animation: Animation?) {
self.plist = PropertyList()
self.animation = animation
}

/// The animation, if any, associated with the current state change.
public var animation: Animation? {
get { plist[Key<AnimationKey>.self] }
set { plist[Key<AnimationKey>.self] = newValue }
}

/// A Boolean value that indicates whether views should disable animations.
///
/// This value is `true` during the initial phase of a two-part transition
/// update, to prevent ``View/animation(_:)`` from inserting new animations
/// into the transaction.
public var disablesAnimations: Bool {
get { plist[Key<DisablesAnimationsKey>.self] }
set { plist[Key<DisablesAnimationsKey>.self] = newValue }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// Transaction+isContinuous.swift
// OpenSwiftUI
//
// Created by Kyle on 2024/1/1.
// Lastest Version: iOS 15.5
// Status: Complete
// ID: 73F9B1285B58E062EB66BE983530A970

private struct ContinuousKey: TransactionKey {
static var defaultValue: Bool { false }
}

extension Transaction {
/// A Boolean value that indicates whether the transaction originated from
/// an action that produces a sequence of values.
///
/// This value is `true` if a continuous action created the transaction, and
/// is `false` otherwise. Continuous actions include things like dragging a
/// slider or pressing and holding a stepper, as opposed to tapping a
/// button.
public var isContinuous: Bool {
get { plist[Key<ContinuousKey>.self] }
set { plist[Key<ContinuousKey>.self] = newValue }
}
}
Loading