Skip to content

Commit

Permalink
💫 Update: Exp - AdaptiveModal
Browse files Browse the repository at this point in the history
Summary: Update experiment/test - `swift-programmatic-modal/AdaptiveModal`.
  • Loading branch information
dominicstop committed May 31, 2023
1 parent 02ca95a commit 7eac231
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 125 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,38 @@ struct AdaptiveModalConfig {
let snapAnimationConfig: AdaptiveModalSnapAnimationConfig;
let interpolationClampingConfig: AdaptiveModalClampingConfig;

let overshootSnapPoint: AdaptiveModalSnapPointPreset;

// let entranceConfig: AdaptiveModalEntranceConfig;
// let snapSwipeVelocityThreshold: CGFloat = 0;

var snapPointLastIndex: Int {
self.snapPoints.count - 1;
};

// MARK: - Init
// ------------

init(
snapPoints: [AdaptiveModalSnapPointConfig],
snapDirection: Direction,
snapAnimationConfig: AdaptiveModalSnapAnimationConfig = .default,
interpolationClampingConfig: AdaptiveModalClampingConfig = .default
interpolationClampingConfig: AdaptiveModalClampingConfig = .default,
overshootSnapPoint: AdaptiveModalSnapPointPreset? = nil
) {
self.snapPoints = snapPoints;
self.snapDirection = snapDirection;

self.snapAnimationConfig = snapAnimationConfig;
self.interpolationClampingConfig = interpolationClampingConfig;

self.overshootSnapPoint = overshootSnapPoint
?? .getDefault(forDirection: snapDirection);
};

// MARK: - Functions
// -----------------

func sortInterpolationSteps<T>(_ array: [T]) -> [T] {
switch self.snapDirection {
case .bottomToTop, .rightToLeft:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,23 @@ struct AdaptiveModalInterpolationPoint {
withTargetRect targetRect: CGRect,
currentSize: CGSize,
snapPointConfig: AdaptiveModalSnapPointConfig,
modalCornerRadius: CGFloat,
modalMaskedCorners: CACornerMask
prevSnapPointConfig: AdaptiveModalSnapPointConfig? = nil
) {
self.computedRect = snapPointConfig.snapPoint.computeRect(
withTargetRect: targetRect,
currentSize: currentSize
);

self.modalCornerRadius = modalCornerRadius;
self.modalMaskedCorners = modalMaskedCorners;
let keyframeCurrent = snapPointConfig.animationKeyframe;
let keyframePrev = prevSnapPointConfig?.animationKeyframe;

self.modalCornerRadius = keyframeCurrent?.modalCornerRadius
?? keyframePrev?.modalCornerRadius
?? Self.DefaultCornerRadius;

self.modalMaskedCorners = keyframePrev?.modalMaskedCorners
?? keyframePrev?.modalMaskedCorners
?? Self.DefaultMaskedCorners;
};

func apply(toModalView modalView: UIView){
Expand All @@ -39,44 +46,55 @@ struct AdaptiveModalInterpolationPoint {
};

extension AdaptiveModalInterpolationPoint {

private static let DefaultCornerRadius: CGFloat = 0;

private static let DefaultMaskedCorners: CACornerMask = [
.layerMaxXMinYCorner,
.layerMinXMinYCorner,
.layerMaxXMaxYCorner,
.layerMinXMaxYCorner,
];

static func compute(
usingModalConfig modalConfig: AdaptiveModalConfig,
withTargetRect targetRect: CGRect,
currentSize: CGSize
) -> [AdaptiveModalInterpolationPoint] {
) -> [Self] {

var items: [AdaptiveModalInterpolationPoint] = [];

let defaultCornerRadius: CGFloat = 0;

let defaultMaskedCorners: CACornerMask = [
.layerMaxXMinYCorner,
.layerMinXMinYCorner,
.layerMaxXMaxYCorner,
.layerMinXMaxYCorner,
];

for snapConfig in modalConfig.snapPoints {
let keyframe = snapConfig.animationKeyframe;
let prevKeyframe = items.last;
for (index, snapConfig) in modalConfig.snapPoints.enumerated() {
let prevSnapConfig = modalConfig.snapPoints[safeIndex: index];

items.append(
AdaptiveModalInterpolationPoint(
withTargetRect : targetRect,
currentSize : currentSize,
withTargetRect: targetRect,
currentSize: currentSize,
snapPointConfig: snapConfig,

modalCornerRadius: keyframe?.modalCornerRadius
?? prevKeyframe?.modalCornerRadius ?? defaultCornerRadius,

modalMaskedCorners: keyframe?.modalMaskedCorners
?? prevKeyframe?.modalMaskedCorners ?? defaultMaskedCorners
prevSnapPointConfig: prevSnapConfig
)
);
};

items.append({
let prevSnapPointConfig = modalConfig.snapPoints.last!;

let snapPointConfig = AdaptiveModalSnapPointConfig(
fromSnapPointPreset: modalConfig.overshootSnapPoint,
fromBaseLayoutConfig: prevSnapPointConfig.snapPoint,
withTargetRect: targetRect,
currentSize: currentSize
);

return AdaptiveModalInterpolationPoint(
withTargetRect: targetRect,
currentSize: currentSize,
snapPointConfig: snapPointConfig,
prevSnapPointConfig: prevSnapPointConfig
);
}());

return items;
};

};
Original file line number Diff line number Diff line change
Expand Up @@ -270,19 +270,12 @@ class AdaptiveModalManager {
modalBounds: modalView.bounds
);

print(
"applyInterpolationToModal"
+ "\n - inputValue: \(inputValue)"
+ "\n - nextModalRect: \(nextModalRect)"
+ "\n - nextModalRadius: \(nextModalRadius)"
);

if let nextModalRect = nextModalRect{
self.modalFrame = nextModalRect;
};

if let nextModalRadius = nextModalRadius {
// modalView.layer.cornerRadius = modalCornerRadius;
modalView.layer.cornerRadius = nextModalRadius;
};
};

Expand Down Expand Up @@ -399,7 +392,11 @@ class AdaptiveModalManager {
};

let closestSnapPoint = deltaSorted.first!;
let closestSnapPointIndex = closestSnapPoint.offset;

let closestSnapPointIndex = min(
closestSnapPoint.offset,
self.modalConfig.snapPointLastIndex
);

return (
snapPointIndex: closestSnapPointIndex,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,23 @@ struct AdaptiveModalSnapPointConfig {
) {
self.snapPoint = snapPoint
self.animationKeyframe = animationKeyframe
}
};

init(
fromSnapPointPreset snapPointPreset: AdaptiveModalSnapPointPreset,
fromBaseLayoutConfig baseLayoutConfig: RNILayout,
withTargetRect targetRect: CGRect,
currentSize: CGSize
){
let snapPointLayoutPreset = snapPointPreset.snapPointPreset;

let snapPointLayout = snapPointLayoutPreset.getLayoutConfig(
fromBaseLayoutConfig: baseLayoutConfig,
withTargetRect: targetRect,
currentSize: currentSize
);

self.snapPoint = snapPointLayout;
self.animationKeyframe = snapPointPreset.animationKeyframe;
};
};
Original file line number Diff line number Diff line change
@@ -1,89 +1,43 @@
//
// AdaptiveModalInitialSnapPoint.swift
// AdaptiveModalSnapPointPreset.swift
// swift-programmatic-modal
//
// Created by Dominic Go on 5/23/23.
// Created by Dominic Go on 5/31/23.
//

import UIKit
import Foundation

enum AdaptiveModalSnapPointPreset {
case offscreenBottom, offscreenTop, offscreenLeft, offscreenRight;
case edgeBottom, edgeTop, edgeLeft, edgeRight;
case center;

case layoutConfig(_ config: RNILayout);
struct AdaptiveModalSnapPointPreset {

let snapPointPreset: RNILayoutPreset;
let animationKeyframe: AdaptiveModalAnimationConfig?;

func computeSnapPoint(
fromSnapPointConfig prevSnapPoint: RNILayout,
withTargetRect targetRect: CGRect,
currentSize: CGSize
) -> RNILayout {
init(
snapPoint: RNILayoutPreset,
animationKeyframe: AdaptiveModalAnimationConfig? = nil
) {
self.snapPointPreset = snapPoint;
self.animationKeyframe = animationKeyframe;
};
};

extension AdaptiveModalSnapPointPreset {
static func getDefaultSnapPoint(
forDirection direction: AdaptiveModalConfig.Direction
) -> RNILayoutPreset {
switch direction {
case .bottomToTop: return .offscreenTop;
case .topToBottom: return .offscreenBottom;
case .leftToRight: return .offscreenLeft;
case .rightToLeft: return .offscreenRight;
};
};

let prevRect = prevSnapPoint.computeRect(
withTargetRect: targetRect,
currentSize: currentSize
static func getDefault(
forDirection direction: AdaptiveModalConfig.Direction
) -> Self {
Self.init(
snapPoint: Self.getDefaultSnapPoint(forDirection: direction)
);

switch self {
case .offscreenBottom:
return .init(
derivedFrom: prevSnapPoint
);

case .offscreenTop:
return .init(
derivedFrom: prevSnapPoint,
verticalAlignment: .top,
marginTop: -prevRect.height
);

case .offscreenLeft:
return .init(
derivedFrom: prevSnapPoint,
horizontalAlignment: .left,
marginLeft: -prevRect.width
);

case .offscreenRight:
return .init(
derivedFrom: prevSnapPoint,
horizontalAlignment: .right,
marginRight: prevRect.width
);

case .edgeBottom:
return .init(
derivedFrom: prevSnapPoint,
verticalAlignment: .bottom
);

case .edgeTop:
return .init(
derivedFrom: prevSnapPoint,
verticalAlignment: .top
);

case .edgeLeft:
return .init(
derivedFrom: prevSnapPoint,
horizontalAlignment: .left
);

case .edgeRight:
return .init(
derivedFrom: prevSnapPoint,
horizontalAlignment: .right
);

case .center:
return .init(
derivedFrom: prevSnapPoint,
verticalAlignment: .center
);

case let .layoutConfig(config):
return config;
};
};
};
Loading

0 comments on commit 7eac231

Please sign in to comment.