From 70ff74942eb264327834a58dd0dc1ca56405b1f2 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Wed, 20 Sep 2023 16:07:08 +0600 Subject: [PATCH 01/10] MBX-0000 New way --- .../SnackbarPresentationStrategy.swift | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift index 2360e009..1b0c0fb8 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift @@ -11,13 +11,28 @@ import MindboxLogger final class SnackbarPresentationStrategy: PresentationStrategyProtocol { func getWindow() -> UIWindow? { - return UIApplication.shared.windows.first(where: { $0.isKeyWindow }) + if #available(iOS 13, *) { + return UIApplication.shared.connectedScenes + .filter { $0.activationState == .foregroundActive } + .compactMap { $0 as? UIWindowScene } + .first?.windows + .first(where: { $0.isKeyWindow }) + } else { + return UIApplication.shared.keyWindow + } } - + func present(id: String, in window: UIWindow, using viewController: UIViewController) { - window.rootViewController?.addChild(viewController) - window.rootViewController?.view.addSubview(viewController.view) - Logger.common(message: "In-app with id \(id) presented", level: .info, category: .inAppMessages) + if var topController = window.rootViewController { + while let presentedViewController = topController.presentedViewController { + topController = presentedViewController + } + + topController.view.addSubview(viewController.view) + Logger.common(message: "In-app with id \(id) presented", level: .info, category: .inAppMessages) + } else { + Logger.common(message: "Unable to get top controller. Abort.", level: .error, category: .inAppMessages) + } } func dismiss(viewController: UIViewController) { From 338df1db5d7140c9da48fa62cd7e628ee5c8a400 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Tue, 26 Sep 2023 13:01:37 +0600 Subject: [PATCH 02/10] MBX-0000 New way 2 --- .../SnackbarView/SnackbarViewController.swift | 51 ++++++++----------- .../ViewFactory/SnackbarViewFactory.swift | 5 +- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift index bcb7ff5e..84d7c025 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift @@ -11,7 +11,7 @@ import MindboxLogger class SnackbarViewController: UIViewController, InappViewControllerProtocol { - var snackbarView: SnackbarView? + var edgeConstraint: NSLayoutConstraint? let model: SnackbarFormVariant @@ -35,9 +35,9 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private let imagesDict: [String: UIImage] + let snackbarView: SnackbarView private let firstImageValue: String private let onPresented: () -> Void - private let onClose: () -> Void private let onTapAction: (ContentBackgroundLayerAction?) -> Void private var hasSetupLayers = false @@ -52,16 +52,16 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { init( model: SnackbarFormVariant, imagesDict: [String: UIImage], + snackbarView: SnackbarView, firstImageValue: String, onPresented: @escaping () -> Void, - onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, - onClose: @escaping () -> Void + onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void ) { self.model = model self.imagesDict = imagesDict + self.snackbarView = snackbarView self.firstImageValue = firstImageValue self.onPresented = onPresented - self.onClose = onClose self.onTapAction = onTapAction super.init(nibName: nil, bundle: nil) } @@ -73,12 +73,9 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { override func viewDidLoad() { super.viewDidLoad() view.isUserInteractionEnabled = true - snackbarView = SnackbarView(onClose: onClose) - if let snackbarView = snackbarView { - snackbarView.translatesAutoresizingMaskIntoConstraints = false - snackbarView.isUserInteractionEnabled = true - view.addSubview(snackbarView) - } + snackbarView.translatesAutoresizingMaskIntoConstraints = false + snackbarView.isUserInteractionEnabled = true + view.addSubview(snackbarView) } override func viewDidLayoutSubviews() { @@ -88,11 +85,11 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { setupConstraints() setupLayers() - if snackbarView?.bounds.size != .zero { + if snackbarView.bounds.size != .zero { setupElements() hasSetupElements = true } - } else if !hasSetupElements && snackbarView?.bounds.size != .zero { + } else if !hasSetupElements && snackbarView.bounds.size != .zero { UIView.performWithoutAnimation { setupElements() hasSetupElements = true @@ -109,9 +106,6 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { private func setupLayers() { let layers = model.content.background.layers.elements - guard let snackbarView = snackbarView else { - return - } for layer in layers { if let factory = layersFactories[layer.layerType] { @@ -130,8 +124,8 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private func setupElements() { - guard let elements = model.content.elements?.elements, - let snackbarView = snackbarView else { + guard let elements = model.content.elements?.elements else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } @@ -162,6 +156,7 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { func setupConstraints() { guard let image = imagesDict[firstImageValue] else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } @@ -171,9 +166,6 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight setViewFrame(with: finalHeight) - guard let snackbarView = snackbarView else { - return - } snackbarView.swipeDirection = swipeDirection snackbarView.translatesAutoresizingMaskIntoConstraints = false @@ -187,10 +179,6 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } func setupLayoutConstraints(with height: CGFloat) { - guard let snackbarView = snackbarView else { - return - } - if #available(iOS 11.0, *) { NSLayoutConstraint.activate([ snackbarView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), @@ -214,6 +202,7 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { extension SnackbarViewController: GestureHandler { @objc func imageTapped(_ sender: UITapGestureRecognizer) { guard let imageView = sender.view as? InAppImageOnlyView else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } @@ -223,13 +212,14 @@ extension SnackbarViewController: GestureHandler { @objc func onCloseButton(_ gesture: UILongPressGestureRecognizer) { guard let crossView = gesture.view else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } let location = gesture.location(in: crossView) let isInsideCrossView = crossView.bounds.contains(location) if gesture.state == .ended && isInsideCrossView { - snackbarView?.hide() + snackbarView.hide() } } } @@ -254,9 +244,9 @@ class TopSnackbarViewController: SnackbarViewController { override func setupEdgeConstraint(with height: CGFloat) { if #available(iOS 11.0, *) { - edgeConstraint = snackbarView?.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: -height) + edgeConstraint = snackbarView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: -height) } else { - edgeConstraint = snackbarView?.topAnchor.constraint(equalTo: view.topAnchor, constant: -height) + edgeConstraint = snackbarView.topAnchor.constraint(equalTo: view.topAnchor, constant: -height) } edgeConstraint?.isActive = true @@ -281,13 +271,14 @@ class BottomSnackbarViewController: SnackbarViewController { self.view.frame = CGRect(x: leftOffset, y: screenHeight - finalHeight, width: UIScreen.main.bounds.width - leftOffset - rightOffset, height: finalHeight) + self.view.backgroundColor = .green } override func setupEdgeConstraint(with height: CGFloat) { if #available(iOS 11.0, *) { - edgeConstraint = snackbarView?.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: height) + edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: height) } else { - edgeConstraint = snackbarView?.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: height) + edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: height) } edgeConstraint?.isActive = true diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift index 3be04580..3381b6a0 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift @@ -17,11 +17,12 @@ class SnackbarViewFactory: ViewFactoryProtocol { if case .snackbar(let snackbarFormVariant) = model { if let gravity = snackbarFormVariant.content.position?.gravity?.element?.vertical { var snackbarViewController: UIViewController? + let snackbarView = SnackbarView(onClose: onClose) switch gravity { case .top: - snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) + snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) case .bottom: - snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) + snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) default: return nil } From 23426d8743efa0e411c32cc10ffd68145ba0ef7a Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Wed, 27 Sep 2023 13:43:11 +0600 Subject: [PATCH 03/10] MBX-0000 New way 3 --- Mindbox/CoreController/CoreController.swift | 1 + .../PresentationDisplayUseCase.swift | 6 +++ .../SnackbarPresentationStrategy.swift | 11 ++++- .../CommonViews/InAppImageOnlyView.swift | 5 +++ .../ImageLayer/ImageLayerFactory.swift | 7 +++- .../Views/SnackbarView/SnackbarView.swift | 9 +++- .../SnackbarView/SnackbarViewController.swift | 41 ++++++++++++++++++- .../ViewFactory/SnackbarViewFactory.swift | 8 +++- 8 files changed, 80 insertions(+), 8 deletions(-) diff --git a/Mindbox/CoreController/CoreController.swift b/Mindbox/CoreController/CoreController.swift index 3b2aeb63..5658c53f 100644 --- a/Mindbox/CoreController/CoreController.swift +++ b/Mindbox/CoreController/CoreController.swift @@ -37,6 +37,7 @@ class CoreController { self.inAppMessagesManager.start() } + Logger.common(message: "New way 3 test commit!", level: .info, category: .general) Logger.common(message: "[Configuration]: \(configuration)", level: .info, category: .general) Logger.common(message: "[SDK Version]: \(self.utilitiesFetcher.sdkVersion ?? "null")", level: .info, category: .general) Logger.common(message: "[APNS Token]: \(self.persistenceStorage.apnsToken ?? "null")", level: .info, category: .general) diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift index 62301b96..7643e118 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift @@ -30,11 +30,15 @@ final class PresentationDisplayUseCase { return } + Logger.common(message: "PresentationDisplayUseCase window: \(window)") + guard let factory = self.factory else { Logger.common(message: "Factory does not exists.", level: .error, category: .general) return } + Logger.common(message: "PresentationDisplayUseCase factory: \(factory)", level: .error) + guard let viewController = factory.create(model: model.content, id: model.inAppId, imagesDict: model.imagesDict, @@ -45,6 +49,8 @@ final class PresentationDisplayUseCase { return } + Logger.common(message: "PresentationDisplayUseCase viewController: \(viewController)") + presentedVC = viewController presentationStrategy?.present(id: model.inAppId, in: window, using: viewController) } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift index 1b0c0fb8..e1cdefcf 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift @@ -11,14 +11,20 @@ import MindboxLogger final class SnackbarPresentationStrategy: PresentationStrategyProtocol { func getWindow() -> UIWindow? { + Logger.common(message: "SnackbarPresentationStrategy getWindow started.") if #available(iOS 13, *) { - return UIApplication.shared.connectedScenes + let window = UIApplication.shared.connectedScenes .filter { $0.activationState == .foregroundActive } .compactMap { $0 as? UIWindowScene } .first?.windows .first(where: { $0.isKeyWindow }) + + Logger.common(message: "SnackbarPresentationStrategy window iOS 13+: \(window).") + return window } else { - return UIApplication.shared.keyWindow + let window = UIApplication.shared.keyWindow + Logger.common(message: "SnackbarPresentationStrategy window iOS 12 or less: \(window).") + return window } } @@ -26,6 +32,7 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { if var topController = window.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController + Logger.common(message: "SnackbarPresentationStrategy topController equal = \(topController).") } topController.view.addSubview(viewController.view) diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift index f8e008af..34b82e8d 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift @@ -6,6 +6,7 @@ // import UIKit +import MindboxLogger final class InAppImageOnlyView: UIView { var onClose: (() -> Void)? @@ -29,11 +30,15 @@ final class InAppImageOnlyView: UIView { func customInit() { guard let image = image else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } + Logger.common(message: "InAppImageOnlyView custom init started.") + imageView.contentMode = .scaleAspectFill imageView.image = image + imageView.layer.opacity = 0.5 imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] addSubview(imageView) diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift index e185019a..eda52d9d 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift @@ -7,6 +7,7 @@ // import UIKit +import MindboxLogger class ImageLayerFactory: LayerFactory { func create(from image: UIImage, layer: ContentBackgroundLayer, in view: UIView, with controller: GestureHandler) -> UIView? { @@ -14,10 +15,11 @@ class ImageLayerFactory: LayerFactory { let inAppView = InAppImageOnlyView(image: image, action: imageContentBackgroundLayer.action) let imageTapGestureRecognizer = UITapGestureRecognizer(target: controller, action: #selector(controller.imageTapped(_:))) inAppView.addGestureRecognizer(imageTapGestureRecognizer) - + Logger.common(message: "ImageLayerFactory return uiView.") return inAppView } - + + Logger.common(message: "ImageLayerFactory return nil.") return nil } @@ -39,5 +41,6 @@ class ImageLayerFactory: LayerFactory { view.leadingAnchor.constraint(equalTo: parentView.leadingAnchor), view.trailingAnchor.constraint(equalTo: parentView.trailingAnchor) ]) + Logger.common(message: "ImageLayerFactory setupConstraintsSnackbar finished.") } } diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift index 486f7b32..27609516 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift @@ -6,6 +6,7 @@ // import UIKit +import MindboxLogger class SnackbarView: UIView { @@ -39,7 +40,7 @@ class SnackbarView: UIView { self.onClose = onClose self.animationTime = animationTime super.init(frame: .zero) - + Logger.common(message: "SnackbarView inited.") setupPanGesture() } @@ -63,6 +64,7 @@ class SnackbarView: UIView { private func handleSwipeGesture(translation: CGPoint) { if (swipeDirection == .up && translation.y < 0) || (swipeDirection == .down && translation.y > 0) { self.transform = CGAffineTransform(translationX: 0, y: translation.y) + Logger.common(message: "SnackbarView handleSwipeGesture.") } } @@ -72,9 +74,12 @@ class SnackbarView: UIView { if ((swipeDirection == .up && translation.y < 0) || (swipeDirection == .down && translation.y > 0)) && abs(translation.y) > threshold { animateHide(completion: onClose, animated: true) + Logger.common(message: "SnackbarView finalizeGesture.") + } else { UIView.animate(withDuration: animationTime) { self.transform = .identity + Logger.common(message: "SnackbarView finalizeGesture fallback.") } } } @@ -103,6 +108,7 @@ class SnackbarView: UIView { yOffset = 0 } self.transform = CGAffineTransform(translationX: 0, y: yOffset) + Logger.common(message: "SnackbarView setHiddenTransform yOffset: \(yOffset).") } public func hide(animated: Bool = true, completion: (() -> Void)? = nil) { @@ -113,6 +119,7 @@ class SnackbarView: UIView { } required init?(coder: NSCoder) { + Logger.common(message: "SnackbarView init(coder:) has not been implemented.") fatalError("init(coder:) has not been implemented") } } diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift index 84d7c025..4072b84f 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift @@ -64,49 +64,62 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { self.onPresented = onPresented self.onTapAction = onTapAction super.init(nibName: nil, bundle: nil) + Logger.common(message: "SnackbarViewController inited.") } required init?(coder: NSCoder) { + Logger.common(message: "SnackbarViewController init(coder:) has not been implemented.") fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() + view.addSubview(snackbarView) view.isUserInteractionEnabled = true snackbarView.translatesAutoresizingMaskIntoConstraints = false snackbarView.isUserInteractionEnabled = true - view.addSubview(snackbarView) + snackbarView.backgroundColor = .blue + Logger.common(message: "SnackbarViewController viewDidLoad.") } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() + Logger.common(message: "SnackbarViewController flag hasSetupLayers: \(hasSetupLayers).") if !hasSetupLayers { hasSetupLayers = true setupConstraints() setupLayers() + Logger.common(message: "SnackbarViewController we're in !hasSetupLayers condition.") if snackbarView.bounds.size != .zero { + Logger.common(message: "SnackbarViewController we're in !snackbarView.bound.size != zero condition.") setupElements() hasSetupElements = true } } else if !hasSetupElements && snackbarView.bounds.size != .zero { + Logger.common(message: "SnackbarViewController we're in !hasSetupElements && snackbarView.bounds.size != .zero condition.") UIView.performWithoutAnimation { setupElements() hasSetupElements = true view.layoutIfNeeded() } } + + Logger.common(message: "SnackbarViewController viewDidLayoutSubviews done.") } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) animateConstraints(withDuration: Constants.animationDuration) onPresented() + Logger.common(message: "SnackbarViewController viewDidAppear.") } private func setupLayers() { + Logger.common(message: "SnackbarViewController setupLayers function started.") let layers = model.content.background.layers.elements + Logger.common(message: "SnackbarViewController layers: \(layers.count).") for layer in layers { if let factory = layersFactories[layer.layerType] { if case .image(let imageContentBackgroundLayer) = layer { @@ -116,11 +129,20 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { self.layers.append(layerView) snackbarView.addSubview(layerView) factory.setupConstraintsSnackbar(for: layerView, in: snackbarView) + } else { + Logger.common(message: "SnackbarViewController layer view does not exists.") } + } else { + Logger.common(message: "SnackbarViewController imageContentBackgroundLayer source or value does not exists.\n[Layer]: \(imageContentBackgroundLayer)\n[Dict]: \(imagesDict)") } + } else { + Logger.common(message: "SnackbarViewController not image type of layer.") } + } else { + Logger.common(message: "SnackbarViewController layersFactory does not exists.") } } + Logger.common(message: "SnackbarViewController setupLayers function finished.") } private func setupElements() { @@ -146,15 +168,19 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private func animateConstraints(withDuration duration: TimeInterval) { + Logger.common(message: "SnackbarViewController animateConstraints function started.") view.layoutIfNeeded() UIView.animate(withDuration: duration) { self.edgeConstraint?.constant = 0 + Logger.common(message: "SnackbarViewController animateConstraints UIView.animate condition.") self.view.layoutIfNeeded() } + Logger.common(message: "SnackbarViewController animateConstraints function finished.") } func setupConstraints() { + Logger.common(message: "SnackbarViewController setupConstraints function started.") guard let image = imagesDict[firstImageValue] else { Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return @@ -172,6 +198,8 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { setupLayoutConstraints(with: finalHeight) setupEdgeConstraint(with: finalHeight) + + Logger.common(message: "SnackbarViewController setupConstraints function finished.") } func setViewFrame(with height: CGFloat) { @@ -179,19 +207,23 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } func setupLayoutConstraints(with height: CGFloat) { + Logger.common(message: "SnackbarViewController setupLayoutConstraints function started.") if #available(iOS 11.0, *) { + Logger.common(message: "SnackbarViewController setupLayoutConstraints iOS 11+.") NSLayoutConstraint.activate([ snackbarView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), snackbarView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), snackbarView.heightAnchor.constraint(equalToConstant: height), ]) } else { + Logger.common(message: "SnackbarViewController setupLayoutConstraints iOS 10.") NSLayoutConstraint.activate([ snackbarView.leadingAnchor.constraint(equalTo: view.leadingAnchor), snackbarView.trailingAnchor.constraint(equalTo: view.trailingAnchor), snackbarView.heightAnchor.constraint(equalToConstant: height), ]) } + Logger.common(message: "SnackbarViewController setupLayoutConstraints function finished.") } func setupEdgeConstraint(with height: CGFloat) { @@ -271,16 +303,21 @@ class BottomSnackbarViewController: SnackbarViewController { self.view.frame = CGRect(x: leftOffset, y: screenHeight - finalHeight, width: UIScreen.main.bounds.width - leftOffset - rightOffset, height: finalHeight) - self.view.backgroundColor = .green + self.view.backgroundColor = .yellow + Logger.common(message: "SnackbarViewController setViewFrame function finished.") } override func setupEdgeConstraint(with height: CGFloat) { + Logger.common(message: "SnackbarViewController setupEdgeConstraint function started.") if #available(iOS 11.0, *) { + Logger.common(message: "SnackbarViewController setupEdgeConstraint iOS 11+.") edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: height) } else { + Logger.common(message: "SnackbarViewController setupEdgeConstraint iOS 10.") edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: height) } edgeConstraint?.isActive = true + Logger.common(message: "SnackbarViewController setupEdgeConstraint function finished.") } } diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift index 3381b6a0..e2ff5082 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift @@ -8,6 +8,7 @@ import Foundation import UIKit +import MindboxLogger class SnackbarViewFactory: ViewFactoryProtocol { @@ -20,18 +21,23 @@ class SnackbarViewFactory: ViewFactoryProtocol { let snackbarView = SnackbarView(onClose: onClose) switch gravity { case .top: + Logger.common(message: "SnackbarViewFactory TopSnackbarViewController handleSwipeGesture created.") snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) case .bottom: + Logger.common(message: "SnackbarViewFactory BottomSnackbarViewController handleSwipeGesture created.") snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) default: + Logger.common(message: "SnackbarViewFactory controller is nil.") return nil } self.viewController = snackbarViewController + return viewController } } - + + Logger.common(message: "SnackbarViewFactory create returns nil.") return nil } } From e8051a2cb2797f58b5e1b59da16bf673831a5710 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Wed, 4 Oct 2023 16:11:53 +0600 Subject: [PATCH 04/10] MBX-0000 Custom window --- .../PresentationDisplayUseCase.swift | 7 +- .../Strategy/ModalPresentationStrategy.swift | 10 +- .../PresentationStrategyProtocol.swift | 3 + .../SnackbarPresentationStrategy.swift | 128 ++++++++++++++++-- 4 files changed, 131 insertions(+), 17 deletions(-) diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift index 7643e118..9dc2ef69 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift @@ -16,7 +16,7 @@ final class PresentationDisplayUseCase { private var model: InAppFormData? private var factory: ViewFactoryProtocol? private var tracker: InAppMessagesTrackerProtocol - + init(tracker: InAppMessagesTrackerProtocol) { self.tracker = tracker } @@ -52,6 +52,11 @@ final class PresentationDisplayUseCase { Logger.common(message: "PresentationDisplayUseCase viewController: \(viewController)") presentedVC = viewController + + if let image = model.imagesDict[model.firstImageValue] { + presentationStrategy?.setupWindowFrame(model: model.content, imageSize: image.size) + } + presentationStrategy?.present(id: model.inAppId, in: window, using: viewController) } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift index c92fa2be..9be1ec5e 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift @@ -10,7 +10,7 @@ import UIKit import MindboxLogger final class ModalPresentationStrategy: PresentationStrategyProtocol { - var inappWindow: UIWindow? + var window: UIWindow? func getWindow() -> UIWindow? { return makeInAppMessageWindow() @@ -28,6 +28,10 @@ final class ModalPresentationStrategy: PresentationStrategyProtocol { Logger.common(message: "In-app modal presentation dismissed", level: .debug, category: .inAppMessages) } + func setupWindowFrame(model: MindboxFormVariant, imageSize: CGSize) { + // Not need to setup. + } + private func makeInAppMessageWindow() -> UIWindow? { let window: UIWindow? if #available(iOS 13.0, *) { @@ -35,8 +39,8 @@ final class ModalPresentationStrategy: PresentationStrategyProtocol { } else { window = UIWindow(frame: UIScreen.main.bounds) } - self.inappWindow = window - window?.windowLevel = UIWindow.Level.normal + self.window = window + window?.windowLevel = .alert window?.isHidden = false return window } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift index b7621250..806b8424 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift @@ -9,7 +9,10 @@ import UIKit protocol PresentationStrategyProtocol { + var window: UIWindow? { get set } + func getWindow() -> UIWindow? func present(id: String, in window: UIWindow, using viewController: UIViewController) func dismiss(viewController: UIViewController) + func setupWindowFrame(model: MindboxFormVariant, imageSize: CGSize) } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift index e1cdefcf..f1905844 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift @@ -10,22 +10,40 @@ import UIKit import MindboxLogger final class SnackbarPresentationStrategy: PresentationStrategyProtocol { + + enum Constants { + static let oneThirdScreenHeight: CGFloat = UIScreen.main.bounds.height / 3.0 + } + + var window: UIWindow? + func getWindow() -> UIWindow? { + let window: UIWindow + let screenBounds = UIScreen.main.bounds + let windowFrame = CGRect(x: 0, y: 0, width: screenBounds.width, height: screenBounds.height) Logger.common(message: "SnackbarPresentationStrategy getWindow started.") if #available(iOS 13, *) { - let window = UIApplication.shared.connectedScenes - .filter { $0.activationState == .foregroundActive } - .compactMap { $0 as? UIWindowScene } - .first?.windows - .first(where: { $0.isKeyWindow }) - - Logger.common(message: "SnackbarPresentationStrategy window iOS 13+: \(window).") - return window + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { + window = UIWindow(windowScene: windowScene) + } else { + window = UIWindow(frame: UIScreen.main.bounds) + } } else { - let window = UIApplication.shared.keyWindow - Logger.common(message: "SnackbarPresentationStrategy window iOS 12 or less: \(window).") - return window + window = UIWindow(frame: UIScreen.main.bounds) } + + window.frame = windowFrame + window.backgroundColor = .clear + window.windowLevel = .alert + let viewController = UIViewController() + window.rootViewController = viewController + viewController.view.frame = windowFrame + viewController.view.layer.borderWidth = 2.0 + viewController.view.layer.borderColor = UIColor.green.cgColor + + window.isHidden = false + self.window = window + return window } func present(id: String, in window: UIWindow, using viewController: UIViewController) { @@ -35,8 +53,20 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { Logger.common(message: "SnackbarPresentationStrategy topController equal = \(topController).") } + viewController.view.frame = topController.view.frame + topController.addChild(viewController) topController.view.addSubview(viewController.view) - Logger.common(message: "In-app with id \(id) presented", level: .info, category: .inAppMessages) + + viewController.view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + viewController.view.topAnchor.constraint(equalTo: topController.view.topAnchor), + viewController.view.bottomAnchor.constraint(equalTo: topController.view.bottomAnchor), + viewController.view.leadingAnchor.constraint(equalTo: topController.view.leadingAnchor), + viewController.view.trailingAnchor.constraint(equalTo: topController.view.trailingAnchor) + ]) + + viewController.didMove(toParent: topController) + Logger.common(message: "In-app snackbar with id \(id) presented", level: .info, category: .inAppMessages) } else { Logger.common(message: "Unable to get top controller. Abort.", level: .error, category: .inAppMessages) } @@ -45,6 +75,78 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { func dismiss(viewController: UIViewController) { viewController.view.removeFromSuperview() viewController.removeFromParent() - Logger.common(message: "InApp presentation dismissed", level: .debug, category: .inAppMessages) + Logger.common(message: "In-app snackbar presentation dismissed", level: .debug, category: .inAppMessages) + } + + func setupWindowFrame(model: MindboxFormVariant, imageSize: CGSize) { + switch model { + case .snackbar(let snackbarFormVariant): + if let gravity = snackbarFormVariant.content.position?.gravity?.element?.vertical { + let leftOffset = snackbarFormVariant.content.position?.margin?.element?.left ?? 0 + let rightOffset = snackbarFormVariant.content.position?.margin?.element?.right ?? 0 + let width = UIScreen.main.bounds.width - leftOffset - rightOffset + let heightMultiplier = width / imageSize.width + let imageHeight = imageSize.height * heightMultiplier + let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight +// setWindowFrame(x: leftOffset, gravity: gravity, finalHeight: finalHeight, width: width) + + + let safeAreaInset = getSafeAreaInset(gravity: gravity) + let y = getYPosition(gravity: gravity, finalHeight: finalHeight, safeAreaInset: safeAreaInset) + + let superFinalWidth = width - leftOffset - rightOffset + let asd = superFinalWidth / imageSize.width + let superImageHeight = imageSize.height * asd + let superFinalHeight = (superImageHeight < Constants.oneThirdScreenHeight) ? superImageHeight : Constants.oneThirdScreenHeight + + self.window?.frame = CGRect(x: leftOffset, y: y, width: width, height: superFinalHeight) + } + default: + break + } + } +} + +private extension SnackbarPresentationStrategy { + func getSafeAreaInset(gravity: ContentPositionGravity.VerticalType) -> CGFloat { + var safeAreaInset: CGFloat = 0 + if #available(iOS 11, *) { + if gravity == .bottom { + safeAreaInset = window?.safeAreaInsets.bottom ?? 0 + } else if gravity == .top { + safeAreaInset = window?.safeAreaInsets.top ?? 0 + } + } + + return safeAreaInset } + + func getYPosition(gravity: ContentPositionGravity.VerticalType, finalHeight: CGFloat, safeAreaInset: CGFloat) -> CGFloat { + var y = UIScreen.main.bounds.height - finalHeight + if gravity == .bottom { + y = UIScreen.main.bounds.height - finalHeight - safeAreaInset + } else if gravity == .top { + y = 0 + } + + return y + } + +// func setWindowFrame(x: CGFloat, gravity: ContentPositionGravity.VerticalType, imageSize: CGSize, width: CGFloat) { +// guard let window = window else { +// Logger.common(message: "Unable to get window in getWindowFrame func. Abort.", level: .error, category: .inAppMessages) +// return +// } +// +// let newWidth = width - rightOffset - +// let heightMultiplier = newWidth / imageSize.width +// let imageHeight = imageSize.height * heightMultiplier +// let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight +// +// +// let safeAreaInset = getSafeAreaInset(gravity: gravity) +// let y = getYPosition(gravity: gravity, finalHeight: finalHeight, safeAreaInset: safeAreaInset) +// +// window.frame = CGRect(x: x, y: y, width: width, height: finalHeight) +// } } From b4c9993b8e9a4ddb2a906c709b3be19a914f0e44 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Thu, 5 Oct 2023 02:23:51 +0600 Subject: [PATCH 05/10] MBX-0000 Snackbar Custom Window --- .../PresentationDisplayUseCase.swift | 6 +-- .../SnackbarPresentationStrategy.swift | 37 ++----------------- .../CommonViews/InAppImageOnlyView.swift | 1 - .../Views/ModalView/ModalViewController.swift | 4 ++ .../Views/SnackbarView/SnackbarView.swift | 4 -- .../SnackbarView/SnackbarViewController.swift | 36 +----------------- .../ViewFactory/SnackbarViewFactory.swift | 2 - 7 files changed, 10 insertions(+), 80 deletions(-) diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift index 9dc2ef69..165416fd 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift @@ -26,7 +26,7 @@ final class PresentationDisplayUseCase { changeType(model: model.content) guard let window = presentationStrategy?.getWindow() else { - Logger.common(message: "In-app modal window creating failed") + Logger.common(message: "In-app window creating failed") return } @@ -37,8 +37,6 @@ final class PresentationDisplayUseCase { return } - Logger.common(message: "PresentationDisplayUseCase factory: \(factory)", level: .error) - guard let viewController = factory.create(model: model.content, id: model.inAppId, imagesDict: model.imagesDict, @@ -49,8 +47,6 @@ final class PresentationDisplayUseCase { return } - Logger.common(message: "PresentationDisplayUseCase viewController: \(viewController)") - presentedVC = viewController if let image = model.imagesDict[model.firstImageValue] { diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift index f1905844..8118c95b 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift @@ -34,13 +34,10 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { window.frame = windowFrame window.backgroundColor = .clear - window.windowLevel = .alert + window.windowLevel = .normal + 3 let viewController = UIViewController() window.rootViewController = viewController viewController.view.frame = windowFrame - viewController.view.layer.borderWidth = 2.0 - viewController.view.layer.borderColor = UIColor.green.cgColor - window.isHidden = false self.window = window return window @@ -50,7 +47,6 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { if var topController = window.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController - Logger.common(message: "SnackbarPresentationStrategy topController equal = \(topController).") } viewController.view.frame = topController.view.frame @@ -88,18 +84,9 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { let heightMultiplier = width / imageSize.width let imageHeight = imageSize.height * heightMultiplier let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight -// setWindowFrame(x: leftOffset, gravity: gravity, finalHeight: finalHeight, width: width) - - let safeAreaInset = getSafeAreaInset(gravity: gravity) let y = getYPosition(gravity: gravity, finalHeight: finalHeight, safeAreaInset: safeAreaInset) - - let superFinalWidth = width - leftOffset - rightOffset - let asd = superFinalWidth / imageSize.width - let superImageHeight = imageSize.height * asd - let superFinalHeight = (superImageHeight < Constants.oneThirdScreenHeight) ? superImageHeight : Constants.oneThirdScreenHeight - - self.window?.frame = CGRect(x: leftOffset, y: y, width: width, height: superFinalHeight) + self.window?.frame = CGRect(x: leftOffset, y: y, width: width, height: finalHeight) } default: break @@ -126,27 +113,9 @@ private extension SnackbarPresentationStrategy { if gravity == .bottom { y = UIScreen.main.bounds.height - finalHeight - safeAreaInset } else if gravity == .top { - y = 0 + y = safeAreaInset } return y } - -// func setWindowFrame(x: CGFloat, gravity: ContentPositionGravity.VerticalType, imageSize: CGSize, width: CGFloat) { -// guard let window = window else { -// Logger.common(message: "Unable to get window in getWindowFrame func. Abort.", level: .error, category: .inAppMessages) -// return -// } -// -// let newWidth = width - rightOffset - -// let heightMultiplier = newWidth / imageSize.width -// let imageHeight = imageSize.height * heightMultiplier -// let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight -// -// -// let safeAreaInset = getSafeAreaInset(gravity: gravity) -// let y = getYPosition(gravity: gravity, finalHeight: finalHeight, safeAreaInset: safeAreaInset) -// -// window.frame = CGRect(x: x, y: y, width: width, height: finalHeight) -// } } diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift index 34b82e8d..d991fa97 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift @@ -38,7 +38,6 @@ final class InAppImageOnlyView: UIView { imageView.contentMode = .scaleAspectFill imageView.image = image - imageView.layer.opacity = 0.5 imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] addSubview(imageView) diff --git a/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift b/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift index a6e29f51..bf036888 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift @@ -71,6 +71,10 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() + elements.forEach({ + $0.removeFromSuperview() + }) + setupElements() } diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift index 27609516..93bd7aab 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift @@ -64,7 +64,6 @@ class SnackbarView: UIView { private func handleSwipeGesture(translation: CGPoint) { if (swipeDirection == .up && translation.y < 0) || (swipeDirection == .down && translation.y > 0) { self.transform = CGAffineTransform(translationX: 0, y: translation.y) - Logger.common(message: "SnackbarView handleSwipeGesture.") } } @@ -74,12 +73,10 @@ class SnackbarView: UIView { if ((swipeDirection == .up && translation.y < 0) || (swipeDirection == .down && translation.y > 0)) && abs(translation.y) > threshold { animateHide(completion: onClose, animated: true) - Logger.common(message: "SnackbarView finalizeGesture.") } else { UIView.animate(withDuration: animationTime) { self.transform = .identity - Logger.common(message: "SnackbarView finalizeGesture fallback.") } } } @@ -108,7 +105,6 @@ class SnackbarView: UIView { yOffset = 0 } self.transform = CGAffineTransform(translationX: 0, y: yOffset) - Logger.common(message: "SnackbarView setHiddenTransform yOffset: \(yOffset).") } public func hide(animated: Bool = true, completion: (() -> Void)? = nil) { diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift index 4072b84f..49d61a27 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift @@ -10,7 +10,6 @@ import UIKit import MindboxLogger class SnackbarViewController: UIViewController, InappViewControllerProtocol { - var edgeConstraint: NSLayoutConstraint? let model: SnackbarFormVariant @@ -78,48 +77,37 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { view.isUserInteractionEnabled = true snackbarView.translatesAutoresizingMaskIntoConstraints = false snackbarView.isUserInteractionEnabled = true - snackbarView.backgroundColor = .blue - Logger.common(message: "SnackbarViewController viewDidLoad.") } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() - Logger.common(message: "SnackbarViewController flag hasSetupLayers: \(hasSetupLayers).") if !hasSetupLayers { hasSetupLayers = true setupConstraints() setupLayers() - Logger.common(message: "SnackbarViewController we're in !hasSetupLayers condition.") if snackbarView.bounds.size != .zero { - Logger.common(message: "SnackbarViewController we're in !snackbarView.bound.size != zero condition.") setupElements() hasSetupElements = true } } else if !hasSetupElements && snackbarView.bounds.size != .zero { - Logger.common(message: "SnackbarViewController we're in !hasSetupElements && snackbarView.bounds.size != .zero condition.") UIView.performWithoutAnimation { setupElements() hasSetupElements = true view.layoutIfNeeded() } } - - Logger.common(message: "SnackbarViewController viewDidLayoutSubviews done.") } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) animateConstraints(withDuration: Constants.animationDuration) onPresented() - Logger.common(message: "SnackbarViewController viewDidAppear.") } private func setupLayers() { - Logger.common(message: "SnackbarViewController setupLayers function started.") let layers = model.content.background.layers.elements - - Logger.common(message: "SnackbarViewController layers: \(layers.count).") + for layer in layers { if let factory = layersFactories[layer.layerType] { if case .image(let imageContentBackgroundLayer) = layer { @@ -129,20 +117,11 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { self.layers.append(layerView) snackbarView.addSubview(layerView) factory.setupConstraintsSnackbar(for: layerView, in: snackbarView) - } else { - Logger.common(message: "SnackbarViewController layer view does not exists.") } - } else { - Logger.common(message: "SnackbarViewController imageContentBackgroundLayer source or value does not exists.\n[Layer]: \(imageContentBackgroundLayer)\n[Dict]: \(imagesDict)") } - } else { - Logger.common(message: "SnackbarViewController not image type of layer.") } - } else { - Logger.common(message: "SnackbarViewController layersFactory does not exists.") } } - Logger.common(message: "SnackbarViewController setupLayers function finished.") } private func setupElements() { @@ -168,25 +147,21 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private func animateConstraints(withDuration duration: TimeInterval) { - Logger.common(message: "SnackbarViewController animateConstraints function started.") view.layoutIfNeeded() UIView.animate(withDuration: duration) { self.edgeConstraint?.constant = 0 - Logger.common(message: "SnackbarViewController animateConstraints UIView.animate condition.") self.view.layoutIfNeeded() } - Logger.common(message: "SnackbarViewController animateConstraints function finished.") } func setupConstraints() { - Logger.common(message: "SnackbarViewController setupConstraints function started.") guard let image = imagesDict[firstImageValue] else { Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } - let width = view.layer.frame.width - leftOffset - rightOffset + let width = view.layer.frame.width let heightMultiplier = width / image.size.width let imageHeight = image.size.height * heightMultiplier let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight @@ -198,8 +173,6 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { setupLayoutConstraints(with: finalHeight) setupEdgeConstraint(with: finalHeight) - - Logger.common(message: "SnackbarViewController setupConstraints function finished.") } func setViewFrame(with height: CGFloat) { @@ -207,7 +180,6 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } func setupLayoutConstraints(with height: CGFloat) { - Logger.common(message: "SnackbarViewController setupLayoutConstraints function started.") if #available(iOS 11.0, *) { Logger.common(message: "SnackbarViewController setupLayoutConstraints iOS 11+.") NSLayoutConstraint.activate([ @@ -223,7 +195,6 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { snackbarView.heightAnchor.constraint(equalToConstant: height), ]) } - Logger.common(message: "SnackbarViewController setupLayoutConstraints function finished.") } func setupEdgeConstraint(with height: CGFloat) { @@ -303,12 +274,10 @@ class BottomSnackbarViewController: SnackbarViewController { self.view.frame = CGRect(x: leftOffset, y: screenHeight - finalHeight, width: UIScreen.main.bounds.width - leftOffset - rightOffset, height: finalHeight) - self.view.backgroundColor = .yellow Logger.common(message: "SnackbarViewController setViewFrame function finished.") } override func setupEdgeConstraint(with height: CGFloat) { - Logger.common(message: "SnackbarViewController setupEdgeConstraint function started.") if #available(iOS 11.0, *) { Logger.common(message: "SnackbarViewController setupEdgeConstraint iOS 11+.") edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: height) @@ -318,6 +287,5 @@ class BottomSnackbarViewController: SnackbarViewController { } edgeConstraint?.isActive = true - Logger.common(message: "SnackbarViewController setupEdgeConstraint function finished.") } } diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift index e2ff5082..f9a4ce58 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift @@ -21,10 +21,8 @@ class SnackbarViewFactory: ViewFactoryProtocol { let snackbarView = SnackbarView(onClose: onClose) switch gravity { case .top: - Logger.common(message: "SnackbarViewFactory TopSnackbarViewController handleSwipeGesture created.") snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) case .bottom: - Logger.common(message: "SnackbarViewFactory BottomSnackbarViewController handleSwipeGesture created.") snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) default: Logger.common(message: "SnackbarViewFactory controller is nil.") From 103b91e63b15add4e7f1a0835b4d40c096c60db7 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Wed, 20 Sep 2023 16:07:08 +0600 Subject: [PATCH 06/10] MBX-0000 New way --- .../SnackbarPresentationStrategy.swift | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift index 2360e009..1b0c0fb8 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift @@ -11,13 +11,28 @@ import MindboxLogger final class SnackbarPresentationStrategy: PresentationStrategyProtocol { func getWindow() -> UIWindow? { - return UIApplication.shared.windows.first(where: { $0.isKeyWindow }) + if #available(iOS 13, *) { + return UIApplication.shared.connectedScenes + .filter { $0.activationState == .foregroundActive } + .compactMap { $0 as? UIWindowScene } + .first?.windows + .first(where: { $0.isKeyWindow }) + } else { + return UIApplication.shared.keyWindow + } } - + func present(id: String, in window: UIWindow, using viewController: UIViewController) { - window.rootViewController?.addChild(viewController) - window.rootViewController?.view.addSubview(viewController.view) - Logger.common(message: "In-app with id \(id) presented", level: .info, category: .inAppMessages) + if var topController = window.rootViewController { + while let presentedViewController = topController.presentedViewController { + topController = presentedViewController + } + + topController.view.addSubview(viewController.view) + Logger.common(message: "In-app with id \(id) presented", level: .info, category: .inAppMessages) + } else { + Logger.common(message: "Unable to get top controller. Abort.", level: .error, category: .inAppMessages) + } } func dismiss(viewController: UIViewController) { From 670a3d03c37dcf1262e9838b525bbb7ca3523aaf Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Tue, 26 Sep 2023 13:01:37 +0600 Subject: [PATCH 07/10] MBX-0000 New way 2 --- .../SnackbarView/SnackbarViewController.swift | 54 ++++++++----------- .../ViewFactory/SnackbarViewFactory.swift | 5 +- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift index 9e2e189d..fa763f79 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift @@ -11,7 +11,7 @@ import MindboxLogger class SnackbarViewController: UIViewController, InappViewControllerProtocol { - var snackbarView: SnackbarView? + var edgeConstraint: NSLayoutConstraint? let model: SnackbarFormVariant @@ -35,9 +35,9 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private let imagesDict: [String: UIImage] + let snackbarView: SnackbarView private let firstImageValue: String private let onPresented: () -> Void - private let onClose: () -> Void private let onTapAction: (ContentBackgroundLayerAction?) -> Void private var hasSetupLayers = false @@ -52,16 +52,16 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { init( model: SnackbarFormVariant, imagesDict: [String: UIImage], + snackbarView: SnackbarView, firstImageValue: String, onPresented: @escaping () -> Void, - onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, - onClose: @escaping () -> Void + onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void ) { self.model = model self.imagesDict = imagesDict + self.snackbarView = snackbarView self.firstImageValue = firstImageValue self.onPresented = onPresented - self.onClose = onClose self.onTapAction = onTapAction super.init(nibName: nil, bundle: nil) } @@ -73,12 +73,9 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { override func viewDidLoad() { super.viewDidLoad() view.isUserInteractionEnabled = true - snackbarView = SnackbarView(onClose: onClose) - if let snackbarView = snackbarView { - snackbarView.translatesAutoresizingMaskIntoConstraints = false - snackbarView.isUserInteractionEnabled = true - view.addSubview(snackbarView) - } + snackbarView.translatesAutoresizingMaskIntoConstraints = false + snackbarView.isUserInteractionEnabled = true + view.addSubview(snackbarView) } override func viewDidLayoutSubviews() { @@ -88,11 +85,11 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { setupConstraints() setupLayers() - if snackbarView?.bounds.size != .zero { + if snackbarView.bounds.size != .zero { setupElements() hasSetupElements = true } - } else if !hasSetupElements && snackbarView?.bounds.size != .zero { + } else if !hasSetupElements && snackbarView.bounds.size != .zero { UIView.performWithoutAnimation { setupElements() hasSetupElements = true @@ -108,11 +105,8 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private func setupLayers() { - let layers = model.content.background.layers - guard let snackbarView = snackbarView else { - return - } - + let layers = model.content.background.layers.elements + for layer in layers { if let factory = layersFactories[layer.layerType] { if case .image(let imageContentBackgroundLayer) = layer { @@ -130,7 +124,8 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private func setupElements() { - guard let snackbarView = snackbarView else { + guard let elements = model.content.elements?.elements else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } @@ -161,6 +156,7 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { func setupConstraints() { guard let image = imagesDict[firstImageValue] else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } @@ -170,9 +166,6 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight setViewFrame(with: finalHeight) - guard let snackbarView = snackbarView else { - return - } snackbarView.swipeDirection = swipeDirection snackbarView.translatesAutoresizingMaskIntoConstraints = false @@ -186,10 +179,6 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } func setupLayoutConstraints(with height: CGFloat) { - guard let snackbarView = snackbarView else { - return - } - if #available(iOS 11.0, *) { NSLayoutConstraint.activate([ snackbarView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), @@ -213,6 +202,7 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { extension SnackbarViewController: GestureHandler { @objc func imageTapped(_ sender: UITapGestureRecognizer) { guard let imageView = sender.view as? InAppImageOnlyView else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } @@ -222,13 +212,14 @@ extension SnackbarViewController: GestureHandler { @objc func onCloseButton(_ gesture: UILongPressGestureRecognizer) { guard let crossView = gesture.view else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } let location = gesture.location(in: crossView) let isInsideCrossView = crossView.bounds.contains(location) if gesture.state == .ended && isInsideCrossView { - snackbarView?.hide() + snackbarView.hide() } } } @@ -253,9 +244,9 @@ class TopSnackbarViewController: SnackbarViewController { override func setupEdgeConstraint(with height: CGFloat) { if #available(iOS 11.0, *) { - edgeConstraint = snackbarView?.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: -height) + edgeConstraint = snackbarView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: -height) } else { - edgeConstraint = snackbarView?.topAnchor.constraint(equalTo: view.topAnchor, constant: -height) + edgeConstraint = snackbarView.topAnchor.constraint(equalTo: view.topAnchor, constant: -height) } edgeConstraint?.isActive = true @@ -280,13 +271,14 @@ class BottomSnackbarViewController: SnackbarViewController { self.view.frame = CGRect(x: leftOffset, y: screenHeight - finalHeight, width: UIScreen.main.bounds.width - leftOffset - rightOffset, height: finalHeight) + self.view.backgroundColor = .green } override func setupEdgeConstraint(with height: CGFloat) { if #available(iOS 11.0, *) { - edgeConstraint = snackbarView?.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: height) + edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: height) } else { - edgeConstraint = snackbarView?.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: height) + edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: height) } edgeConstraint?.isActive = true diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift index 2750ca6c..160ad94e 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift @@ -17,11 +17,12 @@ class SnackbarViewFactory: ViewFactoryProtocol { if case .snackbar(let snackbarFormVariant) = model { if let gravity = snackbarFormVariant.content.position.gravity?.vertical { var snackbarViewController: UIViewController? + let snackbarView = SnackbarView(onClose: onClose) switch gravity { case .top: - snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) + snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) case .bottom: - snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) + snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) default: return nil } From 6a5363ddcb7d5aa27694f2aff6498578080670fc Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Wed, 27 Sep 2023 13:43:11 +0600 Subject: [PATCH 08/10] MBX-0000 New way 3 --- Mindbox/CoreController/CoreController.swift | 1 + .../PresentationDisplayUseCase.swift | 6 +++ .../SnackbarPresentationStrategy.swift | 11 ++++- .../CommonViews/InAppImageOnlyView.swift | 5 +++ .../ImageLayer/ImageLayerFactory.swift | 7 +++- .../Views/SnackbarView/SnackbarView.swift | 9 +++- .../SnackbarView/SnackbarViewController.swift | 41 ++++++++++++++++++- .../ViewFactory/SnackbarViewFactory.swift | 8 +++- 8 files changed, 80 insertions(+), 8 deletions(-) diff --git a/Mindbox/CoreController/CoreController.swift b/Mindbox/CoreController/CoreController.swift index 3b2aeb63..5658c53f 100644 --- a/Mindbox/CoreController/CoreController.swift +++ b/Mindbox/CoreController/CoreController.swift @@ -37,6 +37,7 @@ class CoreController { self.inAppMessagesManager.start() } + Logger.common(message: "New way 3 test commit!", level: .info, category: .general) Logger.common(message: "[Configuration]: \(configuration)", level: .info, category: .general) Logger.common(message: "[SDK Version]: \(self.utilitiesFetcher.sdkVersion ?? "null")", level: .info, category: .general) Logger.common(message: "[APNS Token]: \(self.persistenceStorage.apnsToken ?? "null")", level: .info, category: .general) diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift index 62301b96..7643e118 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift @@ -30,11 +30,15 @@ final class PresentationDisplayUseCase { return } + Logger.common(message: "PresentationDisplayUseCase window: \(window)") + guard let factory = self.factory else { Logger.common(message: "Factory does not exists.", level: .error, category: .general) return } + Logger.common(message: "PresentationDisplayUseCase factory: \(factory)", level: .error) + guard let viewController = factory.create(model: model.content, id: model.inAppId, imagesDict: model.imagesDict, @@ -45,6 +49,8 @@ final class PresentationDisplayUseCase { return } + Logger.common(message: "PresentationDisplayUseCase viewController: \(viewController)") + presentedVC = viewController presentationStrategy?.present(id: model.inAppId, in: window, using: viewController) } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift index 1b0c0fb8..e1cdefcf 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift @@ -11,14 +11,20 @@ import MindboxLogger final class SnackbarPresentationStrategy: PresentationStrategyProtocol { func getWindow() -> UIWindow? { + Logger.common(message: "SnackbarPresentationStrategy getWindow started.") if #available(iOS 13, *) { - return UIApplication.shared.connectedScenes + let window = UIApplication.shared.connectedScenes .filter { $0.activationState == .foregroundActive } .compactMap { $0 as? UIWindowScene } .first?.windows .first(where: { $0.isKeyWindow }) + + Logger.common(message: "SnackbarPresentationStrategy window iOS 13+: \(window).") + return window } else { - return UIApplication.shared.keyWindow + let window = UIApplication.shared.keyWindow + Logger.common(message: "SnackbarPresentationStrategy window iOS 12 or less: \(window).") + return window } } @@ -26,6 +32,7 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { if var topController = window.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController + Logger.common(message: "SnackbarPresentationStrategy topController equal = \(topController).") } topController.view.addSubview(viewController.view) diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift index f8e008af..34b82e8d 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift @@ -6,6 +6,7 @@ // import UIKit +import MindboxLogger final class InAppImageOnlyView: UIView { var onClose: (() -> Void)? @@ -29,11 +30,15 @@ final class InAppImageOnlyView: UIView { func customInit() { guard let image = image else { + Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } + Logger.common(message: "InAppImageOnlyView custom init started.") + imageView.contentMode = .scaleAspectFill imageView.image = image + imageView.layer.opacity = 0.5 imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] addSubview(imageView) diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift index e185019a..eda52d9d 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/LayersFactory/ImageLayer/ImageLayerFactory.swift @@ -7,6 +7,7 @@ // import UIKit +import MindboxLogger class ImageLayerFactory: LayerFactory { func create(from image: UIImage, layer: ContentBackgroundLayer, in view: UIView, with controller: GestureHandler) -> UIView? { @@ -14,10 +15,11 @@ class ImageLayerFactory: LayerFactory { let inAppView = InAppImageOnlyView(image: image, action: imageContentBackgroundLayer.action) let imageTapGestureRecognizer = UITapGestureRecognizer(target: controller, action: #selector(controller.imageTapped(_:))) inAppView.addGestureRecognizer(imageTapGestureRecognizer) - + Logger.common(message: "ImageLayerFactory return uiView.") return inAppView } - + + Logger.common(message: "ImageLayerFactory return nil.") return nil } @@ -39,5 +41,6 @@ class ImageLayerFactory: LayerFactory { view.leadingAnchor.constraint(equalTo: parentView.leadingAnchor), view.trailingAnchor.constraint(equalTo: parentView.trailingAnchor) ]) + Logger.common(message: "ImageLayerFactory setupConstraintsSnackbar finished.") } } diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift index 486f7b32..27609516 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift @@ -6,6 +6,7 @@ // import UIKit +import MindboxLogger class SnackbarView: UIView { @@ -39,7 +40,7 @@ class SnackbarView: UIView { self.onClose = onClose self.animationTime = animationTime super.init(frame: .zero) - + Logger.common(message: "SnackbarView inited.") setupPanGesture() } @@ -63,6 +64,7 @@ class SnackbarView: UIView { private func handleSwipeGesture(translation: CGPoint) { if (swipeDirection == .up && translation.y < 0) || (swipeDirection == .down && translation.y > 0) { self.transform = CGAffineTransform(translationX: 0, y: translation.y) + Logger.common(message: "SnackbarView handleSwipeGesture.") } } @@ -72,9 +74,12 @@ class SnackbarView: UIView { if ((swipeDirection == .up && translation.y < 0) || (swipeDirection == .down && translation.y > 0)) && abs(translation.y) > threshold { animateHide(completion: onClose, animated: true) + Logger.common(message: "SnackbarView finalizeGesture.") + } else { UIView.animate(withDuration: animationTime) { self.transform = .identity + Logger.common(message: "SnackbarView finalizeGesture fallback.") } } } @@ -103,6 +108,7 @@ class SnackbarView: UIView { yOffset = 0 } self.transform = CGAffineTransform(translationX: 0, y: yOffset) + Logger.common(message: "SnackbarView setHiddenTransform yOffset: \(yOffset).") } public func hide(animated: Bool = true, completion: (() -> Void)? = nil) { @@ -113,6 +119,7 @@ class SnackbarView: UIView { } required init?(coder: NSCoder) { + Logger.common(message: "SnackbarView init(coder:) has not been implemented.") fatalError("init(coder:) has not been implemented") } } diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift index fa763f79..5d8fcbeb 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift @@ -64,49 +64,62 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { self.onPresented = onPresented self.onTapAction = onTapAction super.init(nibName: nil, bundle: nil) + Logger.common(message: "SnackbarViewController inited.") } required init?(coder: NSCoder) { + Logger.common(message: "SnackbarViewController init(coder:) has not been implemented.") fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() + view.addSubview(snackbarView) view.isUserInteractionEnabled = true snackbarView.translatesAutoresizingMaskIntoConstraints = false snackbarView.isUserInteractionEnabled = true - view.addSubview(snackbarView) + snackbarView.backgroundColor = .blue + Logger.common(message: "SnackbarViewController viewDidLoad.") } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() + Logger.common(message: "SnackbarViewController flag hasSetupLayers: \(hasSetupLayers).") if !hasSetupLayers { hasSetupLayers = true setupConstraints() setupLayers() + Logger.common(message: "SnackbarViewController we're in !hasSetupLayers condition.") if snackbarView.bounds.size != .zero { + Logger.common(message: "SnackbarViewController we're in !snackbarView.bound.size != zero condition.") setupElements() hasSetupElements = true } } else if !hasSetupElements && snackbarView.bounds.size != .zero { + Logger.common(message: "SnackbarViewController we're in !hasSetupElements && snackbarView.bounds.size != .zero condition.") UIView.performWithoutAnimation { setupElements() hasSetupElements = true view.layoutIfNeeded() } } + + Logger.common(message: "SnackbarViewController viewDidLayoutSubviews done.") } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) animateConstraints(withDuration: Constants.animationDuration) onPresented() + Logger.common(message: "SnackbarViewController viewDidAppear.") } private func setupLayers() { + Logger.common(message: "SnackbarViewController setupLayers function started.") let layers = model.content.background.layers.elements + Logger.common(message: "SnackbarViewController layers: \(layers.count).") for layer in layers { if let factory = layersFactories[layer.layerType] { if case .image(let imageContentBackgroundLayer) = layer { @@ -116,11 +129,20 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { self.layers.append(layerView) snackbarView.addSubview(layerView) factory.setupConstraintsSnackbar(for: layerView, in: snackbarView) + } else { + Logger.common(message: "SnackbarViewController layer view does not exists.") } + } else { + Logger.common(message: "SnackbarViewController imageContentBackgroundLayer source or value does not exists.\n[Layer]: \(imageContentBackgroundLayer)\n[Dict]: \(imagesDict)") } + } else { + Logger.common(message: "SnackbarViewController not image type of layer.") } + } else { + Logger.common(message: "SnackbarViewController layersFactory does not exists.") } } + Logger.common(message: "SnackbarViewController setupLayers function finished.") } private func setupElements() { @@ -146,15 +168,19 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private func animateConstraints(withDuration duration: TimeInterval) { + Logger.common(message: "SnackbarViewController animateConstraints function started.") view.layoutIfNeeded() UIView.animate(withDuration: duration) { self.edgeConstraint?.constant = 0 + Logger.common(message: "SnackbarViewController animateConstraints UIView.animate condition.") self.view.layoutIfNeeded() } + Logger.common(message: "SnackbarViewController animateConstraints function finished.") } func setupConstraints() { + Logger.common(message: "SnackbarViewController setupConstraints function started.") guard let image = imagesDict[firstImageValue] else { Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return @@ -172,6 +198,8 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { setupLayoutConstraints(with: finalHeight) setupEdgeConstraint(with: finalHeight) + + Logger.common(message: "SnackbarViewController setupConstraints function finished.") } func setViewFrame(with height: CGFloat) { @@ -179,19 +207,23 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } func setupLayoutConstraints(with height: CGFloat) { + Logger.common(message: "SnackbarViewController setupLayoutConstraints function started.") if #available(iOS 11.0, *) { + Logger.common(message: "SnackbarViewController setupLayoutConstraints iOS 11+.") NSLayoutConstraint.activate([ snackbarView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), snackbarView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), snackbarView.heightAnchor.constraint(equalToConstant: height), ]) } else { + Logger.common(message: "SnackbarViewController setupLayoutConstraints iOS 10.") NSLayoutConstraint.activate([ snackbarView.leadingAnchor.constraint(equalTo: view.leadingAnchor), snackbarView.trailingAnchor.constraint(equalTo: view.trailingAnchor), snackbarView.heightAnchor.constraint(equalToConstant: height), ]) } + Logger.common(message: "SnackbarViewController setupLayoutConstraints function finished.") } func setupEdgeConstraint(with height: CGFloat) { @@ -271,16 +303,21 @@ class BottomSnackbarViewController: SnackbarViewController { self.view.frame = CGRect(x: leftOffset, y: screenHeight - finalHeight, width: UIScreen.main.bounds.width - leftOffset - rightOffset, height: finalHeight) - self.view.backgroundColor = .green + self.view.backgroundColor = .yellow + Logger.common(message: "SnackbarViewController setViewFrame function finished.") } override func setupEdgeConstraint(with height: CGFloat) { + Logger.common(message: "SnackbarViewController setupEdgeConstraint function started.") if #available(iOS 11.0, *) { + Logger.common(message: "SnackbarViewController setupEdgeConstraint iOS 11+.") edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: height) } else { + Logger.common(message: "SnackbarViewController setupEdgeConstraint iOS 10.") edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: height) } edgeConstraint?.isActive = true + Logger.common(message: "SnackbarViewController setupEdgeConstraint function finished.") } } diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift index 160ad94e..d65b8a72 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift @@ -8,6 +8,7 @@ import Foundation import UIKit +import MindboxLogger class SnackbarViewFactory: ViewFactoryProtocol { @@ -20,18 +21,23 @@ class SnackbarViewFactory: ViewFactoryProtocol { let snackbarView = SnackbarView(onClose: onClose) switch gravity { case .top: + Logger.common(message: "SnackbarViewFactory TopSnackbarViewController handleSwipeGesture created.") snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) case .bottom: + Logger.common(message: "SnackbarViewFactory BottomSnackbarViewController handleSwipeGesture created.") snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) default: + Logger.common(message: "SnackbarViewFactory controller is nil.") return nil } self.viewController = snackbarViewController + return viewController } } - + + Logger.common(message: "SnackbarViewFactory create returns nil.") return nil } } From 3843e35a488c31c9ef7b15dee70d3bab4c24772c Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Wed, 4 Oct 2023 16:11:53 +0600 Subject: [PATCH 09/10] MBX-0000 Custom window --- .../PresentationDisplayUseCase.swift | 7 +- .../Strategy/ModalPresentationStrategy.swift | 10 +- .../PresentationStrategyProtocol.swift | 3 + .../SnackbarPresentationStrategy.swift | 128 ++++++++++++++++-- 4 files changed, 131 insertions(+), 17 deletions(-) diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift index 7643e118..9dc2ef69 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift @@ -16,7 +16,7 @@ final class PresentationDisplayUseCase { private var model: InAppFormData? private var factory: ViewFactoryProtocol? private var tracker: InAppMessagesTrackerProtocol - + init(tracker: InAppMessagesTrackerProtocol) { self.tracker = tracker } @@ -52,6 +52,11 @@ final class PresentationDisplayUseCase { Logger.common(message: "PresentationDisplayUseCase viewController: \(viewController)") presentedVC = viewController + + if let image = model.imagesDict[model.firstImageValue] { + presentationStrategy?.setupWindowFrame(model: model.content, imageSize: image.size) + } + presentationStrategy?.present(id: model.inAppId, in: window, using: viewController) } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift index c92fa2be..9be1ec5e 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/ModalPresentationStrategy.swift @@ -10,7 +10,7 @@ import UIKit import MindboxLogger final class ModalPresentationStrategy: PresentationStrategyProtocol { - var inappWindow: UIWindow? + var window: UIWindow? func getWindow() -> UIWindow? { return makeInAppMessageWindow() @@ -28,6 +28,10 @@ final class ModalPresentationStrategy: PresentationStrategyProtocol { Logger.common(message: "In-app modal presentation dismissed", level: .debug, category: .inAppMessages) } + func setupWindowFrame(model: MindboxFormVariant, imageSize: CGSize) { + // Not need to setup. + } + private func makeInAppMessageWindow() -> UIWindow? { let window: UIWindow? if #available(iOS 13.0, *) { @@ -35,8 +39,8 @@ final class ModalPresentationStrategy: PresentationStrategyProtocol { } else { window = UIWindow(frame: UIScreen.main.bounds) } - self.inappWindow = window - window?.windowLevel = UIWindow.Level.normal + self.window = window + window?.windowLevel = .alert window?.isHidden = false return window } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift index b7621250..806b8424 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/PresentationStrategyProtocol.swift @@ -9,7 +9,10 @@ import UIKit protocol PresentationStrategyProtocol { + var window: UIWindow? { get set } + func getWindow() -> UIWindow? func present(id: String, in window: UIWindow, using viewController: UIViewController) func dismiss(viewController: UIViewController) + func setupWindowFrame(model: MindboxFormVariant, imageSize: CGSize) } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift index e1cdefcf..f1905844 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift @@ -10,22 +10,40 @@ import UIKit import MindboxLogger final class SnackbarPresentationStrategy: PresentationStrategyProtocol { + + enum Constants { + static let oneThirdScreenHeight: CGFloat = UIScreen.main.bounds.height / 3.0 + } + + var window: UIWindow? + func getWindow() -> UIWindow? { + let window: UIWindow + let screenBounds = UIScreen.main.bounds + let windowFrame = CGRect(x: 0, y: 0, width: screenBounds.width, height: screenBounds.height) Logger.common(message: "SnackbarPresentationStrategy getWindow started.") if #available(iOS 13, *) { - let window = UIApplication.shared.connectedScenes - .filter { $0.activationState == .foregroundActive } - .compactMap { $0 as? UIWindowScene } - .first?.windows - .first(where: { $0.isKeyWindow }) - - Logger.common(message: "SnackbarPresentationStrategy window iOS 13+: \(window).") - return window + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { + window = UIWindow(windowScene: windowScene) + } else { + window = UIWindow(frame: UIScreen.main.bounds) + } } else { - let window = UIApplication.shared.keyWindow - Logger.common(message: "SnackbarPresentationStrategy window iOS 12 or less: \(window).") - return window + window = UIWindow(frame: UIScreen.main.bounds) } + + window.frame = windowFrame + window.backgroundColor = .clear + window.windowLevel = .alert + let viewController = UIViewController() + window.rootViewController = viewController + viewController.view.frame = windowFrame + viewController.view.layer.borderWidth = 2.0 + viewController.view.layer.borderColor = UIColor.green.cgColor + + window.isHidden = false + self.window = window + return window } func present(id: String, in window: UIWindow, using viewController: UIViewController) { @@ -35,8 +53,20 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { Logger.common(message: "SnackbarPresentationStrategy topController equal = \(topController).") } + viewController.view.frame = topController.view.frame + topController.addChild(viewController) topController.view.addSubview(viewController.view) - Logger.common(message: "In-app with id \(id) presented", level: .info, category: .inAppMessages) + + viewController.view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + viewController.view.topAnchor.constraint(equalTo: topController.view.topAnchor), + viewController.view.bottomAnchor.constraint(equalTo: topController.view.bottomAnchor), + viewController.view.leadingAnchor.constraint(equalTo: topController.view.leadingAnchor), + viewController.view.trailingAnchor.constraint(equalTo: topController.view.trailingAnchor) + ]) + + viewController.didMove(toParent: topController) + Logger.common(message: "In-app snackbar with id \(id) presented", level: .info, category: .inAppMessages) } else { Logger.common(message: "Unable to get top controller. Abort.", level: .error, category: .inAppMessages) } @@ -45,6 +75,78 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { func dismiss(viewController: UIViewController) { viewController.view.removeFromSuperview() viewController.removeFromParent() - Logger.common(message: "InApp presentation dismissed", level: .debug, category: .inAppMessages) + Logger.common(message: "In-app snackbar presentation dismissed", level: .debug, category: .inAppMessages) + } + + func setupWindowFrame(model: MindboxFormVariant, imageSize: CGSize) { + switch model { + case .snackbar(let snackbarFormVariant): + if let gravity = snackbarFormVariant.content.position?.gravity?.element?.vertical { + let leftOffset = snackbarFormVariant.content.position?.margin?.element?.left ?? 0 + let rightOffset = snackbarFormVariant.content.position?.margin?.element?.right ?? 0 + let width = UIScreen.main.bounds.width - leftOffset - rightOffset + let heightMultiplier = width / imageSize.width + let imageHeight = imageSize.height * heightMultiplier + let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight +// setWindowFrame(x: leftOffset, gravity: gravity, finalHeight: finalHeight, width: width) + + + let safeAreaInset = getSafeAreaInset(gravity: gravity) + let y = getYPosition(gravity: gravity, finalHeight: finalHeight, safeAreaInset: safeAreaInset) + + let superFinalWidth = width - leftOffset - rightOffset + let asd = superFinalWidth / imageSize.width + let superImageHeight = imageSize.height * asd + let superFinalHeight = (superImageHeight < Constants.oneThirdScreenHeight) ? superImageHeight : Constants.oneThirdScreenHeight + + self.window?.frame = CGRect(x: leftOffset, y: y, width: width, height: superFinalHeight) + } + default: + break + } + } +} + +private extension SnackbarPresentationStrategy { + func getSafeAreaInset(gravity: ContentPositionGravity.VerticalType) -> CGFloat { + var safeAreaInset: CGFloat = 0 + if #available(iOS 11, *) { + if gravity == .bottom { + safeAreaInset = window?.safeAreaInsets.bottom ?? 0 + } else if gravity == .top { + safeAreaInset = window?.safeAreaInsets.top ?? 0 + } + } + + return safeAreaInset } + + func getYPosition(gravity: ContentPositionGravity.VerticalType, finalHeight: CGFloat, safeAreaInset: CGFloat) -> CGFloat { + var y = UIScreen.main.bounds.height - finalHeight + if gravity == .bottom { + y = UIScreen.main.bounds.height - finalHeight - safeAreaInset + } else if gravity == .top { + y = 0 + } + + return y + } + +// func setWindowFrame(x: CGFloat, gravity: ContentPositionGravity.VerticalType, imageSize: CGSize, width: CGFloat) { +// guard let window = window else { +// Logger.common(message: "Unable to get window in getWindowFrame func. Abort.", level: .error, category: .inAppMessages) +// return +// } +// +// let newWidth = width - rightOffset - +// let heightMultiplier = newWidth / imageSize.width +// let imageHeight = imageSize.height * heightMultiplier +// let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight +// +// +// let safeAreaInset = getSafeAreaInset(gravity: gravity) +// let y = getYPosition(gravity: gravity, finalHeight: finalHeight, safeAreaInset: safeAreaInset) +// +// window.frame = CGRect(x: x, y: y, width: width, height: finalHeight) +// } } From 74acb1a83bc55d7f00289e7a841f5864a04b7c47 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Thu, 5 Oct 2023 02:23:51 +0600 Subject: [PATCH 10/10] MBX-0000 Snackbar Custom Window --- .../PresentationDisplayUseCase.swift | 6 +-- .../SnackbarPresentationStrategy.swift | 37 ++----------------- .../CommonViews/InAppImageOnlyView.swift | 1 - .../Views/ModalView/ModalViewController.swift | 4 ++ .../Views/SnackbarView/SnackbarView.swift | 4 -- .../SnackbarView/SnackbarViewController.swift | 36 +----------------- .../ViewFactory/SnackbarViewFactory.swift | 2 - 7 files changed, 10 insertions(+), 80 deletions(-) diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift index 9dc2ef69..165416fd 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift @@ -26,7 +26,7 @@ final class PresentationDisplayUseCase { changeType(model: model.content) guard let window = presentationStrategy?.getWindow() else { - Logger.common(message: "In-app modal window creating failed") + Logger.common(message: "In-app window creating failed") return } @@ -37,8 +37,6 @@ final class PresentationDisplayUseCase { return } - Logger.common(message: "PresentationDisplayUseCase factory: \(factory)", level: .error) - guard let viewController = factory.create(model: model.content, id: model.inAppId, imagesDict: model.imagesDict, @@ -49,8 +47,6 @@ final class PresentationDisplayUseCase { return } - Logger.common(message: "PresentationDisplayUseCase viewController: \(viewController)") - presentedVC = viewController if let image = model.imagesDict[model.firstImageValue] { diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift index f1905844..8118c95b 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/Strategy/SnackbarPresentationStrategy.swift @@ -34,13 +34,10 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { window.frame = windowFrame window.backgroundColor = .clear - window.windowLevel = .alert + window.windowLevel = .normal + 3 let viewController = UIViewController() window.rootViewController = viewController viewController.view.frame = windowFrame - viewController.view.layer.borderWidth = 2.0 - viewController.view.layer.borderColor = UIColor.green.cgColor - window.isHidden = false self.window = window return window @@ -50,7 +47,6 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { if var topController = window.rootViewController { while let presentedViewController = topController.presentedViewController { topController = presentedViewController - Logger.common(message: "SnackbarPresentationStrategy topController equal = \(topController).") } viewController.view.frame = topController.view.frame @@ -88,18 +84,9 @@ final class SnackbarPresentationStrategy: PresentationStrategyProtocol { let heightMultiplier = width / imageSize.width let imageHeight = imageSize.height * heightMultiplier let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight -// setWindowFrame(x: leftOffset, gravity: gravity, finalHeight: finalHeight, width: width) - - let safeAreaInset = getSafeAreaInset(gravity: gravity) let y = getYPosition(gravity: gravity, finalHeight: finalHeight, safeAreaInset: safeAreaInset) - - let superFinalWidth = width - leftOffset - rightOffset - let asd = superFinalWidth / imageSize.width - let superImageHeight = imageSize.height * asd - let superFinalHeight = (superImageHeight < Constants.oneThirdScreenHeight) ? superImageHeight : Constants.oneThirdScreenHeight - - self.window?.frame = CGRect(x: leftOffset, y: y, width: width, height: superFinalHeight) + self.window?.frame = CGRect(x: leftOffset, y: y, width: width, height: finalHeight) } default: break @@ -126,27 +113,9 @@ private extension SnackbarPresentationStrategy { if gravity == .bottom { y = UIScreen.main.bounds.height - finalHeight - safeAreaInset } else if gravity == .top { - y = 0 + y = safeAreaInset } return y } - -// func setWindowFrame(x: CGFloat, gravity: ContentPositionGravity.VerticalType, imageSize: CGSize, width: CGFloat) { -// guard let window = window else { -// Logger.common(message: "Unable to get window in getWindowFrame func. Abort.", level: .error, category: .inAppMessages) -// return -// } -// -// let newWidth = width - rightOffset - -// let heightMultiplier = newWidth / imageSize.width -// let imageHeight = imageSize.height * heightMultiplier -// let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight -// -// -// let safeAreaInset = getSafeAreaInset(gravity: gravity) -// let y = getYPosition(gravity: gravity, finalHeight: finalHeight, safeAreaInset: safeAreaInset) -// -// window.frame = CGRect(x: x, y: y, width: width, height: finalHeight) -// } } diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift index 34b82e8d..d991fa97 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/InAppImageOnlyView.swift @@ -38,7 +38,6 @@ final class InAppImageOnlyView: UIView { imageView.contentMode = .scaleAspectFill imageView.image = image - imageView.layer.opacity = 0.5 imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] addSubview(imageView) diff --git a/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift b/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift index 40702691..969b3a78 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift @@ -71,6 +71,10 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() + elements.forEach({ + $0.removeFromSuperview() + }) + setupElements() } diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift index 27609516..93bd7aab 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarView.swift @@ -64,7 +64,6 @@ class SnackbarView: UIView { private func handleSwipeGesture(translation: CGPoint) { if (swipeDirection == .up && translation.y < 0) || (swipeDirection == .down && translation.y > 0) { self.transform = CGAffineTransform(translationX: 0, y: translation.y) - Logger.common(message: "SnackbarView handleSwipeGesture.") } } @@ -74,12 +73,10 @@ class SnackbarView: UIView { if ((swipeDirection == .up && translation.y < 0) || (swipeDirection == .down && translation.y > 0)) && abs(translation.y) > threshold { animateHide(completion: onClose, animated: true) - Logger.common(message: "SnackbarView finalizeGesture.") } else { UIView.animate(withDuration: animationTime) { self.transform = .identity - Logger.common(message: "SnackbarView finalizeGesture fallback.") } } } @@ -108,7 +105,6 @@ class SnackbarView: UIView { yOffset = 0 } self.transform = CGAffineTransform(translationX: 0, y: yOffset) - Logger.common(message: "SnackbarView setHiddenTransform yOffset: \(yOffset).") } public func hide(animated: Bool = true, completion: (() -> Void)? = nil) { diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift index 5d8fcbeb..eec21e8d 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift @@ -10,7 +10,6 @@ import UIKit import MindboxLogger class SnackbarViewController: UIViewController, InappViewControllerProtocol { - var edgeConstraint: NSLayoutConstraint? let model: SnackbarFormVariant @@ -78,48 +77,37 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { view.isUserInteractionEnabled = true snackbarView.translatesAutoresizingMaskIntoConstraints = false snackbarView.isUserInteractionEnabled = true - snackbarView.backgroundColor = .blue - Logger.common(message: "SnackbarViewController viewDidLoad.") } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() - Logger.common(message: "SnackbarViewController flag hasSetupLayers: \(hasSetupLayers).") if !hasSetupLayers { hasSetupLayers = true setupConstraints() setupLayers() - Logger.common(message: "SnackbarViewController we're in !hasSetupLayers condition.") if snackbarView.bounds.size != .zero { - Logger.common(message: "SnackbarViewController we're in !snackbarView.bound.size != zero condition.") setupElements() hasSetupElements = true } } else if !hasSetupElements && snackbarView.bounds.size != .zero { - Logger.common(message: "SnackbarViewController we're in !hasSetupElements && snackbarView.bounds.size != .zero condition.") UIView.performWithoutAnimation { setupElements() hasSetupElements = true view.layoutIfNeeded() } } - - Logger.common(message: "SnackbarViewController viewDidLayoutSubviews done.") } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) animateConstraints(withDuration: Constants.animationDuration) onPresented() - Logger.common(message: "SnackbarViewController viewDidAppear.") } private func setupLayers() { - Logger.common(message: "SnackbarViewController setupLayers function started.") let layers = model.content.background.layers.elements - - Logger.common(message: "SnackbarViewController layers: \(layers.count).") + for layer in layers { if let factory = layersFactories[layer.layerType] { if case .image(let imageContentBackgroundLayer) = layer { @@ -129,20 +117,11 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { self.layers.append(layerView) snackbarView.addSubview(layerView) factory.setupConstraintsSnackbar(for: layerView, in: snackbarView) - } else { - Logger.common(message: "SnackbarViewController layer view does not exists.") } - } else { - Logger.common(message: "SnackbarViewController imageContentBackgroundLayer source or value does not exists.\n[Layer]: \(imageContentBackgroundLayer)\n[Dict]: \(imagesDict)") } - } else { - Logger.common(message: "SnackbarViewController not image type of layer.") } - } else { - Logger.common(message: "SnackbarViewController layersFactory does not exists.") } } - Logger.common(message: "SnackbarViewController setupLayers function finished.") } private func setupElements() { @@ -168,25 +147,21 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private func animateConstraints(withDuration duration: TimeInterval) { - Logger.common(message: "SnackbarViewController animateConstraints function started.") view.layoutIfNeeded() UIView.animate(withDuration: duration) { self.edgeConstraint?.constant = 0 - Logger.common(message: "SnackbarViewController animateConstraints UIView.animate condition.") self.view.layoutIfNeeded() } - Logger.common(message: "SnackbarViewController animateConstraints function finished.") } func setupConstraints() { - Logger.common(message: "SnackbarViewController setupConstraints function started.") guard let image = imagesDict[firstImageValue] else { Logger.common(message: "[Error]: \(#function) at line \(#line) of \(#file)", level: .error) return } - let width = view.layer.frame.width - leftOffset - rightOffset + let width = view.layer.frame.width let heightMultiplier = width / image.size.width let imageHeight = image.size.height * heightMultiplier let finalHeight = (imageHeight < Constants.oneThirdScreenHeight) ? imageHeight : Constants.oneThirdScreenHeight @@ -198,8 +173,6 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { setupLayoutConstraints(with: finalHeight) setupEdgeConstraint(with: finalHeight) - - Logger.common(message: "SnackbarViewController setupConstraints function finished.") } func setViewFrame(with height: CGFloat) { @@ -207,7 +180,6 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } func setupLayoutConstraints(with height: CGFloat) { - Logger.common(message: "SnackbarViewController setupLayoutConstraints function started.") if #available(iOS 11.0, *) { Logger.common(message: "SnackbarViewController setupLayoutConstraints iOS 11+.") NSLayoutConstraint.activate([ @@ -223,7 +195,6 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { snackbarView.heightAnchor.constraint(equalToConstant: height), ]) } - Logger.common(message: "SnackbarViewController setupLayoutConstraints function finished.") } func setupEdgeConstraint(with height: CGFloat) { @@ -303,12 +274,10 @@ class BottomSnackbarViewController: SnackbarViewController { self.view.frame = CGRect(x: leftOffset, y: screenHeight - finalHeight, width: UIScreen.main.bounds.width - leftOffset - rightOffset, height: finalHeight) - self.view.backgroundColor = .yellow Logger.common(message: "SnackbarViewController setViewFrame function finished.") } override func setupEdgeConstraint(with height: CGFloat) { - Logger.common(message: "SnackbarViewController setupEdgeConstraint function started.") if #available(iOS 11.0, *) { Logger.common(message: "SnackbarViewController setupEdgeConstraint iOS 11+.") edgeConstraint = snackbarView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: height) @@ -318,6 +287,5 @@ class BottomSnackbarViewController: SnackbarViewController { } edgeConstraint?.isActive = true - Logger.common(message: "SnackbarViewController setupEdgeConstraint function finished.") } } diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift index d65b8a72..b009d91f 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift @@ -21,10 +21,8 @@ class SnackbarViewFactory: ViewFactoryProtocol { let snackbarView = SnackbarView(onClose: onClose) switch gravity { case .top: - Logger.common(message: "SnackbarViewFactory TopSnackbarViewController handleSwipeGesture created.") snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) case .bottom: - Logger.common(message: "SnackbarViewFactory BottomSnackbarViewController handleSwipeGesture created.") snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, snackbarView: snackbarView, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction) default: Logger.common(message: "SnackbarViewFactory controller is nil.")