From 546b292530f49ce810e20fc1ef49753ef09ca0cb Mon Sep 17 00:00:00 2001 From: Dominic Go <18517029+dominicstop@users.noreply.github.com> Date: Fri, 9 Jun 2023 07:16:22 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=AB=20Update:=20Exp=20-=20`AdaptiveMod?= =?UTF-8?q?al`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related: * `TODO:2023-06-04-23-45-31` - Impl: Adaptive Modal - `LayoutComputableValue`. Summary: Update experiment/test - `swift-programmatic-modal/AdaptiveModal`. --- .../AdaptiveModalInterpolationPoint.swift | 21 +- .../AdaptiveModal/AdaptiveModalManager.swift | 25 ++- .../AdaptiveModalSnapPoint.swift | 8 +- .../RNILayout/RNILayout.swift | 204 +++++++++++------- .../RNILayout/RNILayoutPreset.swift | 52 +++-- .../RNILayout/RNILayoutValue.swift | 119 ++++++++++ .../RNILayout/RNILayoutValueContext.swift | 70 ++++++ .../RNILayout/RNILayoutValueMode.swift | 69 ++++++ .../RNILayoutValuePercentTarget.swift | 60 ++++++ .../Test/RNIDraggableTestViewController.swift | 64 +++--- .../Test/RNILayoutTestViewController.swift | 199 ++++++++--------- .../project.pbxproj | 16 ++ 12 files changed, 654 insertions(+), 253 deletions(-) create mode 100644 experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift create mode 100644 experiments/swift-programmatic-modal/RNILayout/RNILayoutValueContext.swift create mode 100644 experiments/swift-programmatic-modal/RNILayout/RNILayoutValueMode.swift create mode 100644 experiments/swift-programmatic-modal/RNILayout/RNILayoutValuePercentTarget.swift diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift index 02fcf176..3cd13d24 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalInterpolationPoint.swift @@ -88,16 +88,14 @@ struct AdaptiveModalInterpolationPoint: Equatable { usingModalConfig modalConfig: AdaptiveModalConfig, snapPointIndex: Int, percent: CGFloat? = nil, - withTargetRect targetRect: CGRect, - currentSize: CGSize, + layoutValueContext context: RNILayoutValueContext, snapPointConfig: AdaptiveModalSnapPointConfig, prevInterpolationPoint keyframePrev: Self? = nil ) { self.snapPointIndex = snapPointIndex; let computedRect = snapPointConfig.snapPoint.computeRect( - withTargetRect: targetRect, - currentSize: currentSize + usingLayoutValueContext: context ); self.computedRect = computedRect; @@ -106,7 +104,7 @@ struct AdaptiveModalInterpolationPoint: Equatable { switch modalConfig.snapPercentStrategy { case .position: let maxRangeInput = - targetRect[keyPath: modalConfig.maxInputRangeKeyForRect]; + context.targetRect[keyPath: modalConfig.maxInputRangeKeyForRect]; let inputValue = computedRect.origin[keyPath: modalConfig.inputValueKeyForPoint]; @@ -280,8 +278,7 @@ extension AdaptiveModalInterpolationPoint { static func compute( usingModalConfig modalConfig: AdaptiveModalConfig, - withTargetRect targetRect: CGRect, - currentSize: CGSize + layoutValueContext context: RNILayoutValueContext ) -> [Self] { var items: [AdaptiveModalInterpolationPoint] = []; @@ -310,8 +307,7 @@ extension AdaptiveModalInterpolationPoint { AdaptiveModalInterpolationPoint( usingModalConfig: modalConfig, snapPointIndex: index, - withTargetRect: targetRect, - currentSize: currentSize, + layoutValueContext: context, snapPointConfig: snapConfig, prevInterpolationPoint: items.last ) @@ -323,17 +319,14 @@ extension AdaptiveModalInterpolationPoint { let overshootSnapPointConfig = AdaptiveModalSnapPointConfig( fromSnapPointPreset: modalConfig.overshootSnapPoint, - fromBaseLayoutConfig: prevSnapPointConfig.snapPoint, - withTargetRect: targetRect, - currentSize: currentSize + fromBaseLayoutConfig: prevSnapPointConfig.snapPoint ); return AdaptiveModalInterpolationPoint( usingModalConfig: modalConfig, snapPointIndex: modalConfig.snapPointLastIndex + 1, percent: 1, - withTargetRect: targetRect, - currentSize: currentSize, + layoutValueContext: context, snapPointConfig: overshootSnapPointConfig, prevInterpolationPoint: items.last ); diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift index f4c88cc0..f32db90f 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift @@ -191,6 +191,18 @@ class AdaptiveModalManager: NSObject { return targetView.frame[keyPath: self.modalConfig.maxInputRangeKeyForRect]; }; + var layoutValueContext: RNILayoutValueContext? { + if let targetVC = self.targetViewController { + return .init(fromTargetViewController: targetVC); + }; + + if let targetView = self.targetView { + return .init(fromTargetView: targetView); + }; + + return nil; + }; + // MARK: - Init // ------------ @@ -1073,20 +1085,17 @@ class AdaptiveModalManager: NSObject { self.setupViewConstraints(); }; - func computeSnapPoints(forTargetView nextTargetView: UIView? = nil) { - if nextTargetView != nil { - self.targetView = nextTargetView; - }; - - guard let targetView = nextTargetView ?? self.targetView + func computeSnapPoints( + usingLayoutValueContext context: RNILayoutValueContext? = nil + ) { + guard let context = context ?? self.layoutValueContext else { return }; let currentSize = self.currentSizeProvider?() ?? .zero; self.interpolationSteps = .Element.compute( usingModalConfig: self.modalConfig, - withTargetRect: targetView.frame, - currentSize: currentSize + layoutValueContext: context ); }; diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalSnapPoint.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalSnapPoint.swift index b2c50431..2d6bf641 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalSnapPoint.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalSnapPoint.swift @@ -21,16 +21,12 @@ struct AdaptiveModalSnapPointConfig { init( fromSnapPointPreset snapPointPreset: AdaptiveModalSnapPointPreset, - fromBaseLayoutConfig baseLayoutConfig: RNILayout, - withTargetRect targetRect: CGRect, - currentSize: CGSize + fromBaseLayoutConfig baseLayoutConfig: RNILayout ) { let snapPointLayoutPreset = snapPointPreset.snapPointPreset; let snapPointLayout = snapPointLayoutPreset.getLayoutConfig( - fromBaseLayoutConfig: baseLayoutConfig, - withTargetRect: targetRect, - currentSize: currentSize + fromBaseLayoutConfig: baseLayoutConfig ); self.snapPoint = snapPointLayout; diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift index 822d1c30..1cc9a4f6 100644 --- a/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayout.swift @@ -21,61 +21,56 @@ public struct RNILayout { // ------------------ public let horizontalAlignment: HorizontalAlignment; - public let verticalAlignment: VerticalAlignment; + public let verticalAlignment : VerticalAlignment; - public let width: RNIComputableValue; - public let height: RNIComputableValue; + public let width : RNILayoutValue; + public let height: RNILayoutValue; - public let marginLeft: CGFloat?; - public let marginRight: CGFloat?; - public let marginTop: CGFloat?; - public let marginBottom: CGFloat?; - - // MARK: - Computed Properties - // --------------------------- - - public var marginHorizontal: CGFloat { - (self.marginLeft ?? 0) + (self.marginRight ?? 0) - }; - - public var marginVertical: CGFloat { - (self.marginTop ?? 0) + (self.marginBottom ?? 0) - }; + public let marginLeft : RNILayoutValueMode?; + public let marginRight : RNILayoutValueMode?; + public let marginTop : RNILayoutValueMode?; + public let marginBottom: RNILayoutValueMode?; // MARK: - Init // ------------ init( horizontalAlignment: HorizontalAlignment, - verticalAlignment: VerticalAlignment, - width: RNIComputableValue, - height: RNIComputableValue, - marginLeft: CGFloat? = nil, - marginRight: CGFloat? = nil, - marginTop: CGFloat? = nil, - marginBottom: CGFloat? = nil + verticalAlignment : VerticalAlignment, + + width : RNILayoutValue, + height: RNILayoutValue, + + marginLeft : RNILayoutValueMode? = nil, + marginRight : RNILayoutValueMode? = nil, + marginTop : RNILayoutValueMode? = nil, + marginBottom: RNILayoutValueMode? = nil ) { self.horizontalAlignment = horizontalAlignment; - self.verticalAlignment = verticalAlignment; - self.width = width; + self.verticalAlignment = verticalAlignment; + + self.width = width; self.height = height; - self.marginLeft = marginLeft; - self.marginRight = marginRight; - self.marginTop = marginTop; + + self.marginLeft = marginLeft; + self.marginRight = marginRight; + self.marginTop = marginTop; self.marginBottom = marginBottom; }; init( derivedFrom prev: Self, horizontalAlignment: HorizontalAlignment? = nil, - verticalAlignment: VerticalAlignment? = nil, - width: RNIComputableValue? = nil, - height: RNIComputableValue? = nil, - marginLeft: CGFloat? = nil, - marginRight: CGFloat? = nil, - marginTop: CGFloat? = nil, - marginBottom: CGFloat? = nil - ){ + verticalAlignment : VerticalAlignment? = nil, + + width : RNILayoutValue? = nil, + height: RNILayoutValue? = nil, + + marginLeft : RNILayoutValueMode? = nil, + marginRight : RNILayoutValueMode? = nil, + marginTop : RNILayoutValueMode? = nil, + marginBottom: RNILayoutValueMode? = nil + ) { self.horizontalAlignment = horizontalAlignment ?? prev.horizontalAlignment; self.verticalAlignment = verticalAlignment ?? prev.verticalAlignment; @@ -95,43 +90,42 @@ public struct RNILayout { /// * Rect with the computed size based on `size` config. /// public func computeRawRectSize( - withTargetRect targetRect: CGRect, - currentSize: CGSize - ) -> CGRect { - let targetSize = targetRect.size; - - let computedSize = CGSize( - width: self.width.compute( - withTargetValue: targetSize.width, - currentValue: currentSize.width - ), - height: self.height.compute( - withTargetValue: targetSize.height, - currentValue: currentSize.height - ) + usingLayoutValueContext context: RNILayoutValueContext + ) -> CGSize { + + let computedWidth = self.width.computeValue( + usingLayoutValueContext: context, + preferredSizeKey: \.width + ); + + let computedHeight = self.height.computeValue( + usingLayoutValueContext: context, + preferredSizeKey: \.height ); - return CGRect(origin: .zero, size: computedSize); + return CGSize( + width : computedWidth ?? 0, + height: computedHeight ?? 0 + ); }; /// Compute Rect - Step 2 - /// * Rect with the computed size based on `size` config. - /// /// * Rect with the origin based on `horizontalAlignment`, and /// `verticalAlignment` config. /// public func computeRawRectOrigin( - forRect rect: CGRect? = nil, + usingLayoutValueContext context: RNILayoutValueContext, withTargetRect targetRect: CGRect, - currentSize: CGSize, + forRect rect: CGRect? = nil, + withSize size: CGSize? = nil, ignoreXAxis: Bool = false, ignoreYAxis: Bool = false ) -> CGRect { - var rect = rect ?? self.computeRawRectSize( - withTargetRect: targetRect, - currentSize: currentSize - ); + let origin = rect?.origin ?? .zero; + let size = rect?.size ?? size ?? .zero; + + var rect = CGRect(origin: origin, size: size); if !ignoreXAxis { // Compute Origin - X @@ -176,33 +170,67 @@ public struct RNILayout { /// * Rect with margins applied to it based on the margin-related properties /// public func computeRect( - withTargetRect targetRect: CGRect, - currentSize: CGSize + usingLayoutValueContext baseContext: RNILayoutValueContext ) -> CGRect { + + let computedSize = self.computeRawRectSize( + usingLayoutValueContext: baseContext + ); + var rect = self.computeRawRectOrigin( - withTargetRect: targetRect, - currentSize: currentSize + usingLayoutValueContext: baseContext, + withTargetRect: baseContext.targetRect + ); + + let context = RNILayoutValueContext( + derivedFrom: baseContext, + currentSize: computedSize ); // Margin - X-Axis switch self.horizontalAlignment { case .left: - guard let marginLeft = self.marginLeft else { break }; + let computedMarginLeft = + self.marginLeft?.compute( + usingLayoutValueContext: context, + preferredSizeKey: \.width + ); + + guard let marginLeft = computedMarginLeft else { break }; rect.origin.x = rect.origin.x + marginLeft; case .right: - guard let marginRight = self.marginRight else { break }; + let computedMarginRight = self.marginRight?.compute( + usingLayoutValueContext: context, + preferredSizeKey: \.width + ); + + guard let marginRight = computedMarginRight else { break }; rect.origin.x = rect.origin.x - marginRight; case .center: if case .stretch = self.width.mode { - rect.size.width = rect.size.width - self.marginHorizontal; + let computedMarginHorizontal: CGFloat = { + let computedMarginLeft = self.marginLeft?.compute( + usingLayoutValueContext: context, + preferredSizeKey: \.width + ); + + let computedMarginRight = self.marginRight?.compute( + usingLayoutValueContext: context, + preferredSizeKey: \.width + ); + + return (computedMarginLeft ?? 0) + (computedMarginRight ?? 0); + }(); + + rect.size.width = rect.size.width - computedMarginHorizontal; // re-compute origin rect = self.computeRawRectOrigin( + usingLayoutValueContext: context, + withTargetRect: context.targetRect, forRect: rect, - withTargetRect: targetRect, - currentSize: currentSize, ignoreYAxis: true ); }; @@ -211,22 +239,46 @@ public struct RNILayout { // Margin - Y-Axis switch self.verticalAlignment { case .top: - guard let marginTop = self.marginTop else { break }; + let computedMarginTop = self.marginTop?.compute( + usingLayoutValueContext: context, + preferredSizeKey: \.height + ); + + guard let marginTop = computedMarginTop else { break }; rect.origin.y = rect.origin.y + marginTop; case .bottom: - guard let marginBottom = self.marginBottom else { break }; + let computedMarginBottom = self.marginBottom?.compute( + usingLayoutValueContext: context, + preferredSizeKey: \.height + ); + + guard let marginBottom = computedMarginBottom else { break }; rect.origin.y = rect.origin.y - marginBottom; case .center: if case .stretch = self.height.mode { - rect.size.height = rect.size.height - self.marginVertical; - + let computedMargiVertical: CGFloat = { + let computedMarginTop = self.marginTop?.compute( + usingLayoutValueContext: context, + preferredSizeKey: \.height + ); + + let computedMarginBottom = self.marginBottom?.compute( + usingLayoutValueContext: context, + preferredSizeKey: \.height + ); + + return (computedMarginTop ?? 0) + (computedMarginBottom ?? 0); + }(); + + rect.size.height = rect.size.height - computedMargiVertical; + // re-compute origin rect = self.computeRawRectOrigin( + usingLayoutValueContext: context, + withTargetRect: context.targetRect, forRect: rect, - withTargetRect: targetRect, - currentSize: currentSize, ignoreXAxis: true ); }; diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift index 3bf14f2a..ce54ffdb 100644 --- a/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutPreset.swift @@ -35,16 +35,9 @@ enum RNILayoutPreset { // --------------- func getLayoutConfig( - fromBaseLayoutConfig baseLayoutConfig: RNILayout, - withTargetRect targetRect: CGRect, - currentSize: CGSize + fromBaseLayoutConfig baseLayoutConfig: RNILayout ) -> RNILayout { - let baseRect = baseLayoutConfig.computeRect( - withTargetRect: targetRect, - currentSize: currentSize - ); - switch self { case .offscreenBottom: return .init( @@ -55,21 +48,30 @@ enum RNILayoutPreset { return .init( derivedFrom: baseLayoutConfig, verticalAlignment: .top, - marginTop: -baseRect.height + marginTop: .percent( + relativeTo: .currentHeight, + percentValue: -1 + ) ); case .offscreenLeft: return .init( derivedFrom: baseLayoutConfig, horizontalAlignment: .left, - marginLeft: -baseRect.width + marginLeft: .percent( + relativeTo: .currentWidth, + percentValue: -1 + ) ); case .offscreenRight: return .init( derivedFrom: baseLayoutConfig, horizontalAlignment: .right, - marginRight: baseRect.width + marginRight: .percent( + relativeTo: .currentWidth, + percentValue: 1 + ) ); case .edgeBottom: @@ -82,28 +84,40 @@ enum RNILayoutPreset { return .init( derivedFrom: baseLayoutConfig, verticalAlignment: .top, - marginTop: baseRect.height / 2 + marginTop: .percent( + relativeTo: .currentHeight, + percentValue: 0.5 + ) ); case .halfOffscreenTop: return .init( derivedFrom: baseLayoutConfig, verticalAlignment: .top, - marginTop: -(baseRect.height / 2) + marginTop: .percent( + relativeTo: .currentHeight, + percentValue: -0.5 + ) ); case .halfOffscreenLeft: return .init( derivedFrom: baseLayoutConfig, horizontalAlignment: .left, - marginLeft: -(baseRect.width / 2) + marginLeft: .percent( + relativeTo: .currentWidth, + percentValue: -0.5 + ) ); case .halfOffscreenRight: return .init( derivedFrom: baseLayoutConfig, horizontalAlignment: .right, - marginRight: baseRect.width / 2 + marginRight: .percent( + relativeTo: .currentWidth, + percentValue: 0.5 + ) ); case .edgeTop: @@ -135,10 +149,10 @@ enum RNILayoutPreset { derivedFrom: baseLayoutConfig, horizontalAlignment: .center, verticalAlignment: .center, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .stretch ) ); @@ -146,7 +160,7 @@ enum RNILayoutPreset { case .fitScreenHorizontally: return .init( derivedFrom: baseLayoutConfig, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ) ); @@ -154,7 +168,7 @@ enum RNILayoutPreset { case .fitScreenVertically: return .init( derivedFrom: baseLayoutConfig, - height: RNIComputableValue( + height: RNILayoutValue( mode: .stretch ) ); diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift new file mode 100644 index 00000000..193063e7 --- /dev/null +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift @@ -0,0 +1,119 @@ +// +// RNILayoutValue.swift +// swift-programmatic-modal +// +// Created by Dominic Go on 6/8/23. +// + +import UIKit + +public struct RNILayoutValue { + + public enum Axis { + case horizontal, vertical; + }; + + // MARK: - Properties + // ------------------ + + public let mode: RNILayoutValueMode; + + public let offsetValue: RNILayoutValueMode?; + public let offsetOperation: RNIComputableOffset.OffsetOperation?; + + public let minValue: RNILayoutValueMode?; + public let maxValue: RNILayoutValueMode?; + + // MARK: - Init + // ------------ + + init( + mode: RNILayoutValueMode, + offsetValue: RNILayoutValueMode? = nil, + offsetOperation: RNIComputableOffset.OffsetOperation? = nil, + minValue: RNILayoutValueMode? = nil, + maxValue: RNILayoutValueMode? = nil + ) { + self.mode = mode; + + self.offsetValue = offsetValue; + self.offsetOperation = offsetOperation; + self.minValue = minValue; + self.maxValue = maxValue; + }; + + // MARK: - Intermediate Functions + // ------------------------------ + + public func applyOffsets( + usingLayoutValueContext context: RNILayoutValueContext, + toValue value: CGFloat + ) -> CGFloat? { + guard let offsetValue = self.offsetValue else { return nil }; + + let computedOffsetValue = offsetValue.compute( + usingLayoutValueContext: context, + preferredSizeKey: nil + ); + + guard let computedOffsetValue = computedOffsetValue else { return nil }; + + let computableOffset = RNIComputableOffset( + offset: computedOffsetValue, + offsetOperation: self.offsetOperation ?? .add + ); + + return computableOffset.compute(withValue: value); + }; + + public func clampValue( + usingLayoutValueContext context: RNILayoutValueContext, + forValue value: CGFloat + ) -> CGFloat? { + let computedMinValue = self.minValue?.compute( + usingLayoutValueContext: context, + preferredSizeKey: nil + ); + + let computedMaxValue = self.minValue?.compute( + usingLayoutValueContext: context, + preferredSizeKey: nil + ); + + return value.clamped(min: computedMinValue, max: computedMaxValue); + }; + + public func computeRawValue( + usingLayoutValueContext context: RNILayoutValueContext, + preferredSizeKey: KeyPath? + ) -> CGFloat? { + return self.mode.compute( + usingLayoutValueContext: context, + preferredSizeKey: preferredSizeKey + ); + }; + + // MARK: - User-Invoked Functions + // ------------------------------ + + public func computeValue( + usingLayoutValueContext context: RNILayoutValueContext, + preferredSizeKey: KeyPath? + ) -> CGFloat? { + + let computedValueRaw = self.computeRawValue( + usingLayoutValueContext: context, + preferredSizeKey: preferredSizeKey + ); + + let computedValueWithOffsets = self.applyOffsets( + usingLayoutValueContext: context, + toValue: computedValueRaw ?? 0 + ); + + return self.clampValue( + usingLayoutValueContext: context, + forValue: computedValueWithOffsets ?? 0 + ); + }; +}; diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutValueContext.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValueContext.swift new file mode 100644 index 00000000..10a8fb0a --- /dev/null +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValueContext.swift @@ -0,0 +1,70 @@ +// +// RNILayoutValueContext.swift +// swift-programmatic-modal +// +// Created by Dominic Go on 6/9/23. +// + +import UIKit + +public struct RNILayoutValueContext { + + let targetRect: CGRect; + + let windowSize: CGSize?; + let currentSize: CGSize?; + + let safeAreaInsets: UIEdgeInsets?; + + var targetSize: CGSize { + self.targetRect.size; + }; + + var screenSize: CGSize { + UIScreen.main.bounds.size; + }; +}; + +extension RNILayoutValueContext { + init( + derivedFrom prev: Self, + targetRect: CGRect? = nil, + windowSize: CGSize? = nil, + currentSize: CGSize? = nil, + safeAreaInsets: UIEdgeInsets? = nil + ) { + + self.targetRect = targetRect ?? prev.targetRect; + + self.windowSize = windowSize ?? prev.windowSize; + self.currentSize = currentSize ?? prev.currentSize; + + self.safeAreaInsets = safeAreaInsets ?? prev.safeAreaInsets; + }; + + init?( + fromTargetViewController targetVC: UIViewController, + currentSize: CGSize? = nil + ) { + guard let targetView = targetVC.view else { return nil }; + + self.targetRect = targetView.frame; + self.windowSize = targetView.window?.bounds.size; + + self.safeAreaInsets = targetView.window?.safeAreaInsets; + + self.currentSize = currentSize; + }; + + init?( + fromTargetView targetView: UIView, + currentSize: CGSize? = nil + ) { + self.targetRect = targetView.frame; + self.windowSize = targetView.window?.bounds.size; + + self.safeAreaInsets = targetView.window?.safeAreaInsets; + + self.currentSize = currentSize; + }; +}; diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutValueMode.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValueMode.swift new file mode 100644 index 00000000..c70ce312 --- /dev/null +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValueMode.swift @@ -0,0 +1,69 @@ +// +// RNILayoutValueMode.swift +// swift-programmatic-modal +// +// Created by Dominic Go on 6/8/23. +// + +import UIKit + +public enum RNILayoutValueMode { + + case stretch; + + case constant(_: CGFloat); + + case percent( + relativeTo: RNILayoutValuePercentTarget = .targetSize, + percentValue: Double + ); + + case safeAreaInsets( + insetKey: KeyPath + ); + + case multipleValues(_ values: [RNILayoutValueMode]); + + // MARK: Functions + // --------------- + + public func compute( + usingLayoutValueContext context: RNILayoutValueContext, + preferredSizeKey: KeyPath? + ) -> CGFloat? { + + switch self { + case .stretch: + guard let preferredSizeKey = preferredSizeKey else { return nil }; + return context.targetSize[keyPath: preferredSizeKey]; + + case let .constant(constantValue): + return constantValue; + + case let .percent(relativeToValue, percentValue): + guard let preferredSizeKey = preferredSizeKey else { return nil }; + + let targetValue = relativeToValue.getValue( + layoutValueContext: context, + preferredSizeKey: preferredSizeKey + ); + + guard let targetValue = targetValue else { return nil }; + return targetValue * percentValue; + + case let .safeAreaInsets(insetKey): + return context.safeAreaInsets?[keyPath: insetKey]; + + case let .multipleValues(computableValues): + return computableValues.reduce(0) { + let computedValue = $1.compute( + usingLayoutValueContext: context, + preferredSizeKey: preferredSizeKey + ); + + guard let computedValue = computedValue else { return 0 }; + return $0 + computedValue; + }; + }; + }; +}; diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutValuePercentTarget.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValuePercentTarget.swift new file mode 100644 index 00000000..c0637399 --- /dev/null +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValuePercentTarget.swift @@ -0,0 +1,60 @@ +// +// RNILayoutValuePercentTarget.swift +// swift-programmatic-modal +// +// Created by Dominic Go on 6/8/23. +// + +import UIKit + +public enum RNILayoutValuePercentTarget { + + case screenSize , screenWidth , screenHeight; + case windowSize , windowWidth , windowHeight; + case targetSize , targetWidth , targetHeight; + case currentSize, currentWidth, currentHeight; + + public func getValue( + layoutValueContext context: RNILayoutValueContext, + preferredSizeKey: KeyPath + ) -> CGFloat? { + + switch self { + case .screenSize: + return context.screenSize[keyPath: preferredSizeKey]; + + case .screenWidth: + return context.screenSize.width; + + case .screenHeight: + return context.screenSize.height; + + case .windowSize: + return context.windowSize?[keyPath: preferredSizeKey]; + + case .windowWidth: + return context.windowSize?.width; + + case .windowHeight: + return context.windowSize?.height; + + case .targetSize: + return context.targetSize[keyPath: preferredSizeKey]; + + case .targetWidth: + return context.targetSize.width; + + case .targetHeight: + return context.targetSize.height; + + case .currentSize: + return context.currentSize?[keyPath: preferredSizeKey]; + + case .currentWidth: + return context.currentSize?.width; + + case .currentHeight: + return context.currentSize?.height; + }; + }; +}; diff --git a/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift b/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift index f289c014..631ca25c 100644 --- a/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/RNIDraggableTestViewController.swift @@ -27,10 +27,10 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.8) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.2) ) ), @@ -48,10 +48,10 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.8) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.4) ) ), @@ -68,10 +68,10 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.8) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.6) ) ), @@ -96,10 +96,10 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.1) ) ) @@ -108,10 +108,10 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.3) ) ) @@ -120,10 +120,10 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.7) ) ) @@ -138,10 +138,10 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.3) ) ), @@ -159,13 +159,13 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .center, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.7), - maxValue: ScreenSize.iPhone8.size.width + maxValue: .constant(ScreenSize.iPhone8.size.width) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.7), - maxValue: ScreenSize.iPhone8.size.height + maxValue: .constant(ScreenSize.iPhone8.size.height) ) ), animationKeyframe: AdaptiveModalAnimationConfig( @@ -196,10 +196,10 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.3) ) ), @@ -225,15 +225,15 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.5) ), - marginLeft: 15, - marginRight: 15, - marginBottom: 15 + marginLeft: .constant(15), + marginRight: .constant(15), + marginBottom: .constant(15) ), animationKeyframe: AdaptiveModalAnimationConfig( //modalOpacity: 0.5, @@ -258,13 +258,13 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .center, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.85), - maxValue: ScreenSize.iPhone8.size.width + maxValue: .constant(ScreenSize.iPhone8.size.width) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.75), - maxValue: ScreenSize.iPhone8.size.height + maxValue: .constant(ScreenSize.iPhone8.size.height) ) ), animationKeyframe: AdaptiveModalAnimationConfig( @@ -288,12 +288,12 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.95), - maxValue: ScreenSize.iPhone8.size.height + maxValue: .constant(ScreenSize.iPhone8.size.height) ) ), animationKeyframe: AdaptiveModalAnimationConfig( diff --git a/experiments/swift-programmatic-modal/Test/RNILayoutTestViewController.swift b/experiments/swift-programmatic-modal/Test/RNILayoutTestViewController.swift index 0e53d286..fe053fed 100644 --- a/experiments/swift-programmatic-modal/Test/RNILayoutTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/RNILayoutTestViewController.swift @@ -26,54 +26,54 @@ class RNILayoutTestViewController : UIViewController { RNILayout( horizontalAlignment: .left, verticalAlignment: .top, - width: RNIComputableValue( - mode: .constant(constantValue: 100) + width: RNILayoutValue( + mode: .constant(100) ), - height: RNIComputableValue( - mode: .constant(constantValue: 100) + height: RNILayoutValue( + mode: .constant(100) ) ), // 1 B RNILayout( horizontalAlignment: .right, verticalAlignment: .top, - width: RNIComputableValue( - mode: .constant(constantValue: 100) + width: RNILayoutValue( + mode: .constant(100) ), - height: RNIComputableValue( - mode: .constant(constantValue: 100) + height: RNILayoutValue( + mode: .constant(100) ) ), // 2 C RNILayout( horizontalAlignment: .right, verticalAlignment: .bottom, - width: RNIComputableValue( - mode: .constant(constantValue: 100) + width: RNILayoutValue( + mode: .constant(100) ), - height: RNIComputableValue( - mode: .constant(constantValue: 100) + height: RNILayoutValue( + mode: .constant(100) ) ), // 3 D RNILayout( horizontalAlignment: .left, verticalAlignment: .bottom, - width: RNIComputableValue( - mode: .constant(constantValue: 100) + width: RNILayoutValue( + mode: .constant(100) ), - height: RNIComputableValue( - mode: .constant(constantValue: 100) + height: RNILayoutValue( + mode: .constant(100) ) ), // 4 E RNILayout( horizontalAlignment: .left, verticalAlignment: .center, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.5) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .stretch ) ), @@ -81,10 +81,10 @@ class RNILayoutTestViewController : UIViewController { RNILayout( horizontalAlignment: .right, verticalAlignment: .center, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.5) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .stretch ) ), @@ -92,10 +92,10 @@ class RNILayoutTestViewController : UIViewController { RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.3) ) ), @@ -103,10 +103,10 @@ class RNILayoutTestViewController : UIViewController { RNILayout( horizontalAlignment: .center, verticalAlignment: .top, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.3) ) ), @@ -114,63 +114,63 @@ class RNILayoutTestViewController : UIViewController { RNILayout( horizontalAlignment: .center, verticalAlignment: .center, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.7), - maxValue: ScreenSize.iPhone8.size.width + maxValue: .constant(ScreenSize.iPhone8.size.width) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.7), - maxValue: ScreenSize.iPhone8.size.height + maxValue: .constant(ScreenSize.iPhone8.size.height) ) ), // 9 J RNILayout( horizontalAlignment: .center, verticalAlignment: .top, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.3) ), - marginLeft: 20, - marginRight: 20 + marginLeft: .constant(20), + marginRight: .constant(20) ), // 10 K RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.3) ), - marginLeft: 20, - marginRight: 20 + marginLeft: .constant(20), + marginRight: .constant(20) ), // 11 L RNILayout( horizontalAlignment: .left, verticalAlignment: .center, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.5) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.6), - maxValue: ScreenSize.iPhone8.size.height + maxValue: .constant(ScreenSize.iPhone8.size.height) ) ), // 12 M RNILayout( horizontalAlignment: .right, verticalAlignment: .center, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.5) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.6), - maxValue: ScreenSize.iPhone8.size.height + maxValue: .constant(ScreenSize.iPhone8.size.height) ) ), // N @@ -178,131 +178,129 @@ class RNILayoutTestViewController : UIViewController { RNILayout( horizontalAlignment: .left, verticalAlignment: .center, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.4) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .stretch, - maxValue: ScreenSize.iPhone8.size.height + maxValue: .constant(ScreenSize.iPhone8.size.height) ), - marginLeft: 20, - marginTop: 20, - marginBottom: 20 + marginLeft: .constant(20), + marginTop: .constant(20), + marginBottom: .constant(20) ), // P RNILayout( horizontalAlignment: .right, verticalAlignment: .center, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.4) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .stretch, - maxValue: ScreenSize.iPhone8.size.height + maxValue: .constant(ScreenSize.iPhone8.size.height) ), - marginRight: 20, - marginTop: 20, - marginBottom: 20 + marginRight: .constant(20), + marginTop: .constant(20), + marginBottom: .constant(20) ), // Q = 15 RNILayout( horizontalAlignment: .center, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.4) ), - marginLeft: 20, - marginRight: 20, - marginBottom: 15 + marginLeft: .constant(20), + marginRight: .constant(20), + marginBottom: .constant(15) ), // R - 16 RNILayout( horizontalAlignment: .center, verticalAlignment: .top, - width: RNIComputableValue( + width: RNILayoutValue( mode: .stretch ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.4) ), - marginLeft: 20, - marginRight: 20, - marginTop: 20 + marginLeft: .constant(20), + marginRight: .constant(20), + marginTop: .constant(20) ), // S RNILayout( horizontalAlignment: .left, verticalAlignment: .top, - width: RNIComputableValue( - mode: .constant(constantValue: 100) + width: RNILayoutValue( + mode: .constant(100) ), - height: RNIComputableValue( - mode: .constant(constantValue: 100) + height: RNILayoutValue( + mode: .constant(100) ), - marginLeft: 20, - marginTop: 20 + marginLeft: .constant(20), + marginTop: .constant(20) ), // T RNILayout( horizontalAlignment: .right, verticalAlignment: .top, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.35), - maxValue: ScreenSize.iPhone8.size.width * 0.6 + maxValue: .constant(ScreenSize.iPhone8.size.width * 0.6) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.25), - maxValue: ScreenSize.iPhone8.size.height * 0.5 + maxValue: .constant(ScreenSize.iPhone8.size.height * 0.5) ), - marginRight: 20, - marginTop: 20 + marginRight: .constant(20), + marginTop: .constant(20) ), // U RNILayout( horizontalAlignment: .left, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.4), - maxValue: ScreenSize.iPhone8.size.width * 0.7 + maxValue: .constant(ScreenSize.iPhone8.size.width * 0.7) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.4), - maxValue: ScreenSize.iPhone8.size.height * 0.7 + maxValue: .constant(ScreenSize.iPhone8.size.height * 0.7) ), - marginLeft: 20, - marginBottom: 20 + marginLeft: .constant(20), + marginBottom: .constant(20) ), // V RNILayout( horizontalAlignment: .right, verticalAlignment: .bottom, - width: RNIComputableValue( + width: RNILayoutValue( mode: .percent(percentValue: 0.4), - maxValue: ScreenSize.iPhone8.size.width * 0.7 + maxValue: .constant(ScreenSize.iPhone8.size.width * 0.7) ), - height: RNIComputableValue( + height: RNILayoutValue( mode: .percent(percentValue: 0.4), - maxValue: ScreenSize.iPhone8.size.height * 0.7 + maxValue: .constant(ScreenSize.iPhone8.size.height * 0.7) ), - marginRight: 20, - marginBottom: 20 + marginRight: .constant(20), + marginBottom: .constant(20) ), - RNILayoutPreset.offscreenTop.getLayoutConfig( + RNILayoutPreset.halfOffscreenTop.getLayoutConfig( fromBaseLayoutConfig: RNILayout( horizontalAlignment: .left, verticalAlignment: .top, - width: RNIComputableValue( - mode: .constant(constantValue: 100) + width: RNILayoutValue( + mode: .constant(100) ), - height: RNIComputableValue( - mode: .constant(constantValue: 100) + height: RNILayoutValue( + mode: .constant(100) ) - ), - withTargetRect: self.view.frame, - currentSize: .zero + ) ), ]; @@ -316,6 +314,10 @@ class RNILayoutTestViewController : UIViewController { return self.layoutConfigs[self.layoutConfigIndex]; }; + var layoutValueContext: RNILayoutValueContext? { + .init(fromTargetViewController: self) + }; + lazy var floatingViewLabel: UILabel = { let label = UILabel(); @@ -371,11 +373,12 @@ class RNILayoutTestViewController : UIViewController { }; func updateFloatingView(){ + guard let layoutValueContext = self.layoutValueContext else { return }; + let layoutConfig = self.layoutConfig; let computedRect = layoutConfig.computeRect( - withTargetRect: self.view.frame, - currentSize: CGSize(width: 300, height: 300) + usingLayoutValueContext: layoutValueContext ); let floatingView = self.floatingView; diff --git a/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj b/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj index b8eb217c..f5713512 100644 --- a/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj +++ b/experiments/swift-programmatic-modal/swift-programmatic-modal.xcodeproj/project.pbxproj @@ -14,6 +14,10 @@ 884A18FA2A3146CA0044AA66 /* AdaptiveModalManager+UIViewControllerTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A18F92A3146CA0044AA66 /* AdaptiveModalManager+UIViewControllerTransitioningDelegate.swift */; }; 884A18FC2A3146FC0044AA66 /* AdaptiveModalManager+UIViewControllerAnimatedTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A18FB2A3146FC0044AA66 /* AdaptiveModalManager+UIViewControllerAnimatedTransitioning.swift */; }; 884A18FE2A31472E0044AA66 /* AdaptiveModalPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884A18FD2A31472E0044AA66 /* AdaptiveModalPresentationController.swift */; }; + 886AFCAB2A31FF40004AC9FB /* RNILayoutValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886AFCAA2A31FF40004AC9FB /* RNILayoutValue.swift */; }; + 886AFCAD2A3209D5004AC9FB /* RNILayoutValueMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886AFCAC2A3209D5004AC9FB /* RNILayoutValueMode.swift */; }; + 886AFCAF2A320DED004AC9FB /* RNILayoutValuePercentTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886AFCAE2A320DED004AC9FB /* RNILayoutValuePercentTarget.swift */; }; + 886AFCB12A325B6F004AC9FB /* RNILayoutValueContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886AFCB02A325B6F004AC9FB /* RNILayoutValueContext.swift */; }; 88B7D0EF29C593F400490628 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B7D0EE29C593F400490628 /* AppDelegate.swift */; }; 88B7D0F129C593F400490628 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88B7D0F029C593F400490628 /* SceneDelegate.swift */; }; 88B7D0F829C593F600490628 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 88B7D0F729C593F600490628 /* Assets.xcassets */; }; @@ -106,6 +110,10 @@ 884A18F92A3146CA0044AA66 /* AdaptiveModalManager+UIViewControllerTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdaptiveModalManager+UIViewControllerTransitioningDelegate.swift"; sourceTree = ""; }; 884A18FB2A3146FC0044AA66 /* AdaptiveModalManager+UIViewControllerAnimatedTransitioning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdaptiveModalManager+UIViewControllerAnimatedTransitioning.swift"; sourceTree = ""; }; 884A18FD2A31472E0044AA66 /* AdaptiveModalPresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveModalPresentationController.swift; sourceTree = ""; }; + 886AFCAA2A31FF40004AC9FB /* RNILayoutValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutValue.swift; sourceTree = ""; }; + 886AFCAC2A3209D5004AC9FB /* RNILayoutValueMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutValueMode.swift; sourceTree = ""; }; + 886AFCAE2A320DED004AC9FB /* RNILayoutValuePercentTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutValuePercentTarget.swift; sourceTree = ""; }; + 886AFCB02A325B6F004AC9FB /* RNILayoutValueContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutValueContext.swift; sourceTree = ""; }; 88B7D0EB29C593F400490628 /* swift-programmatic-modal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "swift-programmatic-modal.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 88B7D0EE29C593F400490628 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 88B7D0F029C593F400490628 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -418,6 +426,10 @@ children = ( 88D017D72A1B302F004664D2 /* RNILayout.swift */, 88E8C01B2A23203E008C2FF8 /* RNILayoutPreset.swift */, + 886AFCAA2A31FF40004AC9FB /* RNILayoutValue.swift */, + 886AFCB02A325B6F004AC9FB /* RNILayoutValueContext.swift */, + 886AFCAC2A3209D5004AC9FB /* RNILayoutValueMode.swift */, + 886AFCAE2A320DED004AC9FB /* RNILayoutValuePercentTarget.swift */, ); path = RNILayout; sourceTree = ""; @@ -626,6 +638,7 @@ 88D018342A1B3030004664D2 /* UIModalPresentationStyle+Init.swift in Sources */, 884A18F82A30516B0044AA66 /* AdaptiveModalPresentationTestViewController.swift in Sources */, 88D0186B2A1B3030004664D2 /* RNIModalPresentationNotifiable.swift in Sources */, + 886AFCAB2A31FF40004AC9FB /* RNILayoutValue.swift in Sources */, 88D018552A1B3030004664D2 /* RNIWeakRef.swift in Sources */, 88D018652A1B3030004664D2 /* RNIViewControllerLifeCycleNotifiable+Default.swift in Sources */, 88D0168D2A1730B1004664D2 /* RNILayoutTestViewController.swift in Sources */, @@ -645,6 +658,7 @@ 88D0183A2A1B3030004664D2 /* CAAnimation+Helpers.swift in Sources */, 88D018582A1B3030004664D2 /* RNIObjectMetadata.swift in Sources */, 88D0187A2A1B3030004664D2 /* RNIComputableOffset.swift in Sources */, + 886AFCAD2A3209D5004AC9FB /* RNILayoutValueMode.swift in Sources */, 88D018382A1B3030004664D2 /* UIModalTransitionStyle+Helpers.swift in Sources */, 88D0184A2A1B3030004664D2 /* RNILayout.swift in Sources */, 88D018472A1B3030004664D2 /* RNIDictionarySynthesizable+Default.swift in Sources */, @@ -665,6 +679,7 @@ 88D0183E2A1B3030004664D2 /* CAAnimation+Block.swift in Sources */, 88D0184C2A1B3030004664D2 /* RNIAnimator.swift in Sources */, 88D018362A1B3030004664D2 /* CGSize+Init.swift in Sources */, + 886AFCB12A325B6F004AC9FB /* RNILayoutValueContext.swift in Sources */, 88B7D0EF29C593F400490628 /* AppDelegate.swift in Sources */, 88D018222A1B3030004664D2 /* UIImage+Init.swift in Sources */, 88D018702A1B3030004664D2 /* RNIModalFlags.swift in Sources */, @@ -681,6 +696,7 @@ 88D0185B2A1B3030004664D2 /* RNIIdentifiable+Default.swift in Sources */, 88C2F4622A2CD81F00DA7450 /* AdaptiveModalEventNotifiable.swift in Sources */, 88D018762A1B3030004664D2 /* RNIComputableSizeMode.swift in Sources */, + 886AFCAF2A320DED004AC9FB /* RNILayoutValuePercentTarget.swift in Sources */, 88D018262A1B3030004664D2 /* UIColor+Helpers.swift in Sources */, 88E8C0182A224A8D008C2FF8 /* AdaptiveModalSnapAnimationConfig.swift in Sources */, 88D018562A1B3030004664D2 /* RNIWeakDictionary.swift in Sources */,