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 7, 2023
1 parent 5e816df commit 8bd29c3
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// AdaptiveModalManager+UIViewControllerAnimatedTransitioning.swift
// swift-programmatic-modal
//
// Created by Dominic Go on 6/8/23.
//

import UIKit

extension AdaptiveModalManager: UIViewControllerAnimatedTransitioning {

func transitionDuration(
using transitionContext: UIViewControllerContextTransitioning?
) -> TimeInterval {
// to be implemented
return 1;
};

func animateTransition(
using transitionContext: UIViewControllerContextTransitioning
) {
//TBA
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// AdaptiveModalManager+UIViewControllerTransitioningDelegate.swift
// swift-programmatic-modal
//
// Created by Dominic Go on 6/8/23.
//

import UIKit


extension AdaptiveModalManager: UIViewControllerTransitioningDelegate {

func animationController(
forPresented presented: UIViewController,
presenting: UIViewController,
source: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
return nil;
};

func animationController(
forDismissed dismissed: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
return nil;
};

func presentationController(
forPresented presented: UIViewController,
presenting: UIViewController?,
source: UIViewController
) -> UIPresentationController? {

return AdaptiveModalPresentationController(
presentedViewController: presented,
presenting: presenting,
modalManager: self
);
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import UIKit

class AdaptiveModalManager {
class AdaptiveModalManager: NSObject {

// MARK: - Properties - Config-Related
// ------------------------------------
Expand All @@ -16,56 +16,63 @@ class AdaptiveModalManager {

var enableSnapping = true;

// MARK: - Properties - Refs
// --------------------------
// MARK: - Properties - Views/View Controllers
// --------------------------------------------

weak var modalViewController: UIViewController?;
weak var targetViewController: UIViewController?;

weak var eventDelegate: AdaptiveModalEventNotifiable?;

lazy var dummyModalView = UIView();
lazy var modalWrapperView = UIView();

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

lazy var dummyModalView = UIView();
lazy var modalWrapperView = UIView();

var modalBackgroundView: UIView?;
var modalBackgroundVisualEffectView: UIVisualEffectView?;

var backgroundDimmingView: UIView?;
var backgroundVisualEffectView: UIVisualEffectView?;

// MARK: - Properties - Animation + Gesture Related
// -------------------------------------------------

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

weak var modalBackgroundView: UIView?;
weak var modalBackgroundVisualEffectView: UIVisualEffectView?;
weak var backgroundDimmingView: UIView?;
weak var backgroundVisualEffectView: UIVisualEffectView?;

var displayLinkStartTimestamp: CFTimeInterval?;

var gestureOffset: CGPoint?;
var gestureVelocity: CGPoint?;
var gestureInitialPoint: CGPoint?;
var gesturePoint: CGPoint?;

var prevModalFrame: CGRect = .zero;

var nextSnapPointIndex: Int?;

var backgroundVisualEffectAnimator: AdaptiveModalRangePropertyAnimator?;
var modalBackgroundVisualEffectAnimator: AdaptiveModalRangePropertyAnimator?;

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

var currentSizeProvider: () -> CGSize;
weak var eventDelegate: AdaptiveModalEventNotifiable?;

var currentSizeProvider: (() -> CGSize)?;

var prevModalFrame: CGRect = .zero;

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

var currentInterpolationIndex = 0;

var prevSnapPointIndex: Int?;
var nextSnapPointIndex: 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 @@ -191,25 +198,28 @@ class AdaptiveModalManager {
modalConfig: AdaptiveModalConfig,
modalView: UIView,
targetView: UIView,
modalBackgroundView: UIView? = nil,
modalBackgroundVisualEffectView: UIVisualEffectView? = nil,
backgroundDimmingView: UIView? = nil,
backgroundVisualEffectView: UIVisualEffectView? = nil,
currentSizeProvider: @escaping () -> CGSize
currentSizeProvider: (() -> CGSize)? = nil
) {
self.modalConfig = modalConfig;

self.modalView = modalView;
self.targetView = targetView;

self.modalBackgroundView = modalBackgroundView;
self.modalBackgroundVisualEffectView = modalBackgroundVisualEffectView;
self.currentSizeProvider = currentSizeProvider ?? { .zero };

super.init();

self.backgroundVisualEffectView = backgroundVisualEffectView;
self.backgroundDimmingView = backgroundDimmingView;
self.setupInitViews();
self.setupDummyModalView();
};

init(modalConfig: AdaptiveModalConfig) {
self.modalConfig = modalConfig;

self.currentSizeProvider = currentSizeProvider;
super.init();

self.setupViewControllers();
self.setupInitViews();
self.setupDummyModalView();
};

Expand All @@ -220,6 +230,19 @@ class AdaptiveModalManager {
// MARK: - Functions - Setup
// -------------------------

func setupViewControllers() {
modalViewController?.modalPresentationStyle = .custom;
modalViewController?.transitioningDelegate = self;
};

func setupInitViews(){
self.modalBackgroundView = UIView();
self.modalBackgroundVisualEffectView = UIVisualEffectView();

self.backgroundDimmingView = UIView();
self.backgroundVisualEffectView = UIVisualEffectView();
};

private func setupDummyModalView(){
guard let targetView = self.targetView else { return };
let dummyModalView = self.dummyModalView;
Expand Down Expand Up @@ -1032,6 +1055,24 @@ class AdaptiveModalManager {
// MARK: - User-Invoked Functions
// ------------------------------

func set(
viewControllerToPresent: UIViewController,
presentingViewController: UIViewController
) {
self.modalViewController = viewControllerToPresent;
self.targetViewController = presentingViewController;

self.modalView = viewControllerToPresent.view;
self.targetView = presentingViewController.view;

self.currentSizeProvider = currentSizeProvider ?? { .zero };

self.setupViewControllers();
self.setupDummyModalView();
self.setupInitViews();
self.setupViewConstraints();
};

func computeSnapPoints(forTargetView nextTargetView: UIView? = nil) {
if nextTargetView != nil {
self.targetView = nextTargetView;
Expand All @@ -1040,7 +1081,7 @@ class AdaptiveModalManager {
guard let targetView = nextTargetView ?? self.targetView
else { return };

let currentSize = self.currentSizeProvider();
let currentSize = self.currentSizeProvider?() ?? .zero;

self.interpolationSteps = .Element.compute(
usingModalConfig: self.modalConfig,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// AdaptiveModalPresentationController.swift
// swift-programmatic-modal
//
// Created by Dominic Go on 6/8/23.
//

import UIKit

class AdaptiveModalPresentationController: UIPresentationController {

weak var modalManager: AdaptiveModalManager!;

init(
presentedViewController: UIViewController,
presenting presentingViewController: UIViewController?,
modalManager: AdaptiveModalManager
) {
super.init(
presentedViewController: presentedViewController,
presenting: presentingViewController
);

self.modalManager = modalManager;
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,32 @@
import UIKit

enum RNILayoutPreset {
case offscreenBottom, offscreenTop, offscreenLeft, offscreenRight;
case halfOffscreenBottom, halfOffscreenTop, halfOffscreenLeft, halfOffscreenRight;
case edgeBottom, edgeTop, edgeLeft, edgeRight;
case fitScreen, fitScreenHorizontally, fitScreenVertically;
case offscreenBottom,
offscreenTop,
offscreenLeft,
offscreenRight;

case halfOffscreenBottom,
halfOffscreenTop,
halfOffscreenLeft,
halfOffscreenRight;

case edgeBottom,
edgeTop,
edgeLeft,
edgeRight;

case fitScreen,
fitScreenHorizontally,
fitScreenVertically;

case center;

case layoutConfig(_ config: RNILayout);

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

func getLayoutConfig(
fromBaseLayoutConfig baseLayoutConfig: RNILayout,
withTargetRect targetRect: CGRect,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// AdaptiveModalPresentationTest.swift
// swift-programmatic-modal
//
// Created by Dominic Go on 6/7/23.
//

import UIKit

class TestViewController: UIViewController {
override func viewDidLoad() {
self.view.backgroundColor = .white;
};
};

class AdaptiveModalPresentationTestViewController : UIViewController {

lazy var adaptiveModalManager = AdaptiveModalManager(
modalConfig: AdaptiveModalConfigTestPresets.test03.config
);

override func viewDidLoad() {
self.view.backgroundColor = .white;

let dummyBackgroundView: UIView = {
let imageView = UIImageView(
image: UIImage(named: "DummyBackgroundImage2")
);

imageView.contentMode = .scaleAspectFill;
return imageView;
}();

self.view.addSubview(dummyBackgroundView);
dummyBackgroundView.translatesAutoresizingMaskIntoConstraints = false;

NSLayoutConstraint.activate([
dummyBackgroundView.topAnchor .constraint(equalTo: self.view.topAnchor ),
dummyBackgroundView.bottomAnchor .constraint(equalTo: self.view.bottomAnchor ),
dummyBackgroundView.leadingAnchor .constraint(equalTo: self.view.leadingAnchor ),
dummyBackgroundView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
]);

let presentButton: UIButton = {
let button = UIButton();
button.setTitle("Present View Controller", for: .normal);

button.addTarget(
self,
action: #selector(self.onPressButtonPresentViewController(_:)),
for: .touchUpInside
);

return button;
}();

self.view.addSubview(presentButton);
presentButton.translatesAutoresizingMaskIntoConstraints = false;

NSLayoutConstraint.activate([
presentButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
presentButton.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
]);
};

override func viewDidLayoutSubviews() {

};

@objc func onPressButtonPresentViewController(_ sender: UIButton) {
let testVC = TestViewController();
self.present(testVC, animated: true);
};
};
Loading

0 comments on commit 8bd29c3

Please sign in to comment.