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 Jun 19, 2023
1 parent a06f80b commit 2a54de5
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ struct AdaptiveModalConfig {
// let entranceConfig: AdaptiveModalEntranceConfig;
// let snapSwipeVelocityThreshold: CGFloat = 0;

// MARK: - Computed Properties
// ---------------------------

var snapPoints: [AdaptiveModalSnapPointConfig] {
.Element.deriveSnapPoints(
undershootSnapPoint: self.undershootSnapPoint,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,12 +339,14 @@ extension AdaptiveModalInterpolationPoint {

static func compute(
usingModalConfig modalConfig: AdaptiveModalConfig,
snapPoints: [AdaptiveModalSnapPointConfig]? = nil,
layoutValueContext context: RNILayoutValueContext
) -> [Self] {


let snapPoints = snapPoints ?? modalConfig.snapPoints;
var items: [AdaptiveModalInterpolationPoint] = [];

for (index, snapConfig) in modalConfig.snapPoints.enumerated() {
for (index, snapConfig) in snapPoints.enumerated() {
items.append(
AdaptiveModalInterpolationPoint(
usingModalConfig: modalConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,31 @@ class AdaptiveModalManager: NSObject {
return .default;
};

// MARK: - Properties - Config Interpolation Points
// -------------------------------------------------

/// The computed frames of the modal based on the snap points
private(set) var configInterpolationSteps: [AdaptiveModalInterpolationPoint]!;

var currentConfigInterpolationStep: AdaptiveModalInterpolationPoint {
self.interpolationSteps[self.currentInterpolationIndex];
};

private var configInterpolationRangeInput: [CGFloat]! {
self.interpolationSteps.map { $0.percent };
};

// MARK: - Properties - Override Interpolation Points
// ---------------------------------------------------

private var isOverridingSnapPoints = false;

private var overrideSnapPoints: [AdaptiveModalSnapPointConfig]?;
private var overrideInterpolationPoints: [AdaptiveModalInterpolationPoint]?;

// MARK: - Properties - Interpolation Points
// ------------------------------------------

/// The computed frames of the modal based on the snap points
private(set) var interpolationSteps: [AdaptiveModalInterpolationPoint]!;

var prevInterpolationIndex = 0;
var nextInterpolationIndex: Int?;

Expand All @@ -89,21 +108,24 @@ class AdaptiveModalManager: NSObject {
}
};

var interpolationSteps: [AdaptiveModalInterpolationPoint]! {
self.configInterpolationSteps
};

var currentInterpolationStep: AdaptiveModalInterpolationPoint {
self.interpolationSteps[self.currentInterpolationIndex];
};

private var interpolationRangeInput: [CGFloat]! {
self.interpolationSteps.map {
$0.percent
};
self.interpolationSteps.map { $0.percent };
};

private var interpolationRangeMaxInput: CGFloat? {
guard let targetView = self.targetView else { return nil };
return targetView.frame[keyPath: self.modalConfig.maxInputRangeKeyForRect];
};


// MARK: - Properties - Animation-Related
// ---------------------------------------

Expand Down Expand Up @@ -1054,15 +1076,84 @@ class AdaptiveModalManager: NSObject {

self.didTriggerSetup = false;
};

private func cleanupSnapPointOverride(){
self.isOverridingSnapPoints = false;
self.overrideSnapPoints = nil;
self.overrideInterpolationPoints = nil;
};

private func cleanup() {
self.clearGestureValues();
self.clearAnimators();
self.cleanupViews();
self.cleanupSnapPointOverride();

self.currentInterpolationIndex = 0;
};

// MARK: - Functions - Helpers/Utilities
// -------------------------------------

private func adjustInterpolationIndex(for nextIndex: Int) -> Int {
if nextIndex == 0 {
return self.shouldSnapToUnderShootSnapPoint
? nextIndex
: 1;
};

let lastIndex = self.interpolationSteps.count - 1;

if nextIndex == lastIndex {
return self.shouldSnapToOvershootSnapPoint
? nextIndex
: lastIndex - 1;
};

return nextIndex;
};

private func applyGestureOffsets(
forGesturePoint gesturePoint: CGPoint
) -> CGPoint {

guard let computedGestureOffset = self.computedGestureOffset
else { return gesturePoint };

switch self.modalConfig.snapDirection {
case .bottomToTop, .rightToLeft: return CGPoint(
x: gesturePoint.x - computedGestureOffset.x,
y: gesturePoint.y - computedGestureOffset.y
);

case .topToBottom, .leftToRight: return CGPoint(
x: gesturePoint.x + computedGestureOffset.x,
y: gesturePoint.y + computedGestureOffset.y
);
};
};

func debug(prefix: String? = ""){
print(
"\n - AdaptiveModalManager.debug - \(prefix ?? "N/A")"
+ "\n - modalView: \(self.modalView?.debugDescription ?? "N/A")"
+ "\n - modalView frame: \(self.modalView?.frame.debugDescription ?? "N/A")"
+ "\n - modalView superview: \(self.modalView?.superview.debugDescription ?? "N/A")"
+ "\n - targetView: \(self.targetView?.debugDescription ?? "N/A")"
+ "\n - targetView frame: \(self.targetView?.frame.debugDescription ?? "N/A")"
+ "\n - targetView superview: \(self.targetView?.superview.debugDescription ?? "N/A")"
+ "\n - modalViewController: \(self.modalViewController?.debugDescription ?? "N/A")"
+ "\n - targetViewController: \(self.targetViewController?.debugDescription ?? "N/A")"
+ "\n - currentInterpolationIndex: \(self.currentInterpolationIndex)"
+ "\n - modalView gestureRecognizers: \(self.modalView?.gestureRecognizers.debugDescription ?? "N/A")"
+ "\n - interpolationSteps.computedRect: \(self.interpolationSteps.map({ $0.computedRect }))"
+ "\n - interpolationSteps.percent: \(self.interpolationSteps.map({ $0.percent }))"
+ "\n - interpolationSteps.backgroundVisualEffectIntensity: \(self.interpolationSteps.map({ $0.backgroundVisualEffectIntensity }))"
+ "\n - interpolationSteps.backgroundVisualEffect: \(self.interpolationSteps.map({ $0.backgroundVisualEffect }))"
+ "\n"
);
};

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

Expand All @@ -1071,7 +1162,7 @@ class AdaptiveModalManager: NSObject {
) {
let context = context ?? self.layoutValueContext;

self.interpolationSteps = .Element.compute(
self.configInterpolationSteps = .Element.compute(
usingModalConfig: self.modalConfig,
layoutValueContext: context
);
Expand Down Expand Up @@ -1099,17 +1190,13 @@ class AdaptiveModalManager: NSObject {
let inputRect = self.modalFrame!;

let inputCoord = coord ??
inputRect.origin[keyPath: self.modalConfig.inputValueKeyForPoint];

let inputCoordAdj = inputCoord < 0
? min(inputCoord, 0)
: inputCoord;
inputRect[keyPath: self.modalConfig.inputValueKeyForRect];

let delta = self.interpolationSteps.map {
let coord =
$0.computedRect[keyPath: self.modalConfig.inputValueKeyForRect];

return abs(inputCoordAdj - coord);
return abs(inputCoord - coord);
};

let deltaSorted = delta.enumerated().sorted {
Expand Down Expand Up @@ -1168,24 +1255,6 @@ class AdaptiveModalManager: NSObject {
);
};

private func adjustInterpolationIndex(for nextIndex: Int) -> Int {
if nextIndex == 0 {
return self.shouldSnapToUnderShootSnapPoint
? nextIndex
: 1;
};

let lastIndex = self.interpolationSteps.count - 1;

if nextIndex == lastIndex {
return self.shouldSnapToOvershootSnapPoint
? nextIndex
: lastIndex - 1;
};

return nextIndex;
};

private func animateModal(
to interpolationPoint: AdaptiveModalInterpolationPoint,
completion: ((UIViewAnimatingPosition) -> Void)? = nil
Expand Down Expand Up @@ -1239,26 +1308,6 @@ class AdaptiveModalManager: NSObject {
self.startDisplayLink();
};

private func applyGestureOffsets(
forGesturePoint gesturePoint: CGPoint
) -> CGPoint {

guard let computedGestureOffset = self.computedGestureOffset
else { return gesturePoint };

switch self.modalConfig.snapDirection {
case .bottomToTop, .rightToLeft: return CGPoint(
x: gesturePoint.x - computedGestureOffset.x,
y: gesturePoint.y - computedGestureOffset.y
);

case .topToBottom, .leftToRight: return CGPoint(
x: gesturePoint.x + computedGestureOffset.x,
y: gesturePoint.y + computedGestureOffset.y
);
};
};

@objc private func onDragPanGesture(_ sender: UIPanGestureRecognizer) {
let gesturePoint = sender.location(in: self.targetView);
self.gesturePoint = gesturePoint;
Expand Down Expand Up @@ -1297,27 +1346,6 @@ class AdaptiveModalManager: NSObject {
};
};

func debug(prefix: String? = ""){
print(
"\n - AdaptiveModalManager.debug - \(prefix ?? "N/A")"
+ "\n - modalView: \(self.modalView?.debugDescription ?? "N/A")"
+ "\n - modalView frame: \(self.modalView?.frame.debugDescription ?? "N/A")"
+ "\n - modalView superview: \(self.modalView?.superview.debugDescription ?? "N/A")"
+ "\n - targetView: \(self.targetView?.debugDescription ?? "N/A")"
+ "\n - targetView frame: \(self.targetView?.frame.debugDescription ?? "N/A")"
+ "\n - targetView superview: \(self.targetView?.superview.debugDescription ?? "N/A")"
+ "\n - modalViewController: \(self.modalViewController?.debugDescription ?? "N/A")"
+ "\n - targetViewController: \(self.targetViewController?.debugDescription ?? "N/A")"
+ "\n - currentInterpolationIndex: \(self.currentInterpolationIndex)"
+ "\n - modalView gestureRecognizers: \(self.modalView?.gestureRecognizers.debugDescription ?? "N/A")"
+ "\n - interpolationSteps.computedRect: \(self.interpolationSteps.map({ $0.computedRect }))"
+ "\n - interpolationSteps.percent: \(self.interpolationSteps.map({ $0.percent }))"
+ "\n - interpolationSteps.backgroundVisualEffectIntensity: \(self.interpolationSteps.map({ $0.backgroundVisualEffectIntensity }))"
+ "\n - interpolationSteps.backgroundVisualEffect: \(self.interpolationSteps.map({ $0.backgroundVisualEffect }))"
+ "\n"
);
};

// MARK: - Functions - DisplayLink-Related
// ---------------------------------------

Expand Down Expand Up @@ -1671,4 +1699,63 @@ class AdaptiveModalManager: NSObject {
completion: completion
);
};

public func snapTo(
snapPointConfig: AdaptiveModalSnapPointConfig,
overshootSnapPointPreset: AdaptiveModalSnapPointPreset? = nil,
fallbackSnapPointKey: AdaptiveModalSnapPointConfig.SnapPointKey? = nil,
animated: Bool = true,
completion: (() -> Void)? = nil
) {
var snapPoints = [
self.currentSnapPointConfig,
snapPointConfig
];

let interpolationPoint = AdaptiveModalInterpolationPoint(
usingModalConfig: self.modalConfig,
snapPointIndex: self.currentInterpolationIndex + 1,
layoutValueContext: self.layoutValueContext,
snapPointConfig: snapPointConfig,
prevInterpolationPoint: self.currentInterpolationStep
);

var interpolationPoints = [
self.currentInterpolationStep,
interpolationPoint
];

if let overshootSnapPointPreset = overshootSnapPointPreset {
let overshootSnapPointConfig = AdaptiveModalSnapPointConfig(
key: .overshootPoint,
fromSnapPointPreset: overshootSnapPointPreset,
fromBaseLayoutConfig: snapPointConfig.snapPoint
);

let overshootInterpolationPoint = AdaptiveModalInterpolationPoint(
usingModalConfig: self.modalConfig,
snapPointIndex: self.currentInterpolationIndex + 2,
layoutValueContext: self.layoutValueContext,
snapPointConfig: overshootSnapPointConfig,
prevInterpolationPoint: interpolationPoints.last!
);

snapPoints.append(overshootSnapPointConfig);
interpolationPoints.append(overshootInterpolationPoint);
};

self.isOverridingSnapPoints = true;
self.overrideSnapPoints = snapPoints;
self.overrideInterpolationPoints = interpolationPoints;

print(
"\n - interpolationPoints.percent:", interpolationPoints.map({$0.percent}),
"\n - interpolationPoints.snapPointIndex:", interpolationPoints.map({$0.snapPointIndex}),
"\n - interpolationPoints.computedRect:", interpolationPoints.map({$0.computedRect})
);

self.animateModal(to: interpolationPoint) { _ in
completion?();
};
};
};
Loading

0 comments on commit 2a54de5

Please sign in to comment.