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 4, 2023
1 parent caae311 commit 5d26263
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// AdaptiveModalEventNotifiable.swift
// swift-programmatic-modal
//
// Created by Dominic Go on 6/4/23.
//

import Foundation


protocol AdaptiveModalEventNotifiable: AnyObject {

func notifyOnModalWillSnap(
prevSnapPointIndex: Int?,
nextSnapPointIndex: Int,
snapPointConfig: AdaptiveModalSnapPointConfig,
interpolationPoint: AdaptiveModalInterpolationPoint
);

func notifyOnModalDidSnap(
prevSnapPointIndex: Int?,
currentSnapPointIndex: Int,
snapPointConfig: AdaptiveModalSnapPointConfig,
interpolationPoint: AdaptiveModalInterpolationPoint
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,28 @@

import UIKit


class AdaptiveModalManager {

// MARK: - Properties - Config-Related
// ------------------------------------

var modalConfig: AdaptiveModalConfig;

var currentSnapPointIndex = 0;

var enableSnapping = true;

// MARK: - Properties - Refs/Providers
// ------------------------------------

var currentSizeProvider: () -> CGSize;
// MARK: - Properties - Refs
// --------------------------

weak var eventDelegate: AdaptiveModalEventNotifiable?;

lazy var dummyModalView = UIView();

weak var targetView: UIView?;
weak var modalView: UIView?;

var animator: UIViewPropertyAnimator?;
var displayLink: CADisplayLink?;

weak var modalBackgroundView: UIView?;
weak var modalBackgroundVisualEffectView: UIVisualEffectView?;
weak var backgroundDimmingView: UIView?;
Expand All @@ -42,18 +43,28 @@ class AdaptiveModalManager {

var prevModalFrame: CGRect = .zero;

var nextSnapPointIndex: Int?;

var backgroundVisualEffectAnimator: AdaptiveModalPropertyAnimator?;
var modalBackgroundVisualEffectAnimator: AdaptiveModalPropertyAnimator?;

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

var animator: UIViewPropertyAnimator?;
var displayLink: CADisplayLink?;
var currentSizeProvider: () -> CGSize;

var prevSnapPointIndex: Int?;
var currentSnapPointIndex = 0 {
didSet {
self.prevSnapPointIndex = oldValue;
}
};

/// The computed frames of the modal based on the snap points
var interpolationSteps: [AdaptiveModalInterpolationPoint]?;

var currentInterpolationIndex = 0;

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

Expand Down Expand Up @@ -94,7 +105,7 @@ class AdaptiveModalManager {
};

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

var gestureInitialVelocity: CGVector? {
Expand Down Expand Up @@ -679,14 +690,14 @@ class AdaptiveModalManager {
// MARK: - Functions
// -----------------

func clearGestureValues(){
private func clearGestureValues(){
self.gestureOffset = nil;
self.gestureInitialPoint = nil;
self.gestureVelocity = nil;
self.gesturePoint = nil;
};

func clearAnimators(){
private func clearAnimators(){
self.backgroundVisualEffectAnimator?.clear();
self.backgroundVisualEffectAnimator = nil;

Expand Down Expand Up @@ -753,18 +764,17 @@ class AdaptiveModalManager {
animator.startAnimation();
};

func getClosestSnapPoint(
forGestureCoord gestureCoord: CGFloat
) -> (
snapPointIndex: Int,
func getClosestSnapPoint(forCoord coord: CGFloat? = nil) -> (
interpolationIndex: Int,
snapPointConfig: AdaptiveModalSnapPointConfig,
interpolationPoint: AdaptiveModalInterpolationPoint
)? {
guard let interpolationSteps = self.interpolationSteps,
let modalView = self.modalView
else { return nil };

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

let delta = interpolationSteps.map {
abs($0.computedRect.origin[keyPath: self.modalConfig.inputValueKeyForPoint] - inputCoord);
Expand All @@ -776,15 +786,18 @@ class AdaptiveModalManager {

let closestSnapPoint = deltaSorted.first!;

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

let interpolationPoint = interpolationSteps[closestInterpolationIndex];
let snapPointIndex = interpolationPoint.snapPointIndex;

return (
snapPointIndex: closestSnapPointIndex,
snapPointConfig: self.modalConfig.snapPoints[closestSnapPointIndex],
interpolationPoint: interpolationSteps[closestSnapPointIndex]
interpolationIndex: closestInterpolationIndex,
snapPointConfig: self.modalConfig.snapPoints[snapPointIndex],
interpolationPoint: interpolationPoint
);
};

Expand Down Expand Up @@ -917,10 +930,10 @@ class AdaptiveModalManager {
switch gesture.state {
case .began:
self.gestureInitialPoint = gesturePoint;


case .changed:
self.applyInterpolationToModal(forGesturePoint: gesturePoint);
self.onModalWillSnap();

case .cancelled, .ended:
guard self.enableSnapping else {
Expand All @@ -934,21 +947,25 @@ class AdaptiveModalManager {
gestureFinalPoint[keyPath: self.modalConfig.inputValueKeyForPoint];

let closestSnapPoint =
self.getClosestSnapPoint(forGestureCoord: gestureFinalCoord);
self.getClosestSnapPoint(forCoord: gestureFinalCoord);

guard let closestSnapPoint = closestSnapPoint else {
self.clearGestureValues();
return;
};

self.animateModal(to: closestSnapPoint.interpolationPoint) { _ in
self.endDisplayLink();
self.currentInterpolationIndex =
closestSnapPoint.interpolationIndex;

self.currentSnapPointIndex =
closestSnapPoint.interpolationPoint.snapPointIndex;

self.endDisplayLink();
self.onModalDidSnap();
};

self.startDisplayLink();

self.currentSnapPointIndex = closestSnapPoint.snapPointIndex;
self.clearGestureValues();

default:
Expand Down Expand Up @@ -991,4 +1008,38 @@ class AdaptiveModalManager {
duration: interpolatedDuration
);
};

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

func onModalWillSnap(){
guard let _ = self.modalView else { return };

guard let closestSnapPoint = self.getClosestSnapPoint()
else { return };

let prevIndex = self.nextSnapPointIndex;
let nextIndex = closestSnapPoint.interpolationPoint.snapPointIndex;

guard prevIndex != nextIndex else { return };
self.nextSnapPointIndex = nextIndex;

self.eventDelegate?.notifyOnModalWillSnap(
prevSnapPointIndex: prevIndex,
nextSnapPointIndex: nextIndex,
snapPointConfig: closestSnapPoint.snapPointConfig,
interpolationPoint: closestSnapPoint.interpolationPoint
);
};

func onModalDidSnap(){
self.eventDelegate?.notifyOnModalDidSnap(
prevSnapPointIndex: self.prevSnapPointIndex,
currentSnapPointIndex: self.currentSnapPointIndex,
snapPointConfig: self.currentSnapPointConfig,
interpolationPoint: self.currentInterpolationStep!
);

self.nextSnapPointIndex = nil;
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ enum AdaptiveModalConfigTestPresets: CaseIterable {
),
animationKeyframe: AdaptiveModalAnimationConfig(
modalBackgroundOpacity: 0.83,
modalCornerRadius: 15,
modalCornerRadius: 25,
modalMaskedCorners: [
.layerMinXMinYCorner,
.layerMaxXMinYCorner,
Expand All @@ -243,18 +243,23 @@ enum AdaptiveModalConfigTestPresets: CaseIterable {

class RNIDraggableTestViewController : UIViewController {

lazy var modalManager = AdaptiveModalManager(
modalConfig: AdaptiveModalConfigTestPresets.default.config,
modalView: self.floatingView,
targetView: self.view,
modalBackgroundView: self.modalBackgroundView,
modalBackgroundVisualEffectView: self.modalBackgroundVisualEffectView,
backgroundDimmingView: self.backgroundDimmingView,
backgroundVisualEffectView: self.backgroundVisualEffectView,
currentSizeProvider: {
.zero
}
);
lazy var modalManager = {
let manager = AdaptiveModalManager(
modalConfig: AdaptiveModalConfigTestPresets.default.config,
modalView: self.floatingView,
targetView: self.view,
modalBackgroundView: self.modalBackgroundView,
modalBackgroundVisualEffectView: self.modalBackgroundVisualEffectView,
backgroundDimmingView: self.backgroundDimmingView,
backgroundVisualEffectView: self.backgroundVisualEffectView,
currentSizeProvider: {
.zero
}
);

manager.eventDelegate = self;
return manager;
}();

private var initialGesturePoint: CGPoint = .zero;
private var floatingViewInitialCenter: CGPoint = .zero
Expand Down Expand Up @@ -373,3 +378,23 @@ class RNIDraggableTestViewController : UIViewController {

};
};

extension RNIDraggableTestViewController: AdaptiveModalEventNotifiable {
func notifyOnModalWillSnap(
prevSnapPointIndex: Int?,
nextSnapPointIndex: Int,
snapPointConfig: AdaptiveModalSnapPointConfig,
interpolationPoint: AdaptiveModalInterpolationPoint
) {
self.floatingViewLabel.text = "\(nextSnapPointIndex)";
}

func notifyOnModalDidSnap(
prevSnapPointIndex: Int?,
currentSnapPointIndex: Int,
snapPointConfig: AdaptiveModalSnapPointConfig,
interpolationPoint: AdaptiveModalInterpolationPoint
) {
self.floatingViewLabel.text = "\(currentSnapPointIndex)";
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
88C2F45C2A275B2800DA7450 /* AdaptiveModalSnapPointPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C2F45B2A275B2800DA7450 /* AdaptiveModalSnapPointPreset.swift */; };
88C2F45E2A278A9200DA7450 /* AdaptiveModalPropertyAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C2F45D2A278A9200DA7450 /* AdaptiveModalPropertyAnimator.swift */; };
88C2F4602A2CA8CF00DA7450 /* RoundedViewTestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C2F45F2A2CA8CF00DA7450 /* RoundedViewTestViewController.swift */; };
88C2F4622A2CD81F00DA7450 /* AdaptiveModalEventNotifiable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88C2F4612A2CD81F00DA7450 /* AdaptiveModalEventNotifiable.swift */; };
88D016602A14C86B004664D2 /* RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D0165F2A14C86B004664D2 /* RootViewController.swift */; };
88D0168D2A1730B1004664D2 /* RNILayoutTestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D0168C2A1730B1004664D2 /* RNILayoutTestViewController.swift */; };
88D0169E2A1B0DD3004664D2 /* RNIDraggableTestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88D0169D2A1B0DD3004664D2 /* RNIDraggableTestViewController.swift */; };
Expand Down Expand Up @@ -105,6 +106,7 @@
88C2F45B2A275B2800DA7450 /* AdaptiveModalSnapPointPreset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveModalSnapPointPreset.swift; sourceTree = "<group>"; };
88C2F45D2A278A9200DA7450 /* AdaptiveModalPropertyAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveModalPropertyAnimator.swift; sourceTree = "<group>"; };
88C2F45F2A2CA8CF00DA7450 /* RoundedViewTestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedViewTestViewController.swift; sourceTree = "<group>"; };
88C2F4612A2CD81F00DA7450 /* AdaptiveModalEventNotifiable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdaptiveModalEventNotifiable.swift; sourceTree = "<group>"; };
88D0165F2A14C86B004664D2 /* RootViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootViewController.swift; sourceTree = "<group>"; };
88D0168C2A1730B1004664D2 /* RNILayoutTestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNILayoutTestViewController.swift; sourceTree = "<group>"; };
88D0169D2A1B0DD3004664D2 /* RNIDraggableTestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RNIDraggableTestViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -523,6 +525,7 @@
88C2F45D2A278A9200DA7450 /* AdaptiveModalPropertyAnimator.swift */,
88D0188D2A1DCA61004664D2 /* AdaptiveModalManager.swift */,
88075E262A2121FE00B78388 /* AdaptiveModalManager+Helpers.swift */,
88C2F4612A2CD81F00DA7450 /* AdaptiveModalEventNotifiable.swift */,
);
path = AdaptiveModal;
sourceTree = "<group>";
Expand Down Expand Up @@ -658,6 +661,7 @@
88D018882A1D0A36004664D2 /* AdaptiveModalConfig.swift in Sources */,
88D018432A1B3030004664D2 /* UIGestureRecognizer+Helpers.swift in Sources */,
88D0185B2A1B3030004664D2 /* RNIIdentifiable+Default.swift in Sources */,
88C2F4622A2CD81F00DA7450 /* AdaptiveModalEventNotifiable.swift in Sources */,
88D018762A1B3030004664D2 /* RNIComputableSizeMode.swift in Sources */,
88D018262A1B3030004664D2 /* UIColor+Helpers.swift in Sources */,
88E8C0182A224A8D008C2FF8 /* AdaptiveModalSnapAnimationConfig.swift in Sources */,
Expand Down

0 comments on commit 5d26263

Please sign in to comment.