diff --git a/ios/Temp/ModalSheetViewControllerLifecycleNotifier.swift b/ios/Temp/ModalSheetViewControllerLifecycleNotifier.swift index f05afce8..c9fc56d3 100644 --- a/ios/Temp/ModalSheetViewControllerLifecycleNotifier.swift +++ b/ios/Temp/ModalSheetViewControllerLifecycleNotifier.swift @@ -9,7 +9,7 @@ import UIKit import DGSwiftUtilities -open class ModalSheetViewControllerLifecycleNotifier: ViewControllerLifecycleNotifier { +open class ModalSheetViewControllerLifecycleNotifier: ModalViewControllerLifecycleNotifier { private var _didSetup = false; private var _didSetupRootScrollView = false; @@ -56,11 +56,13 @@ open class ModalSheetViewControllerLifecycleNotifier: ViewControllerLifecycleNot }; public override func viewDidAppear(_ animated: Bool) { + defer { + super.viewDidAppear(animated); + }; + if self.isAppearingForTheFirstTime { self.setupRootScrollViewIfNeeded(); }; - - super.viewDidAppear(animated); }; // MARK: - Setup diff --git a/ios/Temp/ModalViewControllerEventsNotifiable.swift b/ios/Temp/ModalViewControllerEventsNotifiable.swift new file mode 100644 index 00000000..26951988 --- /dev/null +++ b/ios/Temp/ModalViewControllerEventsNotifiable.swift @@ -0,0 +1,66 @@ +// +// ModalViewControllerEventsNotifiable.swift +// react-native-ios-modal +// +// Created by Dominic Go on 9/30/24. +// + +import UIKit + + +public protocol ModalViewControllerEventsNotifiable { + + func notifyOnModalWillPresent( + sender: UIViewController, + isAnimated: Bool + ); + + func notifyOnModalDidPresent( + sender: UIViewController, + isAnimated: Bool + ); + + func notifyOnModalWillDismiss( + sender: UIViewController, + isAnimated: Bool + ); + + func notifyOnModalDidDismiss( + sender: UIViewController, + isAnimated: Bool + ); +}; + +// MARK: - ModalViewControllerEventsNotifiable +// ------------------------------------------- + +public extension ModalViewControllerEventsNotifiable { + + func notifyOnModalWillPresent( + sender: UIViewController, + isAnimated: Bool + ) { + // no-op + }; + + func notifyOnModalDidPresent( + sender: UIViewController, + isAnimated: Bool + ) { + // no-op + }; + + func notifyOnModalWillDismiss( + sender: UIViewController, + isAnimated: Bool + ) { + // no-op + }; + + func notifyOnModalDidDismiss( + sender: UIViewController, + isAnimated: Bool + ) { + // no-op + }; +}; diff --git a/ios/Temp/ModalViewControllerLifecycleNotifier.swift b/ios/Temp/ModalViewControllerLifecycleNotifier.swift new file mode 100644 index 00000000..a98573b4 --- /dev/null +++ b/ios/Temp/ModalViewControllerLifecycleNotifier.swift @@ -0,0 +1,126 @@ +// +// ModalViewControllerLifecycleNotifier.swift +// react-native-ios-modal +// +// Created by Dominic Go on 9/30/24. +// + +import UIKit +import DGSwiftUtilities + + +open class ModalViewControllerLifecycleNotifier: ViewControllerLifecycleNotifier { + + public var isExplicitlySomeKindOfModal = false; + public var isExplicitlyBeingDismissed = false; + + private(set) public var modalLifecycleEventDelegates: + MulticastDelegate = .init(); + + // MARK: - View Controller Lifecycle + // --------------------------------- + + public override func viewWillAppear(_ animated: Bool) { + defer { + super.viewWillAppear(animated); + }; + + guard self.isAppearingForTheFirstTime else { + return; + }; + + self.isExplicitlySomeKindOfModal = + self.isBeingPresented + || self.presentingViewController?.presentedViewController === self; + + guard self.isExplicitlySomeKindOfModal else { + return; + }; + + self.modalLifecycleEventDelegates.invoke { + $0.notifyOnModalWillPresent( + sender: self, + isAnimated: animated + ); + }; + }; + + public override func viewDidAppear(_ animated: Bool) { + defer { + super.viewDidAppear(animated); + }; + + guard self.isAppearingForTheFirstTime, + self.isExplicitlySomeKindOfModal + else { + return; + }; + + self.modalLifecycleEventDelegates.invoke { + $0.notifyOnModalDidPresent( + sender: self, + isAnimated: animated + ); + }; + }; + + public override func viewWillDisappear(_ animated: Bool) { + defer { + super.viewWillDisappear(animated); + }; + + guard self.isBeingDismissed, + self.isExplicitlySomeKindOfModal + else { + return; + }; + + guard animated, + let transitionCoordinator = self.transitionCoordinator + else { + self.isExplicitlyBeingDismissed = true; + + self.modalLifecycleEventDelegates.invoke { + $0.notifyOnModalWillDismiss( + sender: self, + isAnimated: false + ); + }; + return; + }; + + transitionCoordinator.notifyWhenInteractionChanges { context in + guard !context.isCancelled else { + return; + }; + + self.isExplicitlyBeingDismissed = true; + self.modalLifecycleEventDelegates.invoke { + $0.notifyOnModalWillDismiss( + sender: self, + isAnimated: context.isAnimated + ); + }; + }; + }; + + public override func viewDidDisappear(_ animated: Bool) { + defer { + super.viewDidDisappear(animated); + }; + + guard self.isBeingDismissed, + self.isExplicitlySomeKindOfModal, + self.isExplicitlyBeingDismissed + else { + return; + }; + + self.modalLifecycleEventDelegates.invoke { + $0.notifyOnModalDidDismiss( + sender: self, + isAnimated: animated + ); + }; + }; +}; diff --git a/ios/Temp/ViewControllerLifecycleNotifier.swift b/ios/Temp/ViewControllerLifecycleNotifier.swift index 467b7121..f858df45 100644 --- a/ios/Temp/ViewControllerLifecycleNotifier.swift +++ b/ios/Temp/ViewControllerLifecycleNotifier.swift @@ -58,9 +58,14 @@ open class ViewControllerLifecycleNotifier: UIViewController { "ViewControllerLifecycleNotifier.\(#function)", "\n - instance:", Unmanaged.passUnretained(self).toOpaque(), "\n - className:", self.className, + "\n - self:", self.debugDescription, "\n - animated:", animated, "\n - isBeingPresented:", self.isBeingPresented, "\n - isAppearingForTheFirstTime:", self.isAppearingForTheFirstTime, + "\n - presentationController:", self.presentationController.debugDescription, + "\n - transitionCoordinator:", self.transitionCoordinator?.debugDescription ?? "N/A", + "\n - presentingViewController:", self.presentingViewController?.debugDescription ?? "N/A", + "\n - presentingViewController.presentedViewController:", self.presentingViewController?.presentedViewController.debugDescription ?? "N/A", "\n" ); };