From f12adc8c1a8f13be74ebc682b492ba7a7f255811 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 3 Sep 2023 20:27:36 +0000 Subject: [PATCH 01/28] Update dependency macos to v13 --- .github/workflows/publish.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8140dcc3..46e7f009 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -22,7 +22,7 @@ jobs: publish: needs: [unit] - runs-on: macos-11 + runs-on: macos-13 steps: - uses: actions/checkout@v2 - name: Release generation From 8ae09c1c8451857b41fd4aab2bd20bd8e1ef0d69 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Mon, 4 Sep 2023 02:38:46 +0600 Subject: [PATCH 02/28] MBX-2793 Multiple layers --- .../InAppConfigurationManager.swift | 2 +- .../InAppConfigutationMapper.swift | 43 +++++++++---- .../VariantImageUrlExtractorService.swift | 63 +++++++++---------- .../InAppMessages/Models/InAppFormData.swift | 2 +- .../PresentationDisplayUseCase.swift | 2 +- .../CloseButtonElementFactory.swift | 2 +- .../ElementFactory/ElementFactory.swift | 2 +- .../Views/ModalView/ModalViewController.swift | 24 ++++--- .../SnackbarView/SnackbarViewController.swift | 26 +++++--- .../Views/ViewFactory/ModalViewFactory.swift | 4 +- .../ViewFactory/SnackbarViewFactory.swift | 6 +- .../ViewFactory/ViewFactoryProtocol.swift | 2 +- Mindbox/Info.plist | 2 +- 13 files changed, 102 insertions(+), 78 deletions(-) diff --git a/Mindbox/InAppMessages/Configuration/InAppConfigurationManager.swift b/Mindbox/InAppMessages/Configuration/InAppConfigurationManager.swift index 002ca977..4205d359 100644 --- a/Mindbox/InAppMessages/Configuration/InAppConfigurationManager.swift +++ b/Mindbox/InAppMessages/Configuration/InAppConfigurationManager.swift @@ -139,7 +139,7 @@ class InAppConfigurationManager: InAppConfigurationManagerProtocol { rawConfigurationResponse = configResponse inAppConfigurationMapper.mapConfigResponse(event, configResponse, { inapp in self.inapp = inapp - Logger.common(message: "In-app сonfiguration applied: \n\(String(describing: inapp))", level: .debug, category: .inAppMessages) + Logger.common(message: "In-app applied: \(String(describing: inapp?.inAppId)))", level: .debug, category: .inAppMessages) self.delegate?.didPreparedConfiguration() }) } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift index fc3e668c..6466a420 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift @@ -257,6 +257,7 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { completion: @escaping (InAppFormData?) -> Void) { var shouldDownloadImage = true var formData: InAppFormData? + var imageDict: [String: UIImage] = [:] let group = DispatchGroup() DispatchQueue.global().async { @@ -269,25 +270,41 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { continue } - guard let imageValue = self.urlExtractorService.extractImageURL(from: inapp.content) else { continue } + let imageValues = self.urlExtractorService.extractImageURL(from: inapp.content) + + var gotError = false - group.enter() Logger.common(message: "Starting inapp processing. [ID]: \(inapp.inAppId)", level: .debug, category: .inAppMessages) - - self.imageDownloadService.downloadImage(withUrl: imageValue) { result in - defer { group.leave() } - switch result { - case .success(let image): - formData = InAppFormData(inAppId: inapp.inAppId, - image: image, - content: inapp.content) - shouldDownloadImage = false - case .failure: + + for imageValue in imageValues { + group.enter() + Logger.common(message: "Initiating the process of image loading from the URL: \(imageValue)", level: .debug, category: .inAppMessages) + self.imageDownloadService.downloadImage(withUrl: imageValue) { result in + switch result { + case .success(let image): + imageDict[imageValue] = image + group.leave() + case .failure: + gotError = true + group.leave() + } + } + + if gotError { break } + + group.wait() } - group.wait() + if gotError { + continue + } + + if !imageDict.isEmpty { + formData = InAppFormData(inAppId: inapp.inAppId, imagesDict: imageDict, content: inapp.content) + shouldDownloadImage = false + } } group.notify(queue: .main) { diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift index bcbc3412..a6864d7f 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift @@ -9,43 +9,38 @@ import Foundation class VariantImageUrlExtractorService { - func extractImageURL(from variant: MindboxFormVariant) -> String? { - var urlString: String? + func extractImageURL(from variant: MindboxFormVariant) -> [String] { + var urlString: [String] = [] + + let elements: [ContentBackgroundLayer] + switch variant { - case .modal(let modalModel): - let modalModel = modalModel.content.background.layers.elements.first(where: { - switch $0 { - case .image(let imageModel): - switch imageModel.source { - case .url(let urlModel): - urlString = urlModel.value - return true - case .unknown: - return false - } - case .unknown: - return false - } - }) - case .snackbar(let snackbarModel): - let snackbarModel = snackbarModel.content.background.layers.elements.first { - switch $0 { - case .image(let imageModel): - switch imageModel.source { - case .url(let urlModel): - urlString = urlModel.value - return true - case .unknown: - return false - } - case .unknown: - return false - } - } - case .unknown: - return nil + case .modal(let modalModel): + elements = modalModel.content.background.layers.elements + case .snackbar(let snackbarModel): + elements = snackbarModel.content.background.layers.elements + case .unknown: + return [] } + extractImageURLs(from: elements, into: &urlString) + return urlString } + + private func extractImageURLs(from elements: [ContentBackgroundLayer], into urlString: inout [String]) { + for element in elements { + switch element { + case .image(let imageModel): + switch imageModel.source { + case .url(let urlModel): + urlString.append(urlModel.value) + case .unknown: + break + } + case .unknown: + break + } + } + } } diff --git a/Mindbox/InAppMessages/Models/InAppFormData.swift b/Mindbox/InAppMessages/Models/InAppFormData.swift index fb19ebfd..62e1b935 100644 --- a/Mindbox/InAppMessages/Models/InAppFormData.swift +++ b/Mindbox/InAppMessages/Models/InAppFormData.swift @@ -12,7 +12,7 @@ import UIKit /// Domain model that contains all data needed to show inapp on screen struct InAppFormData { let inAppId: String - let image: UIImage + let imagesDict: [String: UIImage] let content: MindboxFormVariant } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift index a8cf485f..34edf0e0 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift @@ -37,7 +37,7 @@ final class PresentationDisplayUseCase { guard let viewController = factory.create(model: model.content, id: model.inAppId, - image: model.image, + imagesDict: model.imagesDict, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) else { diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift index 34023bf3..24d861b9 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift @@ -9,7 +9,7 @@ import UIKit class CloseButtonElementFactory: ElementFactory { - func create(from element: ContentElement, in view: UIView, with controller: GestureHandler) -> UIView? { + func create(from element: ContentElement, with controller: GestureHandler) -> UIView? { if case .closeButton(let closeButtonElement) = element { let color = closeButtonElement.color?.isHexValid() ?? false ? closeButtonElement.color : nil let closeButton = CrossView(lineColorHex: color, lineWidth: closeButtonElement.lineWidth) diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/ElementFactory.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/ElementFactory.swift index aee49a5c..ea46e436 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/ElementFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/ElementFactory.swift @@ -9,6 +9,6 @@ import UIKit protocol ElementFactory { - func create(from element: ContentElement, in view: UIView, with controller: GestureHandler) -> UIView? + func create(from element: ContentElement, with controller: GestureHandler) -> UIView? func setupConstraints(for view: UIView, from element: ContentElement, in parentView: UIView) } diff --git a/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift b/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift index dbd3b145..a6e29f51 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift @@ -34,14 +34,14 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, init( model: ModalFormVariant, id: String, - image: UIImage, + imagesDict: [String: UIImage], onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void ) { self.model = model self.id = id - self.image = image + self.imagesDict = imagesDict self.onPresented = onPresented self.onClose = onClose self.onTapAction = onTapAction @@ -54,7 +54,7 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, private let model: ModalFormVariant private let id: String - private let image: UIImage + private let imagesDict: [String: UIImage] private let onPresented: () -> Void private let onClose: () -> Void private let onTapAction: (ContentBackgroundLayerAction?) -> Void @@ -111,11 +111,15 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, let layers = model.content.background.layers.elements for layer in layers { if let factory = layersFactories[layer.layerType] { - let layerView = factory.create(from: self.image, layer: layer, in: view, with: self) - if let layerView = layerView { - self.layers.append(layerView) - view.addSubview(layerView) - factory.setupConstraints(for: layerView, in: view) + if case .image(let imageContentBackgroundLayer) = layer { + if case .url(let urlModel) = imageContentBackgroundLayer.source, let image = imagesDict[urlModel.value] { + let layerView = factory.create(from: image, layer: layer, in: view, with: self) + if let layerView = layerView { + self.layers.append(layerView) + view.addSubview(layerView) + factory.setupConstraints(for: layerView, in: view) + } + } } } } @@ -129,10 +133,10 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, for element in elements { if let factory = elementFactories[element.elementType] { - let elementView = factory.create(from: element, in: inappView, with: self) + let elementView = factory.create(from: element, with: self) if let elementView = elementView { self.elements.append(elementView) - inappView.addSubview(elementView) + view.addSubview(elementView) factory.setupConstraints(for: elementView, from: element, in: inappView) } } diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift index 52cb1eac..b8991ff3 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift @@ -35,7 +35,7 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private let id: String - public let image: UIImage + private let imagesDict: [String: UIImage] private let onPresented: () -> Void private let onClose: () -> Void private let onTapAction: (ContentBackgroundLayerAction?) -> Void @@ -52,14 +52,14 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { init( model: SnackbarFormVariant, id: String, - image: UIImage, + imagesDict: [String: UIImage], onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void ) { self.model = model self.id = id - self.image = image + self.imagesDict = imagesDict self.onPresented = onPresented self.onClose = onClose self.onTapAction = onTapAction @@ -115,11 +115,15 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { for layer in layers { if let factory = layersFactories[layer.layerType] { - let layerView = factory.create(from: self.image, layer: layer, in: snackbarView, with: self) - if let layerView = layerView { - self.layers.append(layerView) - snackbarView.addSubview(layerView) - factory.setupConstraintsSnackbar(for: layerView, in: snackbarView) + if case .image(let imageContentBackgroundLayer) = layer { + if case .url(let urlModel) = imageContentBackgroundLayer.source, let image = imagesDict[urlModel.value] { + let layerView = factory.create(from: image, layer: layer, in: view, with: self) + if let layerView = layerView { + self.layers.append(layerView) + snackbarView.addSubview(layerView) + factory.setupConstraintsSnackbar(for: layerView, in: snackbarView) + } + } } } } @@ -133,7 +137,7 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { for element in elements { if let factory = elementFactories[element.elementType] { - let elementView = factory.create(from: element, in: snackbarView, with: self) + let elementView = factory.create(from: element, with: self) if let elementView = elementView { self.elements.append(elementView) snackbarView.addSubview(elementView) @@ -157,6 +161,10 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } func setupConstraints() { + guard let firstImageKey = imagesDict.keys.first, let image = imagesDict[firstImageKey] else { + return + } + let width = view.layer.frame.width - leftOffset - rightOffset let heightMultiplier = width / image.size.width let imageHeight = image.size.height * heightMultiplier diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift index e1225317..503a120a 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift @@ -13,14 +13,14 @@ class ModalViewFactory: ViewFactoryProtocol { func create(model: MindboxFormVariant, id: String, - image: UIImage, + imagesDict: [String: UIImage], onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? { if case .modal(let modalFormVariant) = model { let viewController = ModalViewController(model: modalFormVariant, id: id, - image: image, + imagesDict: imagesDict, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift index 3f46ebd1..5a9526f4 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift @@ -13,15 +13,15 @@ class SnackbarViewFactory: ViewFactoryProtocol { weak var viewController: UIViewController? - func create(model: MindboxFormVariant, id: String, image: UIImage, onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? { + func create(model: MindboxFormVariant, id: String, imagesDict: [String: UIImage], onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? { if case .snackbar(let snackbarFormVariant) = model { if let gravity = snackbarFormVariant.content.position?.gravity?.element?.vertical { var snackbarViewController: UIViewController? switch gravity { case .top: - snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, id: id, image: image, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) + snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, id: id, imagesDict: imagesDict, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) case .bottom: - snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, id: id, image: image, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) + snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, id: id, imagesDict: imagesDict, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) default: return nil } diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift index af67960e..6e24d472 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift @@ -12,7 +12,7 @@ import Foundation protocol ViewFactoryProtocol { func create(model: MindboxFormVariant, id: String, - image: UIImage, + imagesDict: [String: UIImage], onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? diff --git a/Mindbox/Info.plist b/Mindbox/Info.plist index ea2f1d8a..4755d639 100644 --- a/Mindbox/Info.plist +++ b/Mindbox/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 4781 + 4783 From 2f5c6c2f51a5be2aeed920ce7c30ec89cddf3ab5 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Mon, 4 Sep 2023 04:14:19 +0600 Subject: [PATCH 03/28] MBX-2793 Parallel image loading --- .../InAppConfigutationMapper.swift | 40 +++++++++---------- .../Services/ImageDownloadService.swift | 2 +- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift index 6466a420..7832ebdc 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift @@ -255,55 +255,51 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { private func buildInAppByEvent(inapps: [InAppTransitionData], completion: @escaping (InAppFormData?) -> Void) { - var shouldDownloadImage = true var formData: InAppFormData? - var imageDict: [String: UIImage] = [:] let group = DispatchGroup() + let imageDictQueue = DispatchQueue(label: "com.mindbox.imagedict.queue", attributes: .concurrent) DispatchQueue.global().async { for inapp in inapps { - if !shouldDownloadImage { + guard formData == nil else { break } + var imageDict: [String: UIImage] = [:] + var gotError = false + if let shownInapps = self.persistenceStorage.shownInAppsIds, shownInapps.contains(inapp.inAppId) { continue } let imageValues = self.urlExtractorService.extractImageURL(from: inapp.content) - var gotError = false - - Logger.common(message: "Starting inapp processing. [ID]: \(inapp.inAppId)", level: .debug, category: .inAppMessages) - + Logger.common(message: "Starting in-app processing. [ID]: \(inapp.inAppId)", level: .debug, category: .inAppMessages) for imageValue in imageValues { group.enter() Logger.common(message: "Initiating the process of image loading from the URL: \(imageValue)", level: .debug, category: .inAppMessages) self.imageDownloadService.downloadImage(withUrl: imageValue) { result in + defer { + group.leave() + } + switch result { case .success(let image): - imageDict[imageValue] = image - group.leave() + imageDictQueue.async(flags: .barrier) { + imageDict[imageValue] = image + } case .failure: gotError = true - group.leave() } } - - if gotError { - break - } - - group.wait() } - if gotError { - continue - } + group.wait() - if !imageDict.isEmpty { - formData = InAppFormData(inAppId: inapp.inAppId, imagesDict: imageDict, content: inapp.content) - shouldDownloadImage = false + imageDictQueue.sync { + if !imageDict.isEmpty && !gotError { + formData = InAppFormData(inAppId: inapp.inAppId, imagesDict: imageDict, content: inapp.content) + } } } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/ImageDownloadService.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/ImageDownloadService.swift index 7731baad..28ffce50 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/ImageDownloadService.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/ImageDownloadService.swift @@ -24,7 +24,7 @@ class ImageDownloadService: ImageDownloadServiceProtocol { func downloadImage(withUrl url: String, completion: @escaping (Result) -> Void) { self.imageDownloader.downloadImage(withUrl: url) { localURL, response, error in if let error = error as? NSError { - Logger.common(message: "Failed to download image for url: \(url). \nError: \(error.localizedDescription)", level: .debug, category: .inAppMessages) + Logger.common(message: "Failed to download image. [URL]: \(url). \nError: \(error.localizedDescription)", level: .debug, category: .inAppMessages) if error.code == NSURLErrorTimedOut { completion(.failure(error)) } else { From 3169073c0c076bff6b1207c6c48a2a967e2c2f51 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Mon, 4 Sep 2023 04:42:03 +0600 Subject: [PATCH 04/28] MBX-2793 Add uni tests for VariantImageUrlExtractorService --- Mindbox.xcodeproj/project.pbxproj | 4 + .../InAppConfigutationMapper.swift | 4 +- .../VariantImageUrlExtractorService.swift | 6 +- Mindbox/Info.plist | 2 +- ...VariantImageUrlExtractorServiceTests.swift | 213 ++++++++++++++++++ 5 files changed, 225 insertions(+), 4 deletions(-) create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/VariantImageUrlExtractorServiceTests.swift diff --git a/Mindbox.xcodeproj/project.pbxproj b/Mindbox.xcodeproj/project.pbxproj index 5191695b..3c7e13d0 100644 --- a/Mindbox.xcodeproj/project.pbxproj +++ b/Mindbox.xcodeproj/project.pbxproj @@ -367,6 +367,7 @@ F3482F232A65DC37002A41EC /* InAppMessagesDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3482F222A65DC37002A41EC /* InAppMessagesDelegate.swift */; }; F3482F2A2A65DCFC002A41EC /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3482F292A65DCFC002A41EC /* String+Extensions.swift */; }; F37613E12A6A8CFF009F2EE4 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37613E02A6A8CFF009F2EE4 /* UIColor+Extensions.swift */; }; + F39116EE2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116ED2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift */; }; F397EEAD2A4456C300D48CEC /* ProtocolError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEAC2A4456C300D48CEC /* ProtocolError.swift */; }; F397EEAF2A4456FD00D48CEC /* MindboxError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEAE2A4456FD00D48CEC /* MindboxError.swift */; }; F397EEB12A44571300D48CEC /* UnknownDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEB02A44571300D48CEC /* UnknownDecodable.swift */; }; @@ -822,6 +823,7 @@ F3482F222A65DC37002A41EC /* InAppMessagesDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppMessagesDelegate.swift; sourceTree = ""; }; F3482F292A65DCFC002A41EC /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = ""; }; F37613E02A6A8CFF009F2EE4 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = ""; }; + F39116ED2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariantImageUrlExtractorServiceTests.swift; sourceTree = ""; }; F397EEAC2A4456C300D48CEC /* ProtocolError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolError.swift; sourceTree = ""; }; F397EEAE2A4456FD00D48CEC /* MindboxError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MindboxError.swift; sourceTree = ""; }; F397EEB02A44571300D48CEC /* UnknownDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnknownDecodable.swift; sourceTree = ""; }; @@ -2407,6 +2409,7 @@ F39B67AA2A3C7304005C0CCA /* ImageDownloadService */, F3A8B95B2A389EAD00E9C055 /* GeoServiceTests.swift */, F39B67A62A3C6C6A005C0CCA /* SegmentationServiceTests.swift */, + F39116ED2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift */, ); path = InAppConfigurationMapperTests; sourceTree = ""; @@ -3049,6 +3052,7 @@ 848A895E2620C54900EDFB6D /* VersioningTestCase.swift in Sources */, A1A916E529C9191900D59D9E /* InAppConfigStub.swift in Sources */, 313B233F25ADEA0F00A1CB72 /* MindboxTests.swift in Sources */, + F39116EE2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift in Sources */, A154E334299E110E00F8F074 /* EventRepositoryMock.swift in Sources */, 31ED2DEC25C444C400301FAD /* MBConfigurationTestCase.swift in Sources */, F3D925AD2A1236F400135C87 /* URLSessionImageDownloaderTests.swift in Sources */, diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift index 7832ebdc..75c0c92b 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift @@ -25,7 +25,7 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { var filteredInAppsByEvent: [InAppMessageTriggerEvent: [InAppTransitionData]] = [:] private let sdkVersionValidator: SDKVersionValidator private let imageDownloadService: ImageDownloadServiceProtocol - private let urlExtractorService: VariantImageUrlExtractorService + private let urlExtractorService: VariantImageUrlExtractorServiceProtocol private let abTestDeviceMixer: ABTestDeviceMixer private let dispatchGroup = DispatchGroup() @@ -38,7 +38,7 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { persistenceStorage: PersistenceStorage, sdkVersionValidator: SDKVersionValidator, imageDownloadService: ImageDownloadServiceProtocol, - urlExtractorService: VariantImageUrlExtractorService, + urlExtractorService: VariantImageUrlExtractorServiceProtocol, abTestDeviceMixer: ABTestDeviceMixer) { self.geoService = geoService self.segmentationService = segmentationService diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift index a6864d7f..c3512e6a 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift @@ -8,7 +8,11 @@ import Foundation -class VariantImageUrlExtractorService { +protocol VariantImageUrlExtractorServiceProtocol { + func extractImageURL(from variant: MindboxFormVariant) -> [String] +} + +class VariantImageUrlExtractorService: VariantImageUrlExtractorServiceProtocol { func extractImageURL(from variant: MindboxFormVariant) -> [String] { var urlString: [String] = [] diff --git a/Mindbox/Info.plist b/Mindbox/Info.plist index 4755d639..4d77df85 100644 --- a/Mindbox/Info.plist +++ b/Mindbox/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 4783 + 4794 diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/VariantImageUrlExtractorServiceTests.swift b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/VariantImageUrlExtractorServiceTests.swift new file mode 100644 index 00000000..7df9aba3 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/VariantImageUrlExtractorServiceTests.swift @@ -0,0 +1,213 @@ +// +// VariantImageUrlExtractorServiceTests.swift +// MindboxTests +// +// Created by vailence on 04.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import XCTest +@testable import Mindbox + +final class VariantImageUrlExtractorServiceTests: XCTestCase { + + var sut: VariantImageUrlExtractorServiceProtocol! + + override func setUp() { + super.setUp() + sut = VariantImageUrlExtractorService() + } + + override func tearDown() { + sut = nil + super.tearDown() + } + + func decodeJSON(_ json: String, to type: T.Type) -> T? { + guard let data = json.data(using: .utf8) else { return nil } + let decoder = JSONDecoder() + do { + let decodedObject = try decoder.decode(T.self, from: data) + return decodedObject + } catch { + print("JSON Decoding Error: \(error)") + return nil + } + } + + func testExtractUrls_modal_all_valid() { + let formVariantJSON = """ + { + "content": { + "background": { + "layers": [ + { + "action": { + "intentPayload": "{}", + "value": "https://images.pexels.com/photos/1624496/pexels-photo-1624496.jpeg", + "$type": "redirectUrl" + }, + "source": { + "value": "https://images.pexels.com/photos/1624496/pexels-photo-1624496.jpeg", + "$type": "url" + }, + "$type": "image" + }, + { + "action": { + "intentPayload": "{}", + "value": "https://mindbox-pushok.umbrellait.tech:444/?image=mindbox.png&broken=true&error=wait&speed=20", + "$type": "redirectUrl" + }, + "source": { + "value": "https://mindbox-pushok.umbrellait.tech:444/?image=mindbox.png&broken=true&error=wait&speed=20", + "$type": "url" + }, + "$type": "image" + } + ] + }, + "position": { + "margin": { + "kind": "dp", + "top": 0, + "right": 0, + "left": 0, + "bottom": 0 + }, + "gravity": { + "horizontal": "center", + "vertical": "bottom" + } + }, + "elements": [ + { + "color": "#000000", + "lineWidth": 1, + "size": { + "kind": "dp", + "width": 24, + "height": 24 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.02, + "right": 0.02, + "left": 0, + "bottom": 0 + } + }, + "$type": "closeButton" + } + ] + }, + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "$type": "modal" + } + """ + + guard let formVariant: MindboxFormVariant = decodeJSON(formVariantJSON, to: MindboxFormVariant.self) else { + XCTFail("Could not decode MindboxFormVariant from JSON") + return + } + + let extractedUrls = sut.extractImageURL(from: formVariant) + let expectedUrls = [ + "https://images.pexels.com/photos/1624496/pexels-photo-1624496.jpeg", + "https://mindbox-pushok.umbrellait.tech:444/?image=mindbox.png&broken=true&error=wait&speed=20", + ] + + XCTAssertEqual(extractedUrls, expectedUrls) + } + + func testExtractUrls_snackbar_all_valid() { + let formVariantJSON = """ + { + "content": { + "background": { + "layers": [ + { + "action": { + "intentPayload": "{}", + "value": "https://www.getmailbird.com/setup/assets/imgs/logos/gmail.com.webp", + "$type": "redirectUrl" + }, + "source": { + "value": "https://www.getmailbird.com/setup/assets/imgs/logos/gmail.com.webp", + "$type": "url" + }, + "$type": "image" + }, + { + "action": { + "intentPayload": "{}", + "value": "https://images.pexels.com/photos/1402787/pexels-photo-1402787.jpeg?auto=compress&cs=tinysrgb&w=6000&h=4000&dpr=2", + "$type": "redirectUrl" + }, + "source": { + "value": "https://images.pexels.com/photos/1402787/pexels-photo-1402787.jpeg?auto=compress&cs=tinysrgb&w=6000&h=4000&dpr=2", + "$type": "url" + }, + "$type": "image" + } + ] + }, + "position": { + "margin": { + "kind": "dp", + "top": 0, + "right": 0, + "left": 0, + "bottom": 0 + }, + "gravity": { + "horizontal": "center", + "vertical": "bottom" + } + }, + "elements": [ + { + "color": "#000000", + "lineWidth": 1, + "size": { + "kind": "dp", + "width": 24, + "height": 24 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.02, + "right": 0.02, + "left": 0, + "bottom": 0 + } + }, + "$type": "closeButton" + } + ] + }, + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "$type": "snackbar" + } + """ + + guard let formVariant: MindboxFormVariant = decodeJSON(formVariantJSON, to: MindboxFormVariant.self) else { + XCTFail("Could not decode MindboxFormVariant from JSON") + return + } + + let extractedUrls = sut.extractImageURL(from: formVariant) + let expectedUrls = [ + "https://www.getmailbird.com/setup/assets/imgs/logos/gmail.com.webp", + "https://images.pexels.com/photos/1402787/pexels-photo-1402787.jpeg?auto=compress&cs=tinysrgb&w=6000&h=4000&dpr=2", + ] + + XCTAssertEqual(extractedUrls, expectedUrls) + } +} From c03e1cf48b757fffc7d1c4dcfeb62a491dc09db4 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 13:35:58 +0000 Subject: [PATCH 05/28] Update actions/checkout action to v4 --- .github/workflows/build.yml | 2 +- .github/workflows/publish.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1b49d9cd..5547f9a6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ jobs: build: runs-on: macos-13 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 - name: Update bundler run: gem install bundler - name: Install bundler dependencies diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8140dcc3..4927212b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -12,7 +12,7 @@ jobs: unit: runs-on: macos-13 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 - name: Update bundler run: gem install bundler - name: Install bundler dependencies @@ -24,7 +24,7 @@ jobs: needs: [unit] runs-on: macos-11 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 - name: Release generation run: ./git-release.sh "${{ github.event.head_commit.message }}" "${{secrets.GITHUBACCESSTOKEN}}" "${{secrets.GITHUBUSER}}" - name: Update bundler From 4fc1f6eab909afcbf13cca280f9c2f9922fc82b0 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Wed, 6 Sep 2023 16:10:44 +0600 Subject: [PATCH 06/28] MBX-2792 Init commit --- Mindbox.xcodeproj/project.pbxproj | 12 + .../InAppConfigutationMapper.swift | 5 +- .../InappsFilterService.swift | 229 ++++++++++++++++++ .../VariantImageUrlExtractorService.swift | 10 +- .../Models/Config/ConfigResponse.swift | 6 +- .../Models/Config/InappModel/InAppModel.swift | 26 +- .../InappModel/InappForm/InappForm.swift | 21 +- .../ContentBackground/ContentBackground.swift | 25 +- .../ContentBackgroundLayer.swift | 69 +++++- .../Actions/RedirectUrlLayerAction.swift | 6 +- .../ContentBackgroundLayerAction.swift | 69 +++++- .../ContentBackgroundLayerSource.swift | 69 +++++- .../Sources/UrlLayerSource.swift | 4 + .../Layers/ImageContentBackgroundLayer.swift | 6 + .../ContentElement/ContentElement.swift | 69 +++++- .../ContentElementPosition.swift | 7 +- .../ContentElementPositionMargin.swift | 40 +-- .../ContentElementSize.swift | 29 +-- .../Elements/CloseButtonElement.swift | 15 +- .../InappFormVariantContent.swift | 7 +- .../Variants/ModalFormVariant.swift | 4 + .../InappFormVariant/iFormVariant.swift | 70 ++++++ .../CloseButtonElementFactory.swift | 8 +- .../Views/ModalView/ModalViewController.swift | 6 +- .../SnackbarView/SnackbarViewController.swift | 4 +- 25 files changed, 677 insertions(+), 139 deletions(-) create mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappsFilterService.swift diff --git a/Mindbox.xcodeproj/project.pbxproj b/Mindbox.xcodeproj/project.pbxproj index 3c7e13d0..94cffb2f 100644 --- a/Mindbox.xcodeproj/project.pbxproj +++ b/Mindbox.xcodeproj/project.pbxproj @@ -368,6 +368,7 @@ F3482F2A2A65DCFC002A41EC /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3482F292A65DCFC002A41EC /* String+Extensions.swift */; }; F37613E12A6A8CFF009F2EE4 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37613E02A6A8CFF009F2EE4 /* UIColor+Extensions.swift */; }; F39116EE2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116ED2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift */; }; + F39116F22AA9AF0E00852298 /* InappsFilterService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116F12AA9AF0E00852298 /* InappsFilterService.swift */; }; F397EEAD2A4456C300D48CEC /* ProtocolError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEAC2A4456C300D48CEC /* ProtocolError.swift */; }; F397EEAF2A4456FD00D48CEC /* MindboxError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEAE2A4456FD00D48CEC /* MindboxError.swift */; }; F397EEB12A44571300D48CEC /* UnknownDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEB02A44571300D48CEC /* UnknownDecodable.swift */; }; @@ -824,6 +825,7 @@ F3482F292A65DCFC002A41EC /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = ""; }; F37613E02A6A8CFF009F2EE4 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = ""; }; F39116ED2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariantImageUrlExtractorServiceTests.swift; sourceTree = ""; }; + F39116F12AA9AF0E00852298 /* InappsFilterService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InappsFilterService.swift; sourceTree = ""; }; F397EEAC2A4456C300D48CEC /* ProtocolError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolError.swift; sourceTree = ""; }; F397EEAE2A4456FD00D48CEC /* MindboxError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MindboxError.swift; sourceTree = ""; }; F397EEB02A44571300D48CEC /* UnknownDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnknownDecodable.swift; sourceTree = ""; }; @@ -2326,6 +2328,14 @@ path = Extensions; sourceTree = ""; }; + F39116F32AA9AF3C00852298 /* InappFilterService */ = { + isa = PBXGroup; + children = ( + F39116F12AA9AF0E00852298 /* InappsFilterService.swift */, + ); + path = InappFilterService; + sourceTree = ""; + }; F397EEAB2A4456A900D48CEC /* MindboxError */ = { isa = PBXGroup; children = ( @@ -2395,6 +2405,7 @@ F3A8B9562A389D9300E9C055 /* Services */ = { isa = PBXGroup; children = ( + F39116F32AA9AF3C00852298 /* InappFilterService */, F3A8B9572A389D9D00E9C055 /* GeoService.swift */, F39B67A12A3C6AF4005C0CCA /* SegmentationService.swift */, F39B67A82A3C72E5005C0CCA /* ImageDownloadService.swift */, @@ -2823,6 +2834,7 @@ 84DEE8B125CC042A00C98CC7 /* MBDatabaseError.swift in Sources */, A179587C2978AED800609E91 /* GeoTargeting.swift in Sources */, 3333C1E12681EA4D00B60D84 /* NotificationsPayloads.swift in Sources */, + F39116F22AA9AF0E00852298 /* InappsFilterService.swift in Sources */, 334F3AE7264C199900A6AC00 /* CatalogProductListRequest.swift in Sources */, F331DCC02A80993600222120 /* ContentElementSizeType.swift in Sources */, F331DCC52A80993600222120 /* PositionMarginKind.swift in Sources */, diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift index 75c0c92b..52dc720c 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift @@ -57,7 +57,8 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { _ response: ConfigResponse, _ completion: @escaping (InAppFormData?) -> Void) { let shownInAppsIds = Set(persistenceStorage.shownInAppsIds ?? []) - let responseInapps = filterInappsByABTests(response.abtests, responseInapps: response.inapps?.elements) + let filteredInappsModel = InappsFilterService().filter(inapps: response.inapps?.elements) + let responseInapps = filterInappsByABTests(response.abtests, responseInapps: filteredInappsModel) let filteredInapps = filterInappsBySDKVersion(responseInapps, shownInAppsIds: shownInAppsIds) Logger.common(message: "Shown in-apps ids: [\(shownInAppsIds)]", level: .info, category: .inAppMessages) if filteredInapps.isEmpty { @@ -242,7 +243,7 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { } var inAppsForEvent = filteredInAppsByEvent[triggerEvent] ?? [InAppTransitionData]() - if let inAppFormVariants = inapp.form.variants.elements.first { + if let inAppFormVariants = inapp.form.variants.first { let formData = InAppTransitionData(inAppId: inapp.id, content: inAppFormVariants) inAppsForEvent.append(formData) diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappsFilterService.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappsFilterService.swift new file mode 100644 index 00000000..71a27dce --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappsFilterService.swift @@ -0,0 +1,229 @@ +// +// InappsFilterService.swift +// Mindbox +// +// Created by vailence on 06.09.2023. +// + +import Foundation +import MindboxLogger + +protocol InappsFilterServiceProtocol { +// func +} + +class InappsFilterService: InappsFilterServiceProtocol { + + enum Constants { + static let elementSize = ContentElementSize(kind: .dp, width: 24, height: 24) + static let elementPositionMargin = ContentElementPositionMargin(kind: .proportion, top: 0.02, right: 0.02, left: 0.02, bottom: 0.02) + static let defaultColor = "#000000" + static let lineWidth = 1 + + } + + func filter(inapps: [InAppDTO]?) -> [InApp] { + guard let inapps = inapps else { + return [] + } + + var filteredInapps = [InApp]() + for inapp in inapps { + guard let variants = inapp.form.variants else { + Logger.common(message: "Variants cannot be empty. Inapp will be ignored.") + continue + } + + var isValidInapp = true + var variantsArray = [MindboxFormVariant]() + variantsLoop: for variant in variants { + switch variant { + case .modal(let modalFormVariant): + guard let content = modalFormVariant.content, + let background = content.background, + let layers = background.layers + else { + isValidInapp = false + Logger.common(message: "Something went wrong. Some validations are not passed.") + break variantsLoop + } + + let filteredLayers = filterLayers(layers) + if filteredLayers.isEmpty { + isValidInapp = false + break variantsLoop + } + + let backgroundModel = ContentBackground(layers: filteredLayers) + guard let elementsModel = convertElements(content.elements) else { + break variantsLoop + } + let contentModel = InappFormVariantContent(background: backgroundModel, elements: elementsModel) + let modalFormVariantModel = ModalFormVariant(content: contentModel) + do { + let mindboxFormVariant = try MindboxFormVariant(type: .modal, modalVariant: modalFormVariantModel) + variantsArray.append(mindboxFormVariant) + } catch { + print(error) + } + case .snackbar: + break + case .unknown: + continue + } + } + + if isValidInapp && !variantsArray.isEmpty { + let formModel = InAppForm(variants: variantsArray) + let inapp = InApp(id: inapp.id, sdkVersion: inapp.sdkVersion, targeting: inapp.targeting, form: formModel) + filteredInapps.append(inapp) + } + } + + return filteredInapps + } + + private func filterLayers(_ layers: [ContentBackgroundLayerDTO]) -> [ContentBackgroundLayer] { + var layersArray = [ContentBackgroundLayer]() + for layer in layers { + switch layer { + case .image(let imageContentBackgroundLayerDTO): + if let action = convertAction(imageContentBackgroundLayerDTO.action), + let source = convertSource(imageContentBackgroundLayerDTO.source) { + let imageLayer = ImageContentBackgroundLayer(action: action, source: source) + do { + let newLayer = try ContentBackgroundLayer(type: layer.layerType, imageLayer: imageLayer) + layersArray.append(newLayer) + } catch { + Logger.common(message: "filterLayers error: [\(error)]", level: .error, category: .inAppMessages) + } + } else { + return [] + } + case .unknown: + break + } + } + + return layersArray.filter { $0.layerType != .unknown } + } + + private func convertAction(_ action: ContentBackgroundLayerActionDTO?) -> ContentBackgroundLayerAction? { + guard let action = action, + action.actionType != .unknown else { + return nil + } + + switch action { + case .redirectUrl(let redirectUrlLayerAction): + if let value = redirectUrlLayerAction.value, let payload = redirectUrlLayerAction.intentPayload { + do { + let redirectUrlLayerActionModel = RedirectUrlLayerAction(intentPayload: payload, value: value) + return try ContentBackgroundLayerAction(type: .redirectUrl, redirectModel: redirectUrlLayerActionModel) + } catch { + Logger.common(message: "convertAction error: [\(error)]", level: .error, category: .inAppMessages) + } + } + case .unknown: + break + } + + return nil + } + + private func convertSource(_ source: ContentBackgroundLayerSourceDTO?) -> ContentBackgroundLayerSource? { + guard let source = source, + source.sourceType != .unknown else { + return nil + } + + switch source { + case .url(let urlLayerSource): + if let value = urlLayerSource.value { + do { + let urlLayerSourceModel = UrlLayerSource(value: value) + return try ContentBackgroundLayerSource(type: .url, urlModel: urlLayerSourceModel) + } catch { + Logger.common(message: "convertSource error: [\(error)]", level: .error, category: .inAppMessages) + } + } + case .unknown: + break + } + + return nil + } + + private func convertElements(_ elements: [ContentElementDTO]?) -> [ContentElement]? { + guard let elements = elements, !elements.isEmpty else { + return [] + } + + var filteredElements = [ContentElement]() + + elementsLoop: for element in elements { + if element.elementType == .unknown { + continue + } + + switch element { + case .closeButton(let closeButtonElement): + var customSize: ContentElementSize + if let sizeDTO = closeButtonElement.size?.element { + if sizeDTO.kind == .unknown { + customSize = Constants.elementSize + } else if let height = sizeDTO.height, + let width = sizeDTO.width, + height >= 0, + width >= 0 { + customSize = ContentElementSize(kind: sizeDTO.kind, width: width, height: height) + } else { + return nil + } + } else { + customSize = Constants.elementSize + } + + var customPosition: ContentElementPosition + if let positionDTO = closeButtonElement.position?.element, + let margin = positionDTO.margin?.element { + let marginRange: ClosedRange = 0...1 + var customMargin: ContentElementPositionMargin + if margin.kind == .unknown { + customMargin = Constants.elementPositionMargin + customPosition = ContentElementPosition(margin: customMargin) + } else if let top = margin.top, + let left = margin.left, + let right = margin.right, + let bottom = margin.bottom, + marginRange.contains(top), + marginRange.contains(left), + marginRange.contains(right), + marginRange.contains(bottom) { + customMargin = ContentElementPositionMargin(kind: margin.kind, top: top, right: right, left: left, bottom: bottom) + customPosition = ContentElementPosition(margin: customMargin) + } else { + return nil + } + } else { + customPosition = ContentElementPosition(margin: Constants.elementPositionMargin) + } + + do { + let customCloseButtonElement = CloseButtonElement(color: closeButtonElement.color?.element ?? Constants.defaultColor, + lineWidth: closeButtonElement.lineWidth?.element ?? Constants.lineWidth, + size: customSize, + position: customPosition) + let element = try ContentElement(type: .closeButton, closeButton: customCloseButtonElement) + filteredElements.append(element) + } catch { + Logger.common(message: "convertElements error: [\(error)]", level: .error, category: .inAppMessages) + } + case .unknown: + continue elementsLoop + } + } + + return filteredElements + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift index c3512e6a..7876a33c 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/VariantImageUrlExtractorService.swift @@ -17,18 +17,18 @@ class VariantImageUrlExtractorService: VariantImageUrlExtractorServiceProtocol { var urlString: [String] = [] let elements: [ContentBackgroundLayer] - + switch variant { case .modal(let modalModel): - elements = modalModel.content.background.layers.elements + elements = modalModel.content.background.layers case .snackbar(let snackbarModel): - elements = snackbarModel.content.background.layers.elements + elements = snackbarModel.content.background.layers case .unknown: return [] } - + extractImageURLs(from: elements, into: &urlString) - + return urlString } diff --git a/Mindbox/InAppMessages/Models/Config/ConfigResponse.swift b/Mindbox/InAppMessages/Models/Config/ConfigResponse.swift index 301bf2a4..d6f39ad4 100644 --- a/Mindbox/InAppMessages/Models/Config/ConfigResponse.swift +++ b/Mindbox/InAppMessages/Models/Config/ConfigResponse.swift @@ -9,7 +9,7 @@ import Foundation import MindboxLogger struct ConfigResponse: Decodable { - let inapps: FailableDecodableArray? + let inapps: FailableDecodableArray? let monitoring: Monitoring? let settings: Settings? let abtests: [ABTest]? @@ -21,7 +21,7 @@ struct ConfigResponse: Decodable { init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - inapps = try? container.decodeIfPresent(FailableDecodableArray.self, forKey: .inapps) + inapps = try? container.decodeIfPresent(FailableDecodableArray.self, forKey: .inapps) monitoring = ConfigResponse.decodeIfPresent(container, forKey: .monitoring, errorDesc: "Cannot decode Monitoring") settings = ConfigResponse.decodeIfPresent(container, forKey: .settings, errorDesc: "Cannot decode Settings") @@ -46,7 +46,7 @@ struct ConfigResponse: Decodable { } } - init(inapps: FailableDecodableArray? = nil, monitoring: Monitoring? = nil, settings: Settings? = nil, abtests: [ABTest]? = nil) { + init(inapps: FailableDecodableArray? = nil, monitoring: Monitoring? = nil, settings: Settings? = nil, abtests: [ABTest]? = nil) { self.inapps = inapps self.monitoring = monitoring self.settings = settings diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InAppModel.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InAppModel.swift index 90dfc1ac..2aaa51b5 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InAppModel.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InAppModel.swift @@ -8,28 +8,16 @@ import Foundation +struct InAppDTO: Decodable, Equatable { + let id: String + let sdkVersion: SdkVersion + let targeting: Targeting + let form: InAppFormDTO +} + struct InApp: Decodable, Equatable { let id: String let sdkVersion: SdkVersion let targeting: Targeting let form: InAppForm - - enum CodingKeys: String, CodingKey { - case id - case sdkVersion - case targeting - case form - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - id = try container.decode(String.self, forKey: .id) - sdkVersion = try container.decode(SdkVersion.self, forKey: .sdkVersion) - targeting = try container.decode(Targeting.self, forKey: .targeting) - form = try container.decode(InAppForm.self, forKey: .form) - - if !InappValidator().isValid(item: self) { - throw CustomDecodingError.decodingError("The inapp not passed validation. The inapp will be ignored.") - } - } } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappForm.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappForm.swift index af730dc1..64dd16d7 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappForm.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappForm.swift @@ -8,21 +8,10 @@ import Foundation +struct InAppFormDTO: Decodable, Equatable { + let variants: [MindboxFormVariantDTO]? +} + struct InAppForm: Decodable, Equatable { - let variants: FailableDecodableArray - - enum CodingKeys: String, CodingKey { - case variants - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let variants = try container.decode(FailableDecodableArray.self, forKey: .variants) - - if variants.elements.isEmpty { - throw CustomDecodingError.decodingError("Variants array cannot be empty.") - } - - self.variants = variants - } + let variants: [MindboxFormVariant] } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackground.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackground.swift index 66158672..3920b855 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackground.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackground.swift @@ -8,25 +8,10 @@ import Foundation +struct ContentBackgroundDTO: Decodable, Equatable { + let layers: [ContentBackgroundLayerDTO]? +} + struct ContentBackground: Decodable, Equatable { - let layers: FailableDecodableArray - - enum CodingKeys: String, CodingKey { - case layers - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let layers = try container.decode(FailableDecodableArray.self, forKey: .layers) - - if layers.elements.isEmpty { - throw DecodingError.dataCorruptedError( - forKey: .layers, - in: container, - debugDescription: "Layers cannot be empty." - ) - } - - self.layers = layers - } + let layers: [ContentBackgroundLayer] } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayer.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayer.swift index 6e285c81..c0c3a907 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayer.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayer.swift @@ -21,6 +21,59 @@ enum ContentBackgroundLayerType: String, Decodable { } } +enum ContentBackgroundLayerDTO: Decodable, Hashable, Equatable { + case image(ImageContentBackgroundLayerDTO) + case unknown + + enum CodingKeys: String, CodingKey { + case type = "$type" + } + + static func == (lhs: ContentBackgroundLayerDTO, rhs: ContentBackgroundLayerDTO) -> Bool { + switch (lhs, rhs) { + case (.image, .image): return true + case (.unknown, .unknown): return true + default: return false + } + } + + func hash(into hasher: inout Hasher) { + switch self { + case .image: hasher.combine("image") + case .unknown: hasher.combine("unknown") + } + } + + init(from decoder: Decoder) throws { + let container: KeyedDecodingContainer = try decoder.container( + keyedBy: CodingKeys.self) + guard let type = try? container.decode(ContentBackgroundLayerType.self, forKey: .type) else { + throw CustomDecodingError.decodingError("The layer type could not be decoded. The layer will be ignored.") + } + + let layerContainer: SingleValueDecodingContainer = try decoder.singleValueContainer() + + switch type { + case .image: + let imageLayer = try layerContainer.decode(ImageContentBackgroundLayerDTO.self) + self = .image(imageLayer) + case .unknown: + self = .unknown + } + } +} + +extension ContentBackgroundLayerDTO { + var layerType: ContentBackgroundLayerType { + switch self { + case .image: + return .image + case .unknown: + return .unknown + } + } +} + enum ContentBackgroundLayer: Decodable, Hashable, Equatable { case image(ImageContentBackgroundLayer) case unknown @@ -58,7 +111,7 @@ enum ContentBackgroundLayer: Decodable, Hashable, Equatable { let imageLayer = try layerContainer.decode(ImageContentBackgroundLayer.self) self = .image(imageLayer) case .unknown: - throw CustomDecodingError.unknownType("The layer type is unrecognized. The action will be ignored.") + self = .unknown } } } @@ -73,3 +126,17 @@ extension ContentBackgroundLayer { } } } + +extension ContentBackgroundLayer { + init(type: ContentBackgroundLayerType, imageLayer: ImageContentBackgroundLayer? = nil) throws { + switch type { + case .image: + guard let imageLayer = imageLayer else { + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .image(imageLayer) + case .unknown: + self = .unknown + } + } +} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/Actions/RedirectUrlLayerAction.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/Actions/RedirectUrlLayerAction.swift index 2ad5caac..6d8a76a2 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/Actions/RedirectUrlLayerAction.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/Actions/RedirectUrlLayerAction.swift @@ -8,8 +8,12 @@ import Foundation +struct RedirectUrlLayerActionDTO: ContentBackgroundLayerActionProtocol { + let intentPayload: String? + let value: String? +} + struct RedirectUrlLayerAction: ContentBackgroundLayerActionProtocol { let intentPayload: String let value: String } - diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/ContentBackgroundLayerAction.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/ContentBackgroundLayerAction.swift index e1341d29..86925131 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/ContentBackgroundLayerAction.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundLayerAction/ContentBackgroundLayerAction.swift @@ -21,6 +21,59 @@ enum ContentBackgroundLayerActionType: String, Decodable { } } +enum ContentBackgroundLayerActionDTO: Decodable, Hashable, Equatable { + case redirectUrl(RedirectUrlLayerActionDTO) + case unknown + + enum CodingKeys: String, CodingKey { + case type = "$type" + } + + static func == (lhs: ContentBackgroundLayerActionDTO, rhs: ContentBackgroundLayerActionDTO) -> Bool { + switch (lhs, rhs) { + case (.redirectUrl, .redirectUrl): return true + case (.unknown, .unknown): return true + default: return false + } + } + + func hash(into hasher: inout Hasher) { + switch self { + case .redirectUrl: hasher.combine("redirectUrl") + case .unknown: hasher.combine("unknown") + } + } + + init(from decoder: Decoder) throws { + let container: KeyedDecodingContainer = try decoder.container( + keyedBy: CodingKeys.self) + guard let type = try? container.decode(ContentBackgroundLayerActionType.self, forKey: .type) else { + throw CustomDecodingError.decodingError("The action type could not be decoded. The action will be ignored.") + } + + let actionContainer: SingleValueDecodingContainer = try decoder.singleValueContainer() + + switch type { + case .redirectUrl: + let redirectUrlAction = try actionContainer.decode(RedirectUrlLayerActionDTO.self) + self = .redirectUrl(redirectUrlAction) + case .unknown: + self = .unknown + } + } +} + +extension ContentBackgroundLayerActionDTO { + var actionType: ContentBackgroundLayerActionType { + switch self { + case .redirectUrl: + return .redirectUrl + case .unknown: + return .unknown + } + } +} + enum ContentBackgroundLayerAction: Decodable, Hashable, Equatable { case redirectUrl(RedirectUrlLayerAction) case unknown @@ -58,7 +111,7 @@ enum ContentBackgroundLayerAction: Decodable, Hashable, Equatable { let redirectUrlAction = try actionContainer.decode(RedirectUrlLayerAction.self) self = .redirectUrl(redirectUrlAction) case .unknown: - throw CustomDecodingError.unknownType("The action type could not be decoded. The action will be ignored.") + self = .unknown } } } @@ -73,3 +126,17 @@ extension ContentBackgroundLayerAction { } } } + +extension ContentBackgroundLayerAction { + init(type: ContentBackgroundLayerActionType, redirectModel: RedirectUrlLayerAction? = nil) throws { + switch type { + case .redirectUrl: + guard let redirectModel = redirectModel else { + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .redirectUrl(redirectModel) + case .unknown: + self = .unknown + } + } +} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/ContentBackgroundLayerSource.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/ContentBackgroundLayerSource.swift index 5050aea2..8f0c58de 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/ContentBackgroundLayerSource.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/ContentBackgroundLayerSource.swift @@ -22,6 +22,59 @@ enum ContentBackgroundLayerSourceType: String, Decodable { } } +enum ContentBackgroundLayerSourceDTO: Decodable, Hashable, Equatable { + case url(UrlLayerSourceDTO) + case unknown + + enum CodingKeys: String, CodingKey { + case type = "$type" + } + + static func == (lhs: ContentBackgroundLayerSourceDTO, rhs: ContentBackgroundLayerSourceDTO) -> Bool { + switch (lhs, rhs) { + case (.url, .url): return true + case (.unknown, .unknown): return true + default: return false + } + } + + func hash(into hasher: inout Hasher) { + switch self { + case .url: hasher.combine("url") + case .unknown: hasher.combine("unknown") + } + } + + init(from decoder: Decoder) throws { + let container: KeyedDecodingContainer = try decoder.container( + keyedBy: CodingKeys.self) + guard let type = try? container.decode(ContentBackgroundLayerSourceType.self, forKey: .type) else { + throw CustomDecodingError.decodingError("The source type could not be decoded. The source will be ignored.") + } + + let sourceContainer: SingleValueDecodingContainer = try decoder.singleValueContainer() + + switch type { + case .url: + let urlSource = try sourceContainer.decode(UrlLayerSourceDTO.self) + self = .url(urlSource) + case .unknown: + self = .unknown + } + } +} + +extension ContentBackgroundLayerSourceDTO { + var sourceType: ContentBackgroundLayerSourceType { + switch self { + case .url: + return .url + case .unknown: + return .unknown + } + } +} + enum ContentBackgroundLayerSource: Decodable, Hashable, Equatable { case url(UrlLayerSource) case unknown @@ -59,7 +112,7 @@ enum ContentBackgroundLayerSource: Decodable, Hashable, Equatable { let urlSource = try sourceContainer.decode(UrlLayerSource.self) self = .url(urlSource) case .unknown: - throw CustomDecodingError.unknownType("The source type could not be decoded. The source will be ignored.") + self = .unknown } } } @@ -74,3 +127,17 @@ extension ContentBackgroundLayerSource { } } } + +extension ContentBackgroundLayerSource { + init(type: ContentBackgroundLayerSourceType, urlModel: UrlLayerSource? = nil) throws { + switch type { + case .url: + guard let urlModel = urlModel else { + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .url(urlModel) + case .unknown: + self = .unknown + } + } +} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/Sources/UrlLayerSource.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/Sources/UrlLayerSource.swift index db3c920f..7bf0df5d 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/Sources/UrlLayerSource.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/ContentBackgroundSource/Sources/UrlLayerSource.swift @@ -8,6 +8,10 @@ import Foundation +struct UrlLayerSourceDTO: ContentBackgroundLayerSourceProtocol { + let value: String? +} + struct UrlLayerSource: ContentBackgroundLayerSourceProtocol { let value: String } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/Layers/ImageContentBackgroundLayer.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/Layers/ImageContentBackgroundLayer.swift index e55edf39..dca5190f 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/Layers/ImageContentBackgroundLayer.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentBackground/ContentBackgroundLayer/Layers/ImageContentBackgroundLayer.swift @@ -8,6 +8,12 @@ import Foundation +struct ImageContentBackgroundLayerDTO: ContentBackgroundLayerProtocol { + let action: ContentBackgroundLayerActionDTO? + let source: ContentBackgroundLayerSourceDTO? +} + + struct ImageContentBackgroundLayer: ContentBackgroundLayerProtocol { let action: ContentBackgroundLayerAction let source: ContentBackgroundLayerSource diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElement.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElement.swift index 1a5eac1b..8c802b9d 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElement.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElement.swift @@ -21,6 +21,59 @@ enum ContentElementType: String, Decodable { } } +enum ContentElementDTO: Decodable, Hashable, Equatable { + case closeButton(CloseButtonElementDTO) + case unknown + + enum CodingKeys: String, CodingKey { + case type = "$type" + } + + static func == (lhs: ContentElementDTO, rhs: ContentElementDTO) -> Bool { + switch (lhs, rhs) { + case (.closeButton, .closeButton): return true + case (.unknown, .unknown): return true + default: return false + } + } + + func hash(into hasher: inout Hasher) { + switch self { + case .closeButton: hasher.combine("closeButton") + case .unknown: hasher.combine("unknown") + } + } + + init(from decoder: Decoder) throws { + let container: KeyedDecodingContainer = try decoder.container( + keyedBy: CodingKeys.self) + guard let type = try? container.decode(ContentElementType.self, forKey: .type) else { + throw CustomDecodingError.decodingError("The variant type could not be decoded. The variant will be ignored.") + } + + let elementContainer: SingleValueDecodingContainer = try decoder.singleValueContainer() + + switch type { + case .closeButton: + let closeButtonElement = try elementContainer.decode(CloseButtonElementDTO.self) + self = .closeButton(closeButtonElement) + case .unknown: + self = .unknown + } + } +} + +extension ContentElementDTO { + var elementType: ContentElementType { + switch self { + case .closeButton: + return .closeButton + case .unknown: + return .unknown + } + } +} + enum ContentElement: Decodable, Hashable, Equatable { case closeButton(CloseButtonElement) case unknown @@ -58,7 +111,7 @@ enum ContentElement: Decodable, Hashable, Equatable { let closeButtonElement = try elementContainer.decode(CloseButtonElement.self) self = .closeButton(closeButtonElement) case .unknown: - throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + self = .unknown } } } @@ -73,3 +126,17 @@ extension ContentElement { } } } + +extension ContentElement { + init(type: ContentElementType, closeButton: CloseButtonElement? = nil) throws { + switch type { + case .closeButton: + guard let closeButtonModel = closeButton else { + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .closeButton(closeButtonModel) + case .unknown: + self = .unknown + } + } +} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift index 1358a12b..c40ba94b 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift @@ -8,6 +8,11 @@ import Foundation +struct ContentElementPositionDTO: Decodable, Equatable { + let margin: FailableDecodable? +} + + struct ContentElementPosition: Decodable, Equatable { - let margin: FailableDecodable? + let margin: ContentElementPositionMargin } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift index 50addb0d..c1d8cff6 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift @@ -8,40 +8,18 @@ import Foundation -struct ContentElementPositionMargin: Decodable, Equatable { +struct ContentElementPositionMarginDTO: Decodable, Equatable { let kind: PositionMarginKind let top: Double? let right: Double? let left: Double? let bottom: Double? - - enum CodingKeys: CodingKey { - case kind - case top - case right - case left - case bottom - } - - init(from decoder: Decoder) throws { - let container: KeyedDecodingContainer = try decoder.container(keyedBy: ContentElementPositionMargin.CodingKeys.self) - - self.kind = try container.decode(PositionMarginKind.self, forKey: ContentElementPositionMargin.CodingKeys.kind) - self.top = try container.decodeIfPresentSafely(Double.self, forKey: ContentElementPositionMargin.CodingKeys.top) - self.right = try container.decodeIfPresentSafely(Double.self, forKey: ContentElementPositionMargin.CodingKeys.right) - self.left = try container.decodeIfPresentSafely(Double.self, forKey: ContentElementPositionMargin.CodingKeys.left) - self.bottom = try container.decodeIfPresentSafely(Double.self, forKey: ContentElementPositionMargin.CodingKeys.bottom) - - if !ContentElementPositionMarginValidator().isValid(item: self) { - throw CustomDecodingError.decodingError("ContentElementPositionMargin not passed validation. It will be ignored.") - } - } - - init(kind: PositionMarginKind, top: Double? = nil, right: Double? = nil, left: Double? = nil, bottom: Double? = nil) { - self.kind = kind - self.top = top - self.right = right - self.left = left - self.bottom = bottom - } +} + +struct ContentElementPositionMargin: Decodable, Equatable { + let kind: PositionMarginKind + let top: Double + let right: Double + let left: Double + let bottom: Double } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSize.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSize.swift index 189d4468..d695d133 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSize.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSize.swift @@ -8,31 +8,14 @@ import Foundation +struct ContentElementSizeDTO: Decodable, Equatable { + let kind: ContentElementSizeKind + let width: Double? + let height: Double? +} + struct ContentElementSize: Decodable, Equatable { let kind: ContentElementSizeKind let width: Double let height: Double - - enum CodingKeys: String, CodingKey { - case kind - case width - case height - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - kind = try container.decode(ContentElementSizeKind.self, forKey: .kind) - width = try container.decode(Double.self, forKey: .width) - height = try container.decode(Double.self, forKey: .height) - - if !ContentElementSizeValidator().isValid(item: self) { - throw CustomDecodingError.decodingError("Content element size validation not passed.") - } - } - - init(kind: ContentElementSizeKind, width: Double, height: Double) { - self.kind = kind - self.width = width - self.height = height - } } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift index 43ca3b35..4cb1fb5d 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift @@ -8,9 +8,16 @@ import Foundation +struct CloseButtonElementDTO: ContentElementProtocol { + let color: FailableDecodable? + let lineWidth: FailableDecodable? + let size: FailableDecodable? + let position: FailableDecodable? +} + struct CloseButtonElement: ContentElementProtocol { - let color: String? - let lineWidth: Int? - let size: FailableDecodable? - let position: ContentElementPosition? + let color: String + let lineWidth: Int + let size: ContentElementSize + let position: ContentElementPosition } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/InappFormVariantContent.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/InappFormVariantContent.swift index 03ad7cf5..6db2730f 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/InappFormVariantContent.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/InappFormVariantContent.swift @@ -8,7 +8,12 @@ import Foundation +struct InappFormVariantContentDTO: Decodable, Equatable { + let background: ContentBackgroundDTO? + let elements: [ContentElementDTO]? +} + struct InappFormVariantContent: Decodable, Equatable { let background: ContentBackground - let elements: FailableDecodableArray? + let elements: [ContentElement]? } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/ModalFormVariant.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/ModalFormVariant.swift index a37bb2e9..75438e65 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/ModalFormVariant.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/ModalFormVariant.swift @@ -7,6 +7,10 @@ import Foundation +struct ModalFormVariantDTO: iFormVariant, Decodable, Equatable { + let content: InappFormVariantContentDTO? +} + struct ModalFormVariant: iFormVariant, Decodable, Equatable { let content: InappFormVariantContent } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift index 368f0a3f..538b5af6 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift @@ -22,6 +22,54 @@ enum MindboxFormVariantType: String, Decodable { } } +enum MindboxFormVariantDTO: Decodable, Hashable, Equatable { + case modal(ModalFormVariantDTO) + case snackbar(SnackbarFormVariant) + case unknown + + enum CodingKeys: String, CodingKey { + case type = "$type" + } + + static func == (lhs: MindboxFormVariantDTO, rhs: MindboxFormVariantDTO) -> Bool { + switch (lhs, rhs) { + case (.modal, .modal): return true + case (.snackbar, .snackbar): return true + case (.unknown, .unknown): return true + default: return false + } + } + + func hash(into hasher: inout Hasher) { + switch self { + case .modal: hasher.combine("modal") + case .snackbar: hasher.combine("snackbar") + case .unknown: hasher.combine("unknown") + } + } + + init(from decoder: Decoder) throws { + let container: KeyedDecodingContainer = try decoder.container( + keyedBy: CodingKeys.self) + guard let type = try? container.decode(MindboxFormVariantType.self, forKey: .type) else { + throw CustomDecodingError.decodingError("The variant type could not be decoded. The variant will be ignored.") + } + + let variantContainer: SingleValueDecodingContainer = try decoder.singleValueContainer() + + switch type { + case .modal: + let modalVariant = try variantContainer.decode(ModalFormVariantDTO.self) + self = .modal(modalVariant) + case .snackbar: + let snackbarVariant = try variantContainer.decode(SnackbarFormVariant.self) + self = .snackbar(snackbarVariant) + case .unknown: + self = .unknown + } + } +} + enum MindboxFormVariant: Decodable, Hashable, Equatable { case modal(ModalFormVariant) case snackbar(SnackbarFormVariant) @@ -65,7 +113,29 @@ enum MindboxFormVariant: Decodable, Hashable, Equatable { let snackbarVariant = try variantContainer.decode(SnackbarFormVariant.self) self = .snackbar(snackbarVariant) case .unknown: + self = .unknown + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + } +} + +extension MindboxFormVariant { + init(type: MindboxFormVariantType, modalVariant: ModalFormVariant? = nil, snackbarVariant: SnackbarFormVariant? = nil) throws { + switch type { + case .modal: + guard let modalVariant = modalVariant else { + throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .modal(modalVariant) + + case .snackbar: + guard let snackbarVariant = snackbarVariant else { throw CustomDecodingError.unknownType("The variant type could not be decoded. The variant will be ignored.") + } + self = .snackbar(snackbarVariant) + + case .unknown: + self = .unknown } } } diff --git a/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift b/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift index 24d861b9..0f4eed2a 100644 --- a/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/CommonViews/ElementFactory/CloseButtonFactory/CloseButtonElementFactory.swift @@ -11,7 +11,7 @@ import UIKit class CloseButtonElementFactory: ElementFactory { func create(from element: ContentElement, with controller: GestureHandler) -> UIView? { if case .closeButton(let closeButtonElement) = element { - let color = closeButtonElement.color?.isHexValid() ?? false ? closeButtonElement.color : nil + let color = closeButtonElement.color.isHexValid() ? closeButtonElement.color : nil let closeButton = CrossView(lineColorHex: color, lineWidth: closeButtonElement.lineWidth) closeButton.isUserInteractionEnabled = true let closeRecognizer = UILongPressGestureRecognizer(target: controller, action: #selector(controller.onCloseButton)) @@ -26,9 +26,9 @@ class CloseButtonElementFactory: ElementFactory { func setupConstraints(for view: UIView, from element: ContentElement, in parentView: UIView) { if case .closeButton(let closeButtonElement) = element { - let size = closeButtonElement.size?.element ?? ContentElementSize(kind: .dp, width: 24, height: 24) - let top = closeButtonElement.position?.margin?.element?.top ?? 0.02 - let right = closeButtonElement.position?.margin?.element?.right ?? 0.02 + let size = closeButtonElement.size + let top = closeButtonElement.position.margin.top + let right = closeButtonElement.position.margin.right let horizontalOffset = (parentView.frame.width - CGFloat(size.width)) * right let verticalOffset = (parentView.frame.height - CGFloat(size.height)) * top diff --git a/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift b/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift index a6e29f51..40702691 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ModalView/ModalViewController.swift @@ -108,7 +108,7 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, } private func setupLayers() { - let layers = model.content.background.layers.elements + let layers = model.content.background.layers for layer in layers { if let factory = layersFactories[layer.layerType] { if case .image(let imageContentBackgroundLayer) = layer { @@ -126,11 +126,11 @@ final class ModalViewController: UIViewController, InappViewControllerProtocol, } private func setupElements() { - guard let elements = model.content.elements?.elements, + guard let elements = model.content.elements, let inappView = layers.first(where: { $0 is InAppImageOnlyView }) else { return } - + for element in elements { if let factory = elementFactories[element.elementType] { let elementView = factory.create(from: element, with: self) diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift index b8991ff3..83d13bbd 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift @@ -108,11 +108,11 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private func setupLayers() { - let layers = model.content.background.layers.elements + let layers = model.content.background.layers guard let snackbarView = snackbarView else { return } - + for layer in layers { if let factory = layersFactories[layer.layerType] { if case .image(let imageContentBackgroundLayer) = layer { From a7dc23743514ca7b98b3f7ce9bd745079164011d Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Thu, 7 Sep 2023 14:31:25 +0600 Subject: [PATCH 07/28] MBX-2792 Different services --- Mindbox.xcodeproj/project.pbxproj | 68 ++++-- Mindbox/DI/DependencyContainer.swift | 1 + Mindbox/DI/DependencyProvider.swift | 15 +- .../InAppConfigutationMapper.swift | 9 +- .../ContentPositionFilter.swift | 62 +++++ .../ElementsFiter/ElementsFilter.swift | 62 +++++ .../ElementsPositionFilter.swift | 53 ++++ .../ElementsFiter/ElementsSizeFilter.swift | 39 +++ .../InappFilterService/InappFilter.swift | 50 ++++ .../InappsFilterService.swift | 229 ------------------ .../LayersFilter/LayerActionFilter.swift | 34 +++ .../LayersFilter/LayersFilter.swift | 50 ++++ .../LayersFilter/LayersSourceFilter.swift | 34 +++ .../InappFilterService/VariantsFilter.swift | 78 ++++++ .../ContentElementPosition.swift | 2 +- .../ContentElementPositionMargin.swift | 15 +- .../PositionMarginKind.swift | 20 -- .../Elements/CloseButtonElement.swift | 4 +- .../ContentPosition/ContentPosition.swift | 19 +- .../ContentPositionGravity.swift | 67 +++-- .../ContentPositionMargin.swift | 49 ++-- .../SnackbarFormVariantContent.swift | 10 +- .../Variants/SnackbarFormVariant.swift | 4 + .../InappFormVariant/iFormVariant.swift | 4 +- .../SnackbarView/SnackbarViewController.swift | 9 +- .../ViewFactory/SnackbarViewFactory.swift | 2 +- Mindbox/Info.plist | 2 +- 27 files changed, 625 insertions(+), 366 deletions(-) create mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift create mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift create mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift create mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift create mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappFilter.swift delete mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappsFilterService.swift create mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayerActionFilter.swift create mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift create mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersSourceFilter.swift create mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift delete mode 100644 Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/PositionMarginKind/PositionMarginKind.swift diff --git a/Mindbox.xcodeproj/project.pbxproj b/Mindbox.xcodeproj/project.pbxproj index 94cffb2f..f9a0f935 100644 --- a/Mindbox.xcodeproj/project.pbxproj +++ b/Mindbox.xcodeproj/project.pbxproj @@ -312,7 +312,6 @@ F331DCC12A80993600222120 /* ContentElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DC9B2A80993600222120 /* ContentElement.swift */; }; F331DCC32A80993600222120 /* ContentElementPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DC9F2A80993600222120 /* ContentElementPosition.swift */; }; F331DCC42A80993600222120 /* ContentElementPositionMargin.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCA12A80993600222120 /* ContentElementPositionMargin.swift */; }; - F331DCC52A80993600222120 /* PositionMarginKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCA32A80993600222120 /* PositionMarginKind.swift */; }; F331DCC62A80993600222120 /* ContentElementPositionMarginValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCA42A80993600222120 /* ContentElementPositionMarginValidator.swift */; }; F331DCC82A80993600222120 /* ContentBackgroundLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCA82A80993600222120 /* ContentBackgroundLayer.swift */; }; F331DCCB2A80993600222120 /* ContentBackgroundLayerAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCAD2A80993600222120 /* ContentBackgroundLayerAction.swift */; }; @@ -368,7 +367,15 @@ F3482F2A2A65DCFC002A41EC /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3482F292A65DCFC002A41EC /* String+Extensions.swift */; }; F37613E12A6A8CFF009F2EE4 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F37613E02A6A8CFF009F2EE4 /* UIColor+Extensions.swift */; }; F39116EE2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116ED2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift */; }; - F39116F22AA9AF0E00852298 /* InappsFilterService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116F12AA9AF0E00852298 /* InappsFilterService.swift */; }; + F39116F52AA9AF7A00852298 /* InappFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116F42AA9AF7A00852298 /* InappFilter.swift */; }; + F39116F82AA9B04E00852298 /* VariantsFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116F72AA9B04E00852298 /* VariantsFilter.swift */; }; + F39116FA2AA9B32E00852298 /* LayersFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116F92AA9B32E00852298 /* LayersFilter.swift */; }; + F39116FC2AA9B4A200852298 /* LayerActionFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116FB2AA9B4A200852298 /* LayerActionFilter.swift */; }; + F39116FE2AA9B54B00852298 /* LayersSourceFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39116FD2AA9B54B00852298 /* LayersSourceFilter.swift */; }; + F39117012AA9B68B00852298 /* ElementsFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39117002AA9B68B00852298 /* ElementsFilter.swift */; }; + F39117032AA9B79100852298 /* ElementsSizeFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39117022AA9B79100852298 /* ElementsSizeFilter.swift */; }; + F39117052AA9B92500852298 /* ElementsPositionFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39117042AA9B92500852298 /* ElementsPositionFilter.swift */; }; + F39117072AA9C69A00852298 /* ContentPositionFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39117062AA9C69A00852298 /* ContentPositionFilter.swift */; }; F397EEAD2A4456C300D48CEC /* ProtocolError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEAC2A4456C300D48CEC /* ProtocolError.swift */; }; F397EEAF2A4456FD00D48CEC /* MindboxError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEAE2A4456FD00D48CEC /* MindboxError.swift */; }; F397EEB12A44571300D48CEC /* UnknownDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEB02A44571300D48CEC /* UnknownDecodable.swift */; }; @@ -769,7 +776,6 @@ F331DC9B2A80993600222120 /* ContentElement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElement.swift; sourceTree = ""; }; F331DC9F2A80993600222120 /* ContentElementPosition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElementPosition.swift; sourceTree = ""; }; F331DCA12A80993600222120 /* ContentElementPositionMargin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElementPositionMargin.swift; sourceTree = ""; }; - F331DCA32A80993600222120 /* PositionMarginKind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PositionMarginKind.swift; sourceTree = ""; }; F331DCA42A80993600222120 /* ContentElementPositionMarginValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElementPositionMarginValidator.swift; sourceTree = ""; }; F331DCA82A80993600222120 /* ContentBackgroundLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBackgroundLayer.swift; sourceTree = ""; }; F331DCAD2A80993600222120 /* ContentBackgroundLayerAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBackgroundLayerAction.swift; sourceTree = ""; }; @@ -825,7 +831,15 @@ F3482F292A65DCFC002A41EC /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = ""; }; F37613E02A6A8CFF009F2EE4 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = ""; }; F39116ED2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariantImageUrlExtractorServiceTests.swift; sourceTree = ""; }; - F39116F12AA9AF0E00852298 /* InappsFilterService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InappsFilterService.swift; sourceTree = ""; }; + F39116F42AA9AF7A00852298 /* InappFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InappFilter.swift; sourceTree = ""; }; + F39116F72AA9B04E00852298 /* VariantsFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariantsFilter.swift; sourceTree = ""; }; + F39116F92AA9B32E00852298 /* LayersFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayersFilter.swift; sourceTree = ""; }; + F39116FB2AA9B4A200852298 /* LayerActionFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayerActionFilter.swift; sourceTree = ""; }; + F39116FD2AA9B54B00852298 /* LayersSourceFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LayersSourceFilter.swift; sourceTree = ""; }; + F39117002AA9B68B00852298 /* ElementsFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementsFilter.swift; sourceTree = ""; }; + F39117022AA9B79100852298 /* ElementsSizeFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementsSizeFilter.swift; sourceTree = ""; }; + F39117042AA9B92500852298 /* ElementsPositionFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementsPositionFilter.swift; sourceTree = ""; }; + F39117062AA9C69A00852298 /* ContentPositionFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPositionFilter.swift; sourceTree = ""; }; F397EEAC2A4456C300D48CEC /* ProtocolError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolError.swift; sourceTree = ""; }; F397EEAE2A4456FD00D48CEC /* MindboxError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MindboxError.swift; sourceTree = ""; }; F397EEB02A44571300D48CEC /* UnknownDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnknownDecodable.swift; sourceTree = ""; }; @@ -2031,20 +2045,11 @@ isa = PBXGroup; children = ( F331DCA12A80993600222120 /* ContentElementPositionMargin.swift */, - F331DCA22A80993600222120 /* PositionMarginKind */, F331DCA42A80993600222120 /* ContentElementPositionMarginValidator.swift */, ); path = ContentElementPositionMargin; sourceTree = ""; }; - F331DCA22A80993600222120 /* PositionMarginKind */ = { - isa = PBXGroup; - children = ( - F331DCA32A80993600222120 /* PositionMarginKind.swift */, - ); - path = PositionMarginKind; - sourceTree = ""; - }; F331DCA62A80993600222120 /* ContentBackground */ = { isa = PBXGroup; children = ( @@ -2331,11 +2336,35 @@ F39116F32AA9AF3C00852298 /* InappFilterService */ = { isa = PBXGroup; children = ( - F39116F12AA9AF0E00852298 /* InappsFilterService.swift */, + F39116F42AA9AF7A00852298 /* InappFilter.swift */, + F39116F72AA9B04E00852298 /* VariantsFilter.swift */, + F39116FF2AA9B67E00852298 /* LayersFilter */, + F39117082AAA48CF00852298 /* ElementsFiter */, + F39117062AA9C69A00852298 /* ContentPositionFilter.swift */, ); path = InappFilterService; sourceTree = ""; }; + F39116FF2AA9B67E00852298 /* LayersFilter */ = { + isa = PBXGroup; + children = ( + F39116F92AA9B32E00852298 /* LayersFilter.swift */, + F39116FB2AA9B4A200852298 /* LayerActionFilter.swift */, + F39116FD2AA9B54B00852298 /* LayersSourceFilter.swift */, + ); + path = LayersFilter; + sourceTree = ""; + }; + F39117082AAA48CF00852298 /* ElementsFiter */ = { + isa = PBXGroup; + children = ( + F39117002AA9B68B00852298 /* ElementsFilter.swift */, + F39117022AA9B79100852298 /* ElementsSizeFilter.swift */, + F39117042AA9B92500852298 /* ElementsPositionFilter.swift */, + ); + path = ElementsFiter; + sourceTree = ""; + }; F397EEAB2A4456A900D48CEC /* MindboxError */ = { isa = PBXGroup; children = ( @@ -2762,6 +2791,7 @@ 33072F442664CC6C001F1AB2 /* IssuedPointOfContactResponse.swift in Sources */, A17958762978AEC600609E91 /* OrTargetingChecker.swift in Sources */, 334F3AE1264C199900A6AC00 /* PromoCodeRequest.swift in Sources */, + F39116F52AA9AF7A00852298 /* InappFilter.swift in Sources */, F331DD032A83A56500222120 /* ModalPresentationStrategy.swift in Sources */, A17958792978AEC600609E91 /* GeoTargetingChecker.swift in Sources */, 33BEE80D2681EB7700993720 /* NotificationDecoder.swift in Sources */, @@ -2832,16 +2862,16 @@ F39B67A22A3C6AF4005C0CCA /* SegmentationService.swift in Sources */, 334F3AEC264C199900A6AC00 /* RequestedPromotionRequest.swift in Sources */, 84DEE8B125CC042A00C98CC7 /* MBDatabaseError.swift in Sources */, + F39117072AA9C69A00852298 /* ContentPositionFilter.swift in Sources */, A179587C2978AED800609E91 /* GeoTargeting.swift in Sources */, 3333C1E12681EA4D00B60D84 /* NotificationsPayloads.swift in Sources */, - F39116F22AA9AF0E00852298 /* InappsFilterService.swift in Sources */, 334F3AE7264C199900A6AC00 /* CatalogProductListRequest.swift in Sources */, F331DCC02A80993600222120 /* ContentElementSizeType.swift in Sources */, - F331DCC52A80993600222120 /* PositionMarginKind.swift in Sources */, F331DD0B2A83A56500222120 /* CrossView.swift in Sources */, B3A625562689FDD400B6A3B7 /* BalanceResponse.swift in Sources */, 6FDD1459266F7CB700A50C35 /* ContentResponse.swift in Sources */, F37613E12A6A8CFF009F2EE4 /* UIColor+Extensions.swift in Sources */, + F39116F82AA9B04E00852298 /* VariantsFilter.swift in Sources */, F3A8B9582A389D9D00E9C055 /* GeoService.swift in Sources */, 334F3AE2264C199900A6AC00 /* CouponRequest.swift in Sources */, F3A8B9942A3A409C00E9C055 /* Validator.swift in Sources */, @@ -2901,6 +2931,7 @@ 337A47362654F995000DC613 /* OperationBodyRequest.swift in Sources */, 9BC24E6F28F694EA00C2619C /* SDKVersionProvider.swift in Sources */, 6FDD144D266F7C6600A50C35 /* AmountTypeResponse.swift in Sources */, + F39117012AA9B68B00852298 /* ElementsFilter.swift in Sources */, 6FDD1461266F7CE300A50C35 /* DiscountAmountTypeResponse.swift in Sources */, 6FDD144F266F7C7000A50C35 /* UsedResponse.swift in Sources */, 330D8CCD26579581005106D5 /* Channel.swift in Sources */, @@ -2916,6 +2947,7 @@ A1D017F22976CC9400CD9F99 /* SegmentTargeting.swift in Sources */, F331DD072A83A56500222120 /* CloseButtonElementFactory.swift in Sources */, 9BC24E7428F6953D00C2619C /* InAppConfigurationAPI.swift in Sources */, + F39117032AA9B79100852298 /* ElementsSizeFilter.swift in Sources */, F397EEB32A44572400D48CEC /* ValidationError.swift in Sources */, A192787229D442D900CDB53D /* ProductSegmentChecker.swift in Sources */, A153E03D29BAFEC1003C34D4 /* CustomOperationChecker.swift in Sources */, @@ -2939,6 +2971,7 @@ A15D701629AF810E007131E7 /* SDKLogsRequest.swift in Sources */, 33072F362664C4D7001F1AB2 /* RecommendationRequest.swift in Sources */, 84DC49CC25D1832300D5D758 /* EventWrapper.swift in Sources */, + F39116FA2AA9B32E00852298 /* LayersFilter.swift in Sources */, 317054C425AEF88E00AE624C /* DependencyProvider.swift in Sources */, 84DC4A0225D27D0500D5D758 /* UNAuthorizationStatusProviding.swift in Sources */, 6FDD1465266F7CFE00A50C35 /* ItemProductResponse.swift in Sources */, @@ -2954,6 +2987,7 @@ 334F3AF0264C199900A6AC00 /* DiscountRequest.swift in Sources */, F331DD1F2A84B62200222120 /* RedirectUrlLayerAction.swift in Sources */, 847F57FE25C88BB700147A9A /* HTTPMethod.swift in Sources */, + F39117052AA9B92500852298 /* ElementsPositionFilter.swift in Sources */, 334F3AE9264C199900A6AC00 /* OrderRequest.swift in Sources */, 9B24FAAC28C74B8300F10B5D /* InAppConfigurationRepository.swift in Sources */, F33608122A8A151C00C7C9B7 /* ContentPosition.swift in Sources */, @@ -2968,6 +3002,7 @@ 334F3AEF264C199900A6AC00 /* DiscountPromoCodeRequest.swift in Sources */, 84F5655E2628434D00269FD6 /* TrackVisitManager.swift in Sources */, F397EEAF2A4456FD00D48CEC /* MindboxError.swift in Sources */, + F39116FC2AA9B4A200852298 /* LayerActionFilter.swift in Sources */, 3337E6A52660D878006949EB /* OperationResponse.swift in Sources */, B3F4F98E268EEB4B0092EC3C /* LimitBenefitsResponse.swift in Sources */, 9B4F9DF928D088A9002C9CF0 /* InAppConfig.swift in Sources */, @@ -3026,6 +3061,7 @@ 317054CB25AF189800AE624C /* PersistenceStorage.swift in Sources */, F331DD092A83A56500222120 /* LayerFactory.swift in Sources */, F336080D2A8A142800C7C9B7 /* SnackbarFormVariant.swift in Sources */, + F39116FE2AA9B54B00852298 /* LayersSourceFilter.swift in Sources */, 840C38AC25D11BB200D50183 /* DeliveryOperation.swift in Sources */, 334F3AEE264C199900A6AC00 /* SegmentationRequest.swift in Sources */, B3A625502689F8B600B6A3B7 /* BenefitResponse.swift in Sources */, diff --git a/Mindbox/DI/DependencyContainer.swift b/Mindbox/DI/DependencyContainer.swift index eb3d00a4..07cd1a99 100644 --- a/Mindbox/DI/DependencyContainer.swift +++ b/Mindbox/DI/DependencyContainer.swift @@ -28,6 +28,7 @@ protocol DependencyContainer { var imageDownloadService: ImageDownloadServiceProtocol { get } var abTestDeviceMixer: ABTestDeviceMixer { get } var urlExtractorService: VariantImageUrlExtractorService { get } + var inappFilterService: InappFilterProtocol { get } } protocol InstanceFactory { diff --git a/Mindbox/DI/DependencyProvider.swift b/Mindbox/DI/DependencyProvider.swift index 137c5f00..945bad27 100644 --- a/Mindbox/DI/DependencyProvider.swift +++ b/Mindbox/DI/DependencyProvider.swift @@ -30,6 +30,7 @@ final class DependencyProvider: DependencyContainer { var imageDownloadService: ImageDownloadServiceProtocol var abTestDeviceMixer: ABTestDeviceMixer var urlExtractorService: VariantImageUrlExtractorService + var inappFilterService: InappFilterProtocol init() throws { utilitiesFetcher = MBUtilitiesFetcher() @@ -69,11 +70,23 @@ final class DependencyProvider: DependencyContainer { let presentationManager = InAppPresentationManager(actionHandler: actionHandler, displayUseCase: displayUseCase) urlExtractorService = VariantImageUrlExtractorService() + let actionFilter = LayerActionFilterService() + let sourceFilter = LayersSourceFilterService() + let layersFilterService = LayersFilterService(actionFilter: actionFilter, sourceFilter: sourceFilter) + let sizeFilter = ElementSizeFilterService() + let positionFilter = ElementsPositionFilterService() + let elementsFilterService = ElementsFilterService(sizeFilter: sizeFilter, positionFilter: positionFilter) + let contentPositionFilterService = ContentPositionFilterService() + let variantsFilterService = VariantFilterService(layersFilter: layersFilterService, + elementsFilter: elementsFilterService, + contentPositionFilter: contentPositionFilterService) + inappFilterService = InappsFilterService(variantsFilter: variantsFilterService) inAppMessagesManager = InAppCoreManager( configManager: InAppConfigurationManager( inAppConfigAPI: InAppConfigurationAPI(persistenceStorage: persistenceStorage), inAppConfigRepository: InAppConfigurationRepository(), - inAppConfigurationMapper: InAppConfigutationMapper(geoService: geoService, + inAppConfigurationMapper: InAppConfigutationMapper(inappFilterService: inappFilterService, + geoService: geoService, segmentationService: segmentationSevice, customerSegmentsAPI: .live, targetingChecker: inAppTargetingChecker, diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift index 52dc720c..b7eaf92c 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift @@ -16,6 +16,7 @@ protocol InAppConfigurationMapperProtocol { final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { + private let inappFilterService: InappFilterProtocol private let geoService: GeoServiceProtocol private let segmentationService: SegmentationServiceProtocol private let customerSegmentsAPI: CustomerSegmentsAPI @@ -30,7 +31,8 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { private let dispatchGroup = DispatchGroup() - init(geoService: GeoServiceProtocol, + init(inappFilterService: InappFilterProtocol, + geoService: GeoServiceProtocol, segmentationService: SegmentationServiceProtocol, customerSegmentsAPI: CustomerSegmentsAPI, targetingChecker: InAppTargetingCheckerProtocol, @@ -40,6 +42,7 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { imageDownloadService: ImageDownloadServiceProtocol, urlExtractorService: VariantImageUrlExtractorServiceProtocol, abTestDeviceMixer: ABTestDeviceMixer) { + self.inappFilterService = inappFilterService self.geoService = geoService self.segmentationService = segmentationService self.customerSegmentsAPI = customerSegmentsAPI @@ -57,8 +60,8 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { _ response: ConfigResponse, _ completion: @escaping (InAppFormData?) -> Void) { let shownInAppsIds = Set(persistenceStorage.shownInAppsIds ?? []) - let filteredInappsModel = InappsFilterService().filter(inapps: response.inapps?.elements) - let responseInapps = filterInappsByABTests(response.abtests, responseInapps: filteredInappsModel) + let inapps = inappFilterService.filter(inapps: response.inapps?.elements) + let responseInapps = filterInappsByABTests(response.abtests, responseInapps: inapps) let filteredInapps = filterInappsBySDKVersion(responseInapps, shownInAppsIds: shownInAppsIds) Logger.common(message: "Shown in-apps ids: [\(shownInAppsIds)]", level: .info, category: .inAppMessages) if filteredInapps.isEmpty { diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift new file mode 100644 index 00000000..69eedc1a --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift @@ -0,0 +1,62 @@ +// +// ContentPositionFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation + +protocol ContentPositionFilterProtocol { + func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition? +} + +final class ContentPositionFilterService: ContentPositionFilterProtocol { + + enum Constants { + static let defaultGravity = ContentPositionGravity(vertical: .bottom, horizontal: .center) + static let defaultMargin = ContentPositionMargin(kind: .dp, top: 0, right: 0, left: 0, bottom: 0) + static let defaultContentPosition = ContentPosition(gravity: defaultGravity, margin: defaultMargin) + } + + func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition? { + guard let contentPosition = contentPosition else { + return Constants.defaultContentPosition + } + + var customGravity: ContentPositionGravity + if let gravity = contentPosition.gravity { + let vertical = gravity.vertical ?? .bottom + let horizontal = gravity.horizontal ?? .center + customGravity = ContentPositionGravity(vertical: vertical, horizontal: horizontal) + } else { + customGravity = Constants.defaultGravity + } + + var customMargin: ContentPositionMargin? + if let margin = contentPosition.margin { + switch margin.kind { + case .dp: + if let top = margin.top, + let left = margin.left, + let right = margin.right, + let bottom = margin.bottom, + top >= 0, + left >= 0, + right >= 0, + bottom >= 0 { + customMargin = ContentPositionMargin(kind: margin.kind, top: top, right: right, left: left, bottom: bottom) + } + case .unknown: + customMargin = Constants.defaultMargin + } + } + + guard let customMargin = customMargin else { + return nil + } + + return ContentPosition(gravity: customGravity, margin: customMargin) + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift new file mode 100644 index 00000000..ac997d86 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift @@ -0,0 +1,62 @@ +// +// ElementsFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation + +protocol ElementsFilterProtocol { + func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement]? +} + +final class ElementsFilterService: ElementsFilterProtocol { + + enum Constants { + static let defaultColor = "#000000" + static let lineWidth = 1 + } + + private let sizeFilter: ElementsSizeFilterProtocol + private let positionFilter: ElementsPositionFilterProtocol + + init(sizeFilter: ElementsSizeFilterProtocol, positionFilter: ElementsPositionFilterProtocol) { + self.sizeFilter = sizeFilter + self.positionFilter = positionFilter + } + + func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement]? { + guard let elements = elements, !elements.isEmpty else { + return [] + } + + var filteredElements: [ContentElement] = [] + + elementsLoop: for element in elements { + if element.elementType == .unknown { + continue + } + + switch element { + case .closeButton(let closeButtonElementDTO): + guard let size = try sizeFilter.filter(closeButtonElementDTO.size), + let position = try positionFilter.filter(closeButtonElementDTO.position) else { + return nil + } + + let customCloseButtonElement = CloseButtonElement(color: closeButtonElementDTO.color?.element ?? Constants.defaultColor, + lineWidth: closeButtonElementDTO.lineWidth?.element ?? Constants.lineWidth, + size: size, + position: position) + let element = try ContentElement(type: .closeButton, closeButton: customCloseButtonElement) + filteredElements.append(element) + case .unknown: + continue elementsLoop + } + } + + return filteredElements + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift new file mode 100644 index 00000000..9612d8a8 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift @@ -0,0 +1,53 @@ +// +// ElementsPositionFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation + +protocol ElementsPositionFilterProtocol { + func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition? +} + +final class ElementsPositionFilterService: ElementsPositionFilterProtocol { + + enum Constants { + static let defaultMargin = ContentElementPositionMargin(kind: .proportion, top: 0.02, right: 0.02, left: 0.02, bottom: 0.02) + + } + + func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition? { + guard let position = position, + let margin = position.margin else { + return ContentElementPosition(margin: Constants.defaultMargin) + } + + let marginRange: ClosedRange = 0...1 + + switch margin.kind { + case .proportion: + if let top = margin.top, + let left = margin.left, + let right = margin.right, + let bottom = margin.bottom, + marginRange.contains(top), + marginRange.contains(left), + marginRange.contains(right), + marginRange.contains(bottom) { + let customMargin = ContentElementPositionMargin(kind: margin.kind, + top: top, + right: right, + left: left, + bottom: bottom) + return ContentElementPosition(margin: customMargin) + } + case .unknown: + return ContentElementPosition(margin: Constants.defaultMargin) + } + + return nil + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift new file mode 100644 index 00000000..a3bab21c --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift @@ -0,0 +1,39 @@ +// +// ElementsSizeFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation + +protocol ElementsSizeFilterProtocol { + func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize? +} + +final class ElementSizeFilterService: ElementsSizeFilterProtocol { + enum Constants { + static let defaultSize = ContentElementSize(kind: .dp, width: 24, height: 24) + } + + func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize? { + guard let size = size else { + return Constants.defaultSize + } + + switch size.kind { + case .dp: + if let height = size.height, + let width = size.width, + height >= 0, + width >= 0 { + return ContentElementSize(kind: size.kind, width: width, height: height) + } + case .unknown: + return Constants.defaultSize + } + + return nil + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappFilter.swift new file mode 100644 index 00000000..af2e8d8c --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappFilter.swift @@ -0,0 +1,50 @@ +// +// InappFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation +import MindboxLogger + +protocol InappFilterProtocol { + func filter(inapps: [InAppDTO]?) -> [InApp] +} + +final class InappsFilterService: InappFilterProtocol { + private let variantsFilter: VariantFilterProtocol + + init(variantsFilter: VariantFilterProtocol) { + self.variantsFilter = variantsFilter + } + + func filter(inapps: [InAppDTO]?) -> [InApp] { + guard let inapps = inapps else { + Logger.common(message: "Received nil for in-apps. Returning an empty array.", level: .debug, category: .inAppMessages) + return [] + } + + Logger.common(message: "Processing \(inapps.count) in-app(s).", level: .debug, category: .inAppMessages) + + var filteredInapps: [InApp] = [] + for inapp in inapps { + do { + if let variants = try variantsFilter.filter(inapp.form.variants), !variants.isEmpty { + let formModel = InAppForm(variants: variants) + let inappModel = InApp(id: inapp.id, + sdkVersion: inapp.sdkVersion, + targeting: inapp.targeting, + form: formModel) + filteredInapps.append(inappModel) + } + } catch { + print("Error filtering variants for in-app with id \(inapp.id): \(error.localizedDescription)") + } + } + + Logger.common(message: "Filtering process completed. \(filteredInapps.count) valid in-app(s) found.", level: .debug, category: .inAppMessages) + return filteredInapps + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappsFilterService.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappsFilterService.swift deleted file mode 100644 index 71a27dce..00000000 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappsFilterService.swift +++ /dev/null @@ -1,229 +0,0 @@ -// -// InappsFilterService.swift -// Mindbox -// -// Created by vailence on 06.09.2023. -// - -import Foundation -import MindboxLogger - -protocol InappsFilterServiceProtocol { -// func -} - -class InappsFilterService: InappsFilterServiceProtocol { - - enum Constants { - static let elementSize = ContentElementSize(kind: .dp, width: 24, height: 24) - static let elementPositionMargin = ContentElementPositionMargin(kind: .proportion, top: 0.02, right: 0.02, left: 0.02, bottom: 0.02) - static let defaultColor = "#000000" - static let lineWidth = 1 - - } - - func filter(inapps: [InAppDTO]?) -> [InApp] { - guard let inapps = inapps else { - return [] - } - - var filteredInapps = [InApp]() - for inapp in inapps { - guard let variants = inapp.form.variants else { - Logger.common(message: "Variants cannot be empty. Inapp will be ignored.") - continue - } - - var isValidInapp = true - var variantsArray = [MindboxFormVariant]() - variantsLoop: for variant in variants { - switch variant { - case .modal(let modalFormVariant): - guard let content = modalFormVariant.content, - let background = content.background, - let layers = background.layers - else { - isValidInapp = false - Logger.common(message: "Something went wrong. Some validations are not passed.") - break variantsLoop - } - - let filteredLayers = filterLayers(layers) - if filteredLayers.isEmpty { - isValidInapp = false - break variantsLoop - } - - let backgroundModel = ContentBackground(layers: filteredLayers) - guard let elementsModel = convertElements(content.elements) else { - break variantsLoop - } - let contentModel = InappFormVariantContent(background: backgroundModel, elements: elementsModel) - let modalFormVariantModel = ModalFormVariant(content: contentModel) - do { - let mindboxFormVariant = try MindboxFormVariant(type: .modal, modalVariant: modalFormVariantModel) - variantsArray.append(mindboxFormVariant) - } catch { - print(error) - } - case .snackbar: - break - case .unknown: - continue - } - } - - if isValidInapp && !variantsArray.isEmpty { - let formModel = InAppForm(variants: variantsArray) - let inapp = InApp(id: inapp.id, sdkVersion: inapp.sdkVersion, targeting: inapp.targeting, form: formModel) - filteredInapps.append(inapp) - } - } - - return filteredInapps - } - - private func filterLayers(_ layers: [ContentBackgroundLayerDTO]) -> [ContentBackgroundLayer] { - var layersArray = [ContentBackgroundLayer]() - for layer in layers { - switch layer { - case .image(let imageContentBackgroundLayerDTO): - if let action = convertAction(imageContentBackgroundLayerDTO.action), - let source = convertSource(imageContentBackgroundLayerDTO.source) { - let imageLayer = ImageContentBackgroundLayer(action: action, source: source) - do { - let newLayer = try ContentBackgroundLayer(type: layer.layerType, imageLayer: imageLayer) - layersArray.append(newLayer) - } catch { - Logger.common(message: "filterLayers error: [\(error)]", level: .error, category: .inAppMessages) - } - } else { - return [] - } - case .unknown: - break - } - } - - return layersArray.filter { $0.layerType != .unknown } - } - - private func convertAction(_ action: ContentBackgroundLayerActionDTO?) -> ContentBackgroundLayerAction? { - guard let action = action, - action.actionType != .unknown else { - return nil - } - - switch action { - case .redirectUrl(let redirectUrlLayerAction): - if let value = redirectUrlLayerAction.value, let payload = redirectUrlLayerAction.intentPayload { - do { - let redirectUrlLayerActionModel = RedirectUrlLayerAction(intentPayload: payload, value: value) - return try ContentBackgroundLayerAction(type: .redirectUrl, redirectModel: redirectUrlLayerActionModel) - } catch { - Logger.common(message: "convertAction error: [\(error)]", level: .error, category: .inAppMessages) - } - } - case .unknown: - break - } - - return nil - } - - private func convertSource(_ source: ContentBackgroundLayerSourceDTO?) -> ContentBackgroundLayerSource? { - guard let source = source, - source.sourceType != .unknown else { - return nil - } - - switch source { - case .url(let urlLayerSource): - if let value = urlLayerSource.value { - do { - let urlLayerSourceModel = UrlLayerSource(value: value) - return try ContentBackgroundLayerSource(type: .url, urlModel: urlLayerSourceModel) - } catch { - Logger.common(message: "convertSource error: [\(error)]", level: .error, category: .inAppMessages) - } - } - case .unknown: - break - } - - return nil - } - - private func convertElements(_ elements: [ContentElementDTO]?) -> [ContentElement]? { - guard let elements = elements, !elements.isEmpty else { - return [] - } - - var filteredElements = [ContentElement]() - - elementsLoop: for element in elements { - if element.elementType == .unknown { - continue - } - - switch element { - case .closeButton(let closeButtonElement): - var customSize: ContentElementSize - if let sizeDTO = closeButtonElement.size?.element { - if sizeDTO.kind == .unknown { - customSize = Constants.elementSize - } else if let height = sizeDTO.height, - let width = sizeDTO.width, - height >= 0, - width >= 0 { - customSize = ContentElementSize(kind: sizeDTO.kind, width: width, height: height) - } else { - return nil - } - } else { - customSize = Constants.elementSize - } - - var customPosition: ContentElementPosition - if let positionDTO = closeButtonElement.position?.element, - let margin = positionDTO.margin?.element { - let marginRange: ClosedRange = 0...1 - var customMargin: ContentElementPositionMargin - if margin.kind == .unknown { - customMargin = Constants.elementPositionMargin - customPosition = ContentElementPosition(margin: customMargin) - } else if let top = margin.top, - let left = margin.left, - let right = margin.right, - let bottom = margin.bottom, - marginRange.contains(top), - marginRange.contains(left), - marginRange.contains(right), - marginRange.contains(bottom) { - customMargin = ContentElementPositionMargin(kind: margin.kind, top: top, right: right, left: left, bottom: bottom) - customPosition = ContentElementPosition(margin: customMargin) - } else { - return nil - } - } else { - customPosition = ContentElementPosition(margin: Constants.elementPositionMargin) - } - - do { - let customCloseButtonElement = CloseButtonElement(color: closeButtonElement.color?.element ?? Constants.defaultColor, - lineWidth: closeButtonElement.lineWidth?.element ?? Constants.lineWidth, - size: customSize, - position: customPosition) - let element = try ContentElement(type: .closeButton, closeButton: customCloseButtonElement) - filteredElements.append(element) - } catch { - Logger.common(message: "convertElements error: [\(error)]", level: .error, category: .inAppMessages) - } - case .unknown: - continue elementsLoop - } - } - - return filteredElements - } -} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayerActionFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayerActionFilter.swift new file mode 100644 index 00000000..51c782f0 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayerActionFilter.swift @@ -0,0 +1,34 @@ +// +// LayerActionFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation + +protocol LayerActionFilterProtocol { + func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction? +} + +final class LayerActionFilterService: LayerActionFilterProtocol { + func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction? { + guard let action = action, + action.actionType != .unknown else { + return nil + } + + switch action { + case .redirectUrl(let redirectUrlLayerAction): + if let value = redirectUrlLayerAction.value, let payload = redirectUrlLayerAction.intentPayload { + let redirectUrlLayerActionModel = RedirectUrlLayerAction(intentPayload: payload, value: value) + return try ContentBackgroundLayerAction(type: .redirectUrl, redirectModel: redirectUrlLayerActionModel) + } + case .unknown: + break + } + + return nil + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift new file mode 100644 index 00000000..1ed4947d --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift @@ -0,0 +1,50 @@ +// +// LayersFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation +import MindboxLogger + +protocol LayersFilterProtocol { + func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer]? +} + +final class LayersFilterService: LayersFilterProtocol { + private let actionFilter: LayerActionFilterProtocol + private let sourceFilter: LayersSourceFilterProtocol + + init(actionFilter: LayerActionFilterProtocol, sourceFilter: LayersSourceFilterProtocol) { + self.actionFilter = actionFilter + self.sourceFilter = sourceFilter + } + + func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer]? { + var filteredLayers: [ContentBackgroundLayer] = [] + + guard let layers = layers else { + return nil + } + + for layer in layers { + switch layer { + case .image(let imageContentBackgroundLayerDTO): + if let action = try actionFilter.filter(imageContentBackgroundLayerDTO.action), + let source = try sourceFilter.filter(imageContentBackgroundLayerDTO.source) { + let imageLayer = ImageContentBackgroundLayer(action: action, source: source) + let newLayer = try ContentBackgroundLayer(type: layer.layerType, imageLayer: imageLayer) + filteredLayers.append(newLayer) + } else { + return [] + } + case .unknown: + break + } + } + + return filteredLayers.filter { $0.layerType != .unknown } + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersSourceFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersSourceFilter.swift new file mode 100644 index 00000000..2b2541bb --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersSourceFilter.swift @@ -0,0 +1,34 @@ +// +// LayersSourceFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation + +protocol LayersSourceFilterProtocol { + func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource? +} + +final class LayersSourceFilterService: LayersSourceFilterProtocol { + func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource? { + guard let source = source, + source.sourceType != .unknown else { + return nil + } + + switch source { + case .url(let urlLayerSource): + if let value = urlLayerSource.value { + let urlLayerSourceModel = UrlLayerSource(value: value) + return try ContentBackgroundLayerSource(type: .url, urlModel: urlLayerSourceModel) + } + case .unknown: + break + } + + return nil + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift new file mode 100644 index 00000000..aa3435d6 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift @@ -0,0 +1,78 @@ +// +// VariantsFilter.swift +// Mindbox +// +// Created by vailence on 07.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation + +protocol VariantFilterProtocol { + func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant]? +} + +final class VariantFilterService: VariantFilterProtocol { + + private let layersFilter: LayersFilterProtocol + private let elementsFilter: ElementsFilterProtocol + private let contentPositionFilter: ContentPositionFilterProtocol + + init(layersFilter: LayersFilterProtocol, elementsFilter: ElementsFilterProtocol, contentPositionFilter: ContentPositionFilterProtocol) { + self.layersFilter = layersFilter + self.elementsFilter = elementsFilter + self.contentPositionFilter = contentPositionFilter + } + + func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant]? { + var resultVariants: [MindboxFormVariant] = [] + guard let variants = variants else { + return nil + } + + variantsLoop: for variant in variants { + switch variant { + case .modal(let modalFormVariantDTO): + guard let content = modalFormVariantDTO.content, + let background = content.background else { + return nil + } + + guard let filteredLayers = try layersFilter.filter(background.layers), + let fileterdElements = try elementsFilter.filter(content.elements) else { + return nil + } + + let backgroundModel = ContentBackground(layers: filteredLayers) + + let contentModel = InappFormVariantContent(background: backgroundModel, elements: fileterdElements) + let modalFormVariantModel = ModalFormVariant(content: contentModel) + let mindboxFormVariant = try MindboxFormVariant(type: .modal, modalVariant: modalFormVariantModel) + resultVariants.append(mindboxFormVariant) + case .snackbar(let snackbarFormVariant): + guard let content = snackbarFormVariant.content, + let background = content.background else { + return nil + } + + guard let filteredLayers = try layersFilter.filter(background.layers), + let filteredElements = try elementsFilter.filter(content.elements), + let contentPosition = try contentPositionFilter.filter(content.position) else { + return nil + } + + let backgroundModel = ContentBackground(layers: filteredLayers) + let contentModel = SnackbarFormVariantContent(background: backgroundModel, + position: contentPosition, + elements: filteredElements) + let snackbarFormVariant = SnackbarFormVariant(content: contentModel) + let mindboxFormVariant = try MindboxFormVariant(type: .snackbar, snackbarVariant: snackbarFormVariant) + resultVariants.append(mindboxFormVariant) + case .unknown: + continue + } + } + + return resultVariants + } +} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift index c40ba94b..1f644a14 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPosition.swift @@ -9,7 +9,7 @@ import Foundation struct ContentElementPositionDTO: Decodable, Equatable { - let margin: FailableDecodable? + let margin: ContentElementPositionMarginDTO? } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift index c1d8cff6..f9b560f9 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMargin.swift @@ -9,7 +9,7 @@ import Foundation struct ContentElementPositionMarginDTO: Decodable, Equatable { - let kind: PositionMarginKind + let kind: ElementPositionMarginKind let top: Double? let right: Double? let left: Double? @@ -17,9 +17,20 @@ struct ContentElementPositionMarginDTO: Decodable, Equatable { } struct ContentElementPositionMargin: Decodable, Equatable { - let kind: PositionMarginKind + let kind: ElementPositionMarginKind let top: Double let right: Double let left: Double let bottom: Double } + +enum ElementPositionMarginKind: String, Decodable, Equatable { + case proportion + case unknown + + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let rawValue = try container.decode(RawValue.self) + self = ElementPositionMarginKind(rawValue: rawValue) ?? .unknown + } +} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/PositionMarginKind/PositionMarginKind.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/PositionMarginKind/PositionMarginKind.swift deleted file mode 100644 index c860330a..00000000 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/PositionMarginKind/PositionMarginKind.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// PositionMarginKind.swift -// Mindbox -// -// Created by vailence on 04.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation - -enum PositionMarginKind: String, Decodable, Equatable { - case proportion - case unknown - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let rawValue = try container.decode(RawValue.self) - self = PositionMarginKind(rawValue: rawValue) ?? .unknown - } -} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift index 4cb1fb5d..31a38e68 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/Elements/CloseButtonElement.swift @@ -11,8 +11,8 @@ import Foundation struct CloseButtonElementDTO: ContentElementProtocol { let color: FailableDecodable? let lineWidth: FailableDecodable? - let size: FailableDecodable? - let position: FailableDecodable? + let size: ContentElementSizeDTO? + let position: ContentElementPositionDTO? } struct CloseButtonElement: ContentElementProtocol { diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPosition.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPosition.swift index 2bc48a9b..2b9cf74d 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPosition.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPosition.swift @@ -8,17 +8,12 @@ import Foundation +struct ContentPositionDTO: Decodable, Equatable { + let gravity: ContentPositionGravityDTO? + let margin: ContentPositionMarginDTO? +} + struct ContentPosition: Decodable, Equatable { - let gravity: FailableDecodable? - let margin: FailableDecodable? - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - gravity = try container.decodeIfPresent(FailableDecodable.self, forKey: .gravity) - margin = try container.decodeIfPresent(FailableDecodable.self, forKey: .margin) - } - - enum CodingKeys: String, CodingKey { - case gravity, margin - } + let gravity: ContentPositionGravity? + let margin: ContentPositionMargin } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift index 0297f09a..dc6d088b 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift @@ -8,49 +8,38 @@ import Foundation +struct ContentPositionGravityDTO: Decodable, Equatable { + let vertical: GravityVerticalType? + let horizontal: GravityHorizontalType? +} + struct ContentPositionGravity: Decodable, Equatable { - let vertical: VerticalType? - let horizontal: HorizontalType? - - enum HorizontalType: String, Decodable { - case left - case right - case center - case unknown - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let rawValue = try container.decode(RawValue.self) - self = HorizontalType(rawValue: rawValue) ?? .unknown - } - } - - enum VerticalType: String, Decodable { - case top - case bottom - case center - case unknown - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let rawValue = try container.decode(RawValue.self) - self = VerticalType(rawValue: rawValue) ?? .unknown - } - } + let vertical: GravityVerticalType? + let horizontal: GravityHorizontalType? +} + +enum GravityHorizontalType: String, Decodable { + case left + case right + case center + case unknown - enum CodingKeys: CodingKey { - case vertical - case horizontal + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let rawValue = try container.decode(RawValue.self) + self = GravityHorizontalType(rawValue: rawValue) ?? .unknown } +} + +enum GravityVerticalType: String, Decodable { + case top + case bottom + case center + case unknown init(from decoder: Decoder) throws { - let container: KeyedDecodingContainer = try decoder.container(keyedBy: ContentPositionGravity.CodingKeys.self) - - self.vertical = try container.decodeIfPresent(ContentPositionGravity.VerticalType.self, forKey: .vertical) - self.horizontal = try container.decodeIfPresent(ContentPositionGravity.HorizontalType.self, forKey: .horizontal) - - if vertical == .unknown || horizontal == .unknown { - throw CustomDecodingError.unknownType("") - } + let container = try decoder.singleValueContainer() + let rawValue = try container.decode(RawValue.self) + self = GravityVerticalType(rawValue: rawValue) ?? .unknown } } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMargin.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMargin.swift index 8781bf6b..2c0ada89 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMargin.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMargin.swift @@ -8,40 +8,29 @@ import Foundation -struct ContentPositionMargin: Decodable, Equatable { - let kind: PositionMarginKind +struct ContentPositionMarginDTO: Decodable, Equatable { + let kind: ContentPositionMarginKind let top: Double? let right: Double? let left: Double? let bottom: Double? +} + +struct ContentPositionMargin: Decodable, Equatable { + let kind: ContentPositionMarginKind + let top: Double + let right: Double + let left: Double + let bottom: Double +} + +enum ContentPositionMarginKind: String, Decodable, Equatable { + case dp + case unknown - enum CodingKeys: CodingKey { - case kind - case top - case right - case left - case bottom - } - - init(from decoder: Decoder, gravity: ContentPositionGravity) throws { - let container: KeyedDecodingContainer = try decoder.container(keyedBy: ContentPositionMargin.CodingKeys.self) - - self.kind = try container.decode(PositionMarginKind.self, forKey: .kind) - self.top = try container.decodeIfPresentSafely(Double.self, forKey: .top) - self.right = try container.decodeIfPresentSafely(Double.self, forKey: .right) - self.left = try container.decodeIfPresentSafely(Double.self, forKey: .left) - self.bottom = try container.decodeIfPresentSafely(Double.self, forKey: .bottom) - - if !ContentPositionMarginValidator().isValid(item: self) { - throw CustomDecodingError.decodingError("ContentPositionMargin not passed validation. It will be ignored.") - } - } - - init(kind: PositionMarginKind, top: Double? = nil, right: Double? = nil, left: Double? = nil, bottom: Double? = nil) { - self.kind = kind - self.top = top - self.right = right - self.left = left - self.bottom = bottom + init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let rawValue = try container.decode(RawValue.self) + self = ContentPositionMarginKind(rawValue: rawValue) ?? .unknown } } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/SnackbarFormVariantContent.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/SnackbarFormVariantContent.swift index 3c1dfadc..9c55610b 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/SnackbarFormVariantContent.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/SnackbarFormVariantContent.swift @@ -8,8 +8,14 @@ import Foundation +struct SnackbarFormVariantContentDTO: Decodable, Equatable { + let background: ContentBackgroundDTO? + let position: ContentPositionDTO? + let elements: [ContentElementDTO]? +} + struct SnackbarFormVariantContent: Decodable, Equatable { let background: ContentBackground - let position: ContentPosition? - let elements: FailableDecodableArray? + let position: ContentPosition + let elements: [ContentElement] } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/SnackbarFormVariant.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/SnackbarFormVariant.swift index f27c61eb..198247b8 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/SnackbarFormVariant.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/Variants/SnackbarFormVariant.swift @@ -8,6 +8,10 @@ import Foundation +struct SnackbarFormVariantDTO: iFormVariant, Decodable, Equatable { + let content: SnackbarFormVariantContentDTO? +} + struct SnackbarFormVariant: iFormVariant, Decodable, Equatable { let content: SnackbarFormVariantContent } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift index 538b5af6..8a95948d 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/iFormVariant.swift @@ -24,7 +24,7 @@ enum MindboxFormVariantType: String, Decodable { enum MindboxFormVariantDTO: Decodable, Hashable, Equatable { case modal(ModalFormVariantDTO) - case snackbar(SnackbarFormVariant) + case snackbar(SnackbarFormVariantDTO) case unknown enum CodingKeys: String, CodingKey { @@ -62,7 +62,7 @@ enum MindboxFormVariantDTO: Decodable, Hashable, Equatable { let modalVariant = try variantContainer.decode(ModalFormVariantDTO.self) self = .modal(modalVariant) case .snackbar: - let snackbarVariant = try variantContainer.decode(SnackbarFormVariant.self) + let snackbarVariant = try variantContainer.decode(SnackbarFormVariantDTO.self) self = .snackbar(snackbarVariant) case .unknown: self = .unknown diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift index 83d13bbd..39ba547d 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift @@ -27,11 +27,11 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { ] var leftOffset: CGFloat { - return model.content.position?.margin?.element?.left ?? 0 + return model.content.position.margin.left } var rightOffset: CGFloat { - return model.content.position?.margin?.element?.right ?? 0 + return model.content.position.margin.right } private let id: String @@ -130,12 +130,11 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } private func setupElements() { - guard let elements = model.content.elements?.elements, - let snackbarView = snackbarView else { + guard let snackbarView = snackbarView else { return } - for element in elements { + for element in model.content.elements { if let factory = elementFactories[element.elementType] { let elementView = factory.create(from: element, with: self) if let elementView = elementView { diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift index 5a9526f4..096ecdbb 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift @@ -15,7 +15,7 @@ class SnackbarViewFactory: ViewFactoryProtocol { func create(model: MindboxFormVariant, id: String, imagesDict: [String: UIImage], onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? { if case .snackbar(let snackbarFormVariant) = model { - if let gravity = snackbarFormVariant.content.position?.gravity?.element?.vertical { + if let gravity = snackbarFormVariant.content.position.gravity?.vertical { var snackbarViewController: UIViewController? switch gravity { case .top: diff --git a/Mindbox/Info.plist b/Mindbox/Info.plist index 4d77df85..5ab6c467 100644 --- a/Mindbox/Info.plist +++ b/Mindbox/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 4794 + 4803 From 12e6221c622aee4498f1f16b218c4f8672870df7 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Fri, 8 Sep 2023 13:20:31 +0600 Subject: [PATCH 08/28] MBX-2793 Fix first image --- .../InAppConfigutationMapper.swift | 3 ++- Mindbox/InAppMessages/Models/InAppFormData.swift | 1 + .../PresentationDisplayUseCase.swift | 1 + .../Views/SnackbarView/SnackbarViewController.swift | 8 ++++---- .../Presentation/Views/ViewFactory/ModalViewFactory.swift | 1 + .../Views/ViewFactory/SnackbarViewFactory.swift | 6 +++--- .../Views/ViewFactory/ViewFactoryProtocol.swift | 1 + 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift index 75c0c92b..3538832e 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/InAppConfigutationMapper.swift @@ -298,7 +298,8 @@ final class InAppConfigutationMapper: InAppConfigurationMapperProtocol { imageDictQueue.sync { if !imageDict.isEmpty && !gotError { - formData = InAppFormData(inAppId: inapp.inAppId, imagesDict: imageDict, content: inapp.content) + let firstImageValue = imageValues.first ?? "" + formData = InAppFormData(inAppId: inapp.inAppId, imagesDict: imageDict, firstImageValue: firstImageValue, content: inapp.content) } } } diff --git a/Mindbox/InAppMessages/Models/InAppFormData.swift b/Mindbox/InAppMessages/Models/InAppFormData.swift index 62e1b935..942b4f41 100644 --- a/Mindbox/InAppMessages/Models/InAppFormData.swift +++ b/Mindbox/InAppMessages/Models/InAppFormData.swift @@ -13,6 +13,7 @@ import UIKit struct InAppFormData { let inAppId: String let imagesDict: [String: UIImage] + let firstImageValue: String let content: MindboxFormVariant } diff --git a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift index 34edf0e0..62301b96 100644 --- a/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift +++ b/Mindbox/InAppMessages/Presentation/Manager/UseCases/PresentationDisplayUseCase/PresentationDisplayUseCase.swift @@ -38,6 +38,7 @@ final class PresentationDisplayUseCase { guard let viewController = factory.create(model: model.content, id: model.inAppId, imagesDict: model.imagesDict, + firstImageValue: model.firstImageValue, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) else { diff --git a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift index b8991ff3..bcb7ff5e 100644 --- a/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift +++ b/Mindbox/InAppMessages/Presentation/Views/SnackbarView/SnackbarViewController.swift @@ -34,8 +34,8 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { return model.content.position?.margin?.element?.right ?? 0 } - private let id: String private let imagesDict: [String: UIImage] + private let firstImageValue: String private let onPresented: () -> Void private let onClose: () -> Void private let onTapAction: (ContentBackgroundLayerAction?) -> Void @@ -51,15 +51,15 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { init( model: SnackbarFormVariant, - id: String, imagesDict: [String: UIImage], + firstImageValue: String, onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void ) { self.model = model - self.id = id self.imagesDict = imagesDict + self.firstImageValue = firstImageValue self.onPresented = onPresented self.onClose = onClose self.onTapAction = onTapAction @@ -161,7 +161,7 @@ class SnackbarViewController: UIViewController, InappViewControllerProtocol { } func setupConstraints() { - guard let firstImageKey = imagesDict.keys.first, let image = imagesDict[firstImageKey] else { + guard let image = imagesDict[firstImageValue] else { return } diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift index 503a120a..07a6a449 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ModalViewFactory.swift @@ -14,6 +14,7 @@ class ModalViewFactory: ViewFactoryProtocol { func create(model: MindboxFormVariant, id: String, imagesDict: [String: UIImage], + firstImageValue: String, onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? { diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift index 5a9526f4..3be04580 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/SnackbarViewFactory.swift @@ -13,15 +13,15 @@ class SnackbarViewFactory: ViewFactoryProtocol { weak var viewController: UIViewController? - func create(model: MindboxFormVariant, id: String, imagesDict: [String: UIImage], onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? { + func create(model: MindboxFormVariant, id: String, imagesDict: [String: UIImage], firstImageValue: String, onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? { if case .snackbar(let snackbarFormVariant) = model { if let gravity = snackbarFormVariant.content.position?.gravity?.element?.vertical { var snackbarViewController: UIViewController? switch gravity { case .top: - snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, id: id, imagesDict: imagesDict, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) + snackbarViewController = TopSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) case .bottom: - snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, id: id, imagesDict: imagesDict, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) + snackbarViewController = BottomSnackbarViewController(model: snackbarFormVariant, imagesDict: imagesDict, firstImageValue: firstImageValue, onPresented: onPresented, onTapAction: onTapAction, onClose: onClose) default: return nil } diff --git a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift index 6e24d472..edbbb402 100644 --- a/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift +++ b/Mindbox/InAppMessages/Presentation/Views/ViewFactory/ViewFactoryProtocol.swift @@ -13,6 +13,7 @@ protocol ViewFactoryProtocol { func create(model: MindboxFormVariant, id: String, imagesDict: [String: UIImage], + firstImageValue: String, onPresented: @escaping () -> Void, onTapAction: @escaping (ContentBackgroundLayerAction?) -> Void, onClose: @escaping () -> Void) -> UIViewController? From 251ba8b1fbd9aeeadd3b4b533d87afbedabb3e4c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 16 Sep 2023 04:56:48 +0000 Subject: [PATCH 09/28] Update dependency fastlane to v2.215.0 --- Gemfile.lock | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a60d0cd6..428e2559 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,7 +9,7 @@ GEM minitest (>= 5.1) tzinfo (~> 2.0) zeitwerk (~> 2.3) - addressable (2.8.4) + addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) @@ -17,8 +17,8 @@ GEM artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.786.0) - aws-sdk-core (3.178.0) + aws-partitions (1.824.0) + aws-sdk-core (3.181.1) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) @@ -26,8 +26,8 @@ GEM aws-sdk-kms (1.71.0) aws-sdk-core (~> 3, >= 3.177.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.130.0) - aws-sdk-core (~> 3, >= 3.177.0) + aws-sdk-s3 (1.134.0) + aws-sdk-core (~> 3, >= 3.181.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.6) aws-sigv4 (1.6.0) @@ -86,7 +86,7 @@ GEM escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) - excon (0.100.0) + excon (0.103.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -159,9 +159,9 @@ GEM fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.45.0) + google-apis-androidpublisher_v3 (0.49.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-core (0.11.0) + google-apis-core (0.11.1) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -190,10 +190,9 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.6.0) + googleauth (1.8.0) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) - memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) @@ -206,9 +205,8 @@ GEM jmespath (1.6.2) json (2.6.3) jwt (2.7.1) - memoist (0.16.2) mini_magick (4.12.0) - mini_mime (1.1.2) + mini_mime (1.1.5) minitest (5.18.0) molinillo (0.8.0) multi_json (1.15.0) @@ -227,13 +225,13 @@ GEM trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.5) + rexml (3.2.6) rouge (2.0.7) ruby-macho (2.5.1) ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) - signet (0.17.0) + signet (0.18.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) From af3b7a4de9d195e0e0bf594f2761f5c3c347f88f Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Fri, 15 Sep 2023 23:16:51 +0600 Subject: [PATCH 10/28] MBX-2792 unit tests --- Mindbox.xcodeproj/project.pbxproj | 136 +- Mindbox/DI/DependencyProvider.swift | 3 +- .../ContentPositionFilter.swift | 6 +- .../ElementsFiter/ElementsColorFilter.swift | 26 + .../ElementsFiter/ElementsFilter.swift | 21 +- .../ElementsPositionFilter.swift | 6 +- .../ElementsFiter/ElementsSizeFilter.swift | 6 +- .../InappFilterService/InappFilter.swift | 23 +- .../LayersFilter/LayerActionFilter.swift | 8 +- .../LayersFilter/LayersFilter.swift | 19 +- .../LayersFilter/LayersSourceFilter.swift | 10 +- .../InappFilterService/VariantsFilter.swift | 25 +- ...ontentElementPositionMarginValidator.swift | 29 - .../ContentElementSizeValidator.swift | 28 - .../ContentPositionGravity.swift | 14 - .../ContentPositionMarginValidator.swift | 22 - .../Config/InappModel/InappValidator.swift | 34 - Mindbox/Info.plist | 2 +- MindboxTests/DI/TestDependencyProvider.swift | 14 + .../InApp/Tests/ABTesting/ABTests.swift | 1683 +++++++++-------- .../InappFilterServiceTests.swift | 313 +++ .../JSON /closeButtonMarginAboveOne.json | 206 ++ .../JSON /closeButtonMarginBelowZero.json | 206 ++ .../JSON /closeButtonWithOpenButton.json | 225 +++ .../JSON /emptyLayersSection.json | 193 ++ .../JSON /emptyVariantsArray.json | 160 ++ .../JSON /invalidCloseButtonColor.json | 206 ++ .../knownImageUnknownPictureLayerType.json | 218 +++ .../JSON /missingBackgroundSection.json | 190 ++ .../missingCloseButtonColorLineWidthSize.json | 199 ++ .../JSON /missingElementsSection.json | 164 ++ .../missingImageLinkInSourceLayerValue.json | 206 ++ .../missingIntentPayloadInActionLayer.json | 330 ++++ .../JSON /missingMarginFieldInSection.json | 205 ++ .../JSON /missingSourceSection.json | 202 ++ .../JSON /missingValueInSourceLayer.json | 205 ++ .../JSON /negativeCloseButtonSizeValues.json | 206 ++ ...redirectUrlValueNumberInsteadOfString.json | 332 ++++ .../JSON /twoCloseButtonsInApp.json | 225 +++ .../JSON /unknownActionLayerType.json | 332 ++++ .../JSON /unknownLayerType.json | 206 ++ .../JSON /unknownSizeKind.json | 206 ++ .../JSON /unknownSourceType.json | 206 ++ .../JSON /unknownVariantType.json | 206 ++ ...tElementPositionMarginValidatorTests.swift | 30 - 45 files changed, 6417 insertions(+), 1075 deletions(-) create mode 100644 Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsColorFilter.swift delete mode 100644 Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMarginValidator.swift delete mode 100644 Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSizeValidator.swift delete mode 100644 Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMarginValidator.swift delete mode 100644 Mindbox/InAppMessages/Models/Config/InappModel/InappValidator.swift create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/InappFilterServiceTests.swift create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginAboveOne.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginBelowZero.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonWithOpenButton.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyLayersSection.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyVariantsArray.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /invalidCloseButtonColor.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /knownImageUnknownPictureLayerType.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingBackgroundSection.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingCloseButtonColorLineWidthSize.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingElementsSection.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingImageLinkInSourceLayerValue.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingIntentPayloadInActionLayer.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingMarginFieldInSection.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingSourceSection.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingValueInSourceLayer.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /negativeCloseButtonSizeValues.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /redirectUrlValueNumberInsteadOfString.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /twoCloseButtonsInApp.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownActionLayerType.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownLayerType.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSizeKind.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSourceType.json create mode 100644 MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownVariantType.json delete mode 100644 MindboxTests/InApp/Tests/ModelValidatorTests/ContentElementPositionMarginValidatorTests.swift diff --git a/Mindbox.xcodeproj/project.pbxproj b/Mindbox.xcodeproj/project.pbxproj index f9a0f935..ef95b3b6 100644 --- a/Mindbox.xcodeproj/project.pbxproj +++ b/Mindbox.xcodeproj/project.pbxproj @@ -312,16 +312,13 @@ F331DCC12A80993600222120 /* ContentElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DC9B2A80993600222120 /* ContentElement.swift */; }; F331DCC32A80993600222120 /* ContentElementPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DC9F2A80993600222120 /* ContentElementPosition.swift */; }; F331DCC42A80993600222120 /* ContentElementPositionMargin.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCA12A80993600222120 /* ContentElementPositionMargin.swift */; }; - F331DCC62A80993600222120 /* ContentElementPositionMarginValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCA42A80993600222120 /* ContentElementPositionMarginValidator.swift */; }; F331DCC82A80993600222120 /* ContentBackgroundLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCA82A80993600222120 /* ContentBackgroundLayer.swift */; }; F331DCCB2A80993600222120 /* ContentBackgroundLayerAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCAD2A80993600222120 /* ContentBackgroundLayerAction.swift */; }; F331DCCC2A80993600222120 /* ContentBackgroundLayerSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCAF2A80993600222120 /* ContentBackgroundLayerSource.swift */; }; F331DCD12A80993600222120 /* ContentBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCB62A80993600222120 /* ContentBackground.swift */; }; F331DCD22A80993600222120 /* InappFormVariantContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCB72A80993600222120 /* InappFormVariantContent.swift */; }; F331DCD32A80993600222120 /* InappForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCB82A80993600222120 /* InappForm.swift */; }; - F331DCD42A80993600222120 /* InappValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCB92A80993600222120 /* InappValidator.swift */; }; F331DCD52A80993600222120 /* InAppModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCBA2A80993600222120 /* InAppModel.swift */; }; - F331DCE22A80B4C800222120 /* ContentElementPositionMarginValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCE12A80B4C800222120 /* ContentElementPositionMarginValidatorTests.swift */; }; F331DD012A83A56500222120 /* InAppPresentationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCEA2A83A56500222120 /* InAppPresentationManager.swift */; }; F331DD022A83A56500222120 /* PresentationDisplayUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCEE2A83A56500222120 /* PresentationDisplayUseCase.swift */; }; F331DD032A83A56500222120 /* ModalPresentationStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DCF02A83A56500222120 /* ModalPresentationStrategy.swift */; }; @@ -345,13 +342,11 @@ F331DD2E2A84CA8900222120 /* UrlLayerSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DD2D2A84CA8900222120 /* UrlLayerSource.swift */; }; F331DD312A84CCA800222120 /* CloseButtonElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DD302A84CCA800222120 /* CloseButtonElement.swift */; }; F331DD332A84D57800222120 /* VariantImageUrlExtractorService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DD322A84D57800222120 /* VariantImageUrlExtractorService.swift */; }; - F331DD582A8648DB00222120 /* ContentElementSizeValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F331DD572A8648DB00222120 /* ContentElementSizeValidator.swift */; }; F336080D2A8A142800C7C9B7 /* SnackbarFormVariant.swift in Sources */ = {isa = PBXBuildFile; fileRef = F336080C2A8A142800C7C9B7 /* SnackbarFormVariant.swift */; }; F336080F2A8A14D800C7C9B7 /* SnackbarFormVariantContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = F336080E2A8A14D800C7C9B7 /* SnackbarFormVariantContent.swift */; }; F33608122A8A151C00C7C9B7 /* ContentPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608112A8A151C00C7C9B7 /* ContentPosition.swift */; }; F33608152A8A156900C7C9B7 /* ContentPositionGravity.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608142A8A156900C7C9B7 /* ContentPositionGravity.swift */; }; F33608182A8A161200C7C9B7 /* ContentPositionMargin.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608172A8A161200C7C9B7 /* ContentPositionMargin.swift */; }; - F336081A2A8A163D00C7C9B7 /* ContentPositionMarginValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608192A8A163D00C7C9B7 /* ContentPositionMarginValidator.swift */; }; F336081C2A8B9EA800C7C9B7 /* SnackbarViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = F336081B2A8B9EA800C7C9B7 /* SnackbarViewFactory.swift */; }; F33608262A8CC94A00C7C9B7 /* SnackbarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608252A8CC94A00C7C9B7 /* SnackbarViewController.swift */; }; F33608282A8CD17E00C7C9B7 /* SnackbarPresentationStrategy.swift in Sources */ = {isa = PBXBuildFile; fileRef = F33608272A8CD17E00C7C9B7 /* SnackbarPresentationStrategy.swift */; }; @@ -376,6 +371,23 @@ F39117032AA9B79100852298 /* ElementsSizeFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39117022AA9B79100852298 /* ElementsSizeFilter.swift */; }; F39117052AA9B92500852298 /* ElementsPositionFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39117042AA9B92500852298 /* ElementsPositionFilter.swift */; }; F39117072AA9C69A00852298 /* ContentPositionFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F39117062AA9C69A00852298 /* ContentPositionFilter.swift */; }; + F391170B2AB2E74F00852298 /* InappFilterServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F391170A2AB2E74F00852298 /* InappFilterServiceTests.swift */; }; + F391170F2AB4B31800852298 /* unknownVariantType.json in Resources */ = {isa = PBXBuildFile; fileRef = F391170E2AB4B31800852298 /* unknownVariantType.json */; }; + F39117112AB4BD4500852298 /* missingBackgroundSection.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117102AB4BD4500852298 /* missingBackgroundSection.json */; }; + F39117132AB4BD8500852298 /* emptyLayersSection.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117122AB4BD8500852298 /* emptyLayersSection.json */; }; + F39117152AB4BEB900852298 /* unknownLayerType.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117142AB4BEB900852298 /* unknownLayerType.json */; }; + F39117172AB4BF2700852298 /* knownImageUnknownPictureLayerType.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117162AB4BF2700852298 /* knownImageUnknownPictureLayerType.json */; }; + F39117192AB4C02500852298 /* unknownActionLayerType.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117182AB4C02500852298 /* unknownActionLayerType.json */; }; + F391171B2AB4C07900852298 /* redirectUrlValueNumberInsteadOfString.json in Resources */ = {isa = PBXBuildFile; fileRef = F391171A2AB4C07900852298 /* redirectUrlValueNumberInsteadOfString.json */; }; + F391171D2AB4C0BE00852298 /* missingIntentPayloadInActionLayer.json in Resources */ = {isa = PBXBuildFile; fileRef = F391171C2AB4C0BE00852298 /* missingIntentPayloadInActionLayer.json */; }; + F391171F2AB4C1C100852298 /* missingSourceSection.json in Resources */ = {isa = PBXBuildFile; fileRef = F391171E2AB4C1C100852298 /* missingSourceSection.json */; }; + F39117212AB4C20200852298 /* emptyVariantsArray.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117202AB4C20200852298 /* emptyVariantsArray.json */; }; + F39117232AB4C23900852298 /* unknownSourceType.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117222AB4C23900852298 /* unknownSourceType.json */; }; + F39117252AB4C27B00852298 /* missingValueInSourceLayer.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117242AB4C27B00852298 /* missingValueInSourceLayer.json */; }; + F39117272AB4C2AA00852298 /* missingImageLinkInSourceLayerValue.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117262AB4C2AA00852298 /* missingImageLinkInSourceLayerValue.json */; }; + F39117292AB4C2EF00852298 /* missingElementsSection.json in Resources */ = {isa = PBXBuildFile; fileRef = F39117282AB4C2EF00852298 /* missingElementsSection.json */; }; + F391172B2AB4C4AD00852298 /* invalidCloseButtonColor.json in Resources */ = {isa = PBXBuildFile; fileRef = F391172A2AB4C4AD00852298 /* invalidCloseButtonColor.json */; }; + F391172D2AB4C61000852298 /* ElementsColorFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F391172C2AB4C61000852298 /* ElementsColorFilter.swift */; }; F397EEAD2A4456C300D48CEC /* ProtocolError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEAC2A4456C300D48CEC /* ProtocolError.swift */; }; F397EEAF2A4456FD00D48CEC /* MindboxError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEAE2A4456FD00D48CEC /* MindboxError.swift */; }; F397EEB12A44571300D48CEC /* UnknownDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397EEB02A44571300D48CEC /* UnknownDecodable.swift */; }; @@ -423,6 +435,14 @@ F3D818B32A3885F50002957C /* ABTestDeviceMixerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3D818B22A3885F50002957C /* ABTestDeviceMixerTests.swift */; }; F3D925AB2A120C0F00135C87 /* InAppImageDownloaderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3D925AA2A120C0F00135C87 /* InAppImageDownloaderMock.swift */; }; F3D925AD2A1236F400135C87 /* URLSessionImageDownloaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3D925AC2A1236F400135C87 /* URLSessionImageDownloaderTests.swift */; }; + F3FAD86A2AB863CD00D98C03 /* missingCloseButtonColorLineWidthSize.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD8692AB863CD00D98C03 /* missingCloseButtonColorLineWidthSize.json */; }; + F3FAD86C2AB8642C00D98C03 /* twoCloseButtonsInApp.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD86B2AB8642C00D98C03 /* twoCloseButtonsInApp.json */; }; + F3FAD86E2AB8656700D98C03 /* closeButtonWithOpenButton.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD86D2AB8656700D98C03 /* closeButtonWithOpenButton.json */; }; + F3FAD8702AB866B600D98C03 /* unknownSizeKind.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD86F2AB866B600D98C03 /* unknownSizeKind.json */; }; + F3FAD8722AB8673100D98C03 /* missingMarginFieldInSection.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD8712AB8673100D98C03 /* missingMarginFieldInSection.json */; }; + F3FAD8742AB8678900D98C03 /* negativeCloseButtonSizeValues.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD8732AB8678900D98C03 /* negativeCloseButtonSizeValues.json */; }; + F3FAD8762AB867E700D98C03 /* closeButtonMarginAboveOne.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD8752AB867E700D98C03 /* closeButtonMarginAboveOne.json */; }; + F3FAD8782AB8685D00D98C03 /* closeButtonMarginBelowZero.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FAD8772AB8685D00D98C03 /* closeButtonMarginBelowZero.json */; }; F78E92EF282E63320003B4A3 /* DispatchSemaphore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78E92EE282E63320003B4A3 /* DispatchSemaphore.swift */; }; /* End PBXBuildFile section */ @@ -776,16 +796,13 @@ F331DC9B2A80993600222120 /* ContentElement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElement.swift; sourceTree = ""; }; F331DC9F2A80993600222120 /* ContentElementPosition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElementPosition.swift; sourceTree = ""; }; F331DCA12A80993600222120 /* ContentElementPositionMargin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElementPositionMargin.swift; sourceTree = ""; }; - F331DCA42A80993600222120 /* ContentElementPositionMarginValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentElementPositionMarginValidator.swift; sourceTree = ""; }; F331DCA82A80993600222120 /* ContentBackgroundLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBackgroundLayer.swift; sourceTree = ""; }; F331DCAD2A80993600222120 /* ContentBackgroundLayerAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBackgroundLayerAction.swift; sourceTree = ""; }; F331DCAF2A80993600222120 /* ContentBackgroundLayerSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBackgroundLayerSource.swift; sourceTree = ""; }; F331DCB62A80993600222120 /* ContentBackground.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentBackground.swift; sourceTree = ""; }; F331DCB72A80993600222120 /* InappFormVariantContent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InappFormVariantContent.swift; sourceTree = ""; }; F331DCB82A80993600222120 /* InappForm.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InappForm.swift; sourceTree = ""; }; - F331DCB92A80993600222120 /* InappValidator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InappValidator.swift; sourceTree = ""; }; F331DCBA2A80993600222120 /* InAppModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppModel.swift; sourceTree = ""; }; - F331DCE12A80B4C800222120 /* ContentElementPositionMarginValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentElementPositionMarginValidatorTests.swift; sourceTree = ""; }; F331DCEA2A83A56500222120 /* InAppPresentationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InAppPresentationManager.swift; sourceTree = ""; }; F331DCEE2A83A56500222120 /* PresentationDisplayUseCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationDisplayUseCase.swift; sourceTree = ""; }; F331DCF02A83A56500222120 /* ModalPresentationStrategy.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ModalPresentationStrategy.swift; sourceTree = ""; }; @@ -809,13 +826,11 @@ F331DD2D2A84CA8900222120 /* UrlLayerSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UrlLayerSource.swift; sourceTree = ""; }; F331DD302A84CCA800222120 /* CloseButtonElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloseButtonElement.swift; sourceTree = ""; }; F331DD322A84D57800222120 /* VariantImageUrlExtractorService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariantImageUrlExtractorService.swift; sourceTree = ""; }; - F331DD572A8648DB00222120 /* ContentElementSizeValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentElementSizeValidator.swift; sourceTree = ""; }; F336080C2A8A142800C7C9B7 /* SnackbarFormVariant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarFormVariant.swift; sourceTree = ""; }; F336080E2A8A14D800C7C9B7 /* SnackbarFormVariantContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarFormVariantContent.swift; sourceTree = ""; }; F33608112A8A151C00C7C9B7 /* ContentPosition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPosition.swift; sourceTree = ""; }; F33608142A8A156900C7C9B7 /* ContentPositionGravity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPositionGravity.swift; sourceTree = ""; }; F33608172A8A161200C7C9B7 /* ContentPositionMargin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPositionMargin.swift; sourceTree = ""; }; - F33608192A8A163D00C7C9B7 /* ContentPositionMarginValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPositionMarginValidator.swift; sourceTree = ""; }; F336081B2A8B9EA800C7C9B7 /* SnackbarViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarViewFactory.swift; sourceTree = ""; }; F33608252A8CC94A00C7C9B7 /* SnackbarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarViewController.swift; sourceTree = ""; }; F33608272A8CD17E00C7C9B7 /* SnackbarPresentationStrategy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnackbarPresentationStrategy.swift; sourceTree = ""; }; @@ -840,6 +855,23 @@ F39117022AA9B79100852298 /* ElementsSizeFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementsSizeFilter.swift; sourceTree = ""; }; F39117042AA9B92500852298 /* ElementsPositionFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementsPositionFilter.swift; sourceTree = ""; }; F39117062AA9C69A00852298 /* ContentPositionFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPositionFilter.swift; sourceTree = ""; }; + F391170A2AB2E74F00852298 /* InappFilterServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InappFilterServiceTests.swift; sourceTree = ""; }; + F391170E2AB4B31800852298 /* unknownVariantType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = unknownVariantType.json; sourceTree = ""; }; + F39117102AB4BD4500852298 /* missingBackgroundSection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingBackgroundSection.json; sourceTree = ""; }; + F39117122AB4BD8500852298 /* emptyLayersSection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = emptyLayersSection.json; sourceTree = ""; }; + F39117142AB4BEB900852298 /* unknownLayerType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = unknownLayerType.json; sourceTree = ""; }; + F39117162AB4BF2700852298 /* knownImageUnknownPictureLayerType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = knownImageUnknownPictureLayerType.json; sourceTree = ""; }; + F39117182AB4C02500852298 /* unknownActionLayerType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = unknownActionLayerType.json; sourceTree = ""; }; + F391171A2AB4C07900852298 /* redirectUrlValueNumberInsteadOfString.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = redirectUrlValueNumberInsteadOfString.json; sourceTree = ""; }; + F391171C2AB4C0BE00852298 /* missingIntentPayloadInActionLayer.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingIntentPayloadInActionLayer.json; sourceTree = ""; }; + F391171E2AB4C1C100852298 /* missingSourceSection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingSourceSection.json; sourceTree = ""; }; + F39117202AB4C20200852298 /* emptyVariantsArray.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = emptyVariantsArray.json; sourceTree = ""; }; + F39117222AB4C23900852298 /* unknownSourceType.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = unknownSourceType.json; sourceTree = ""; }; + F39117242AB4C27B00852298 /* missingValueInSourceLayer.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingValueInSourceLayer.json; sourceTree = ""; }; + F39117262AB4C2AA00852298 /* missingImageLinkInSourceLayerValue.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingImageLinkInSourceLayerValue.json; sourceTree = ""; }; + F39117282AB4C2EF00852298 /* missingElementsSection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingElementsSection.json; sourceTree = ""; }; + F391172A2AB4C4AD00852298 /* invalidCloseButtonColor.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = invalidCloseButtonColor.json; sourceTree = ""; }; + F391172C2AB4C61000852298 /* ElementsColorFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementsColorFilter.swift; sourceTree = ""; }; F397EEAC2A4456C300D48CEC /* ProtocolError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolError.swift; sourceTree = ""; }; F397EEAE2A4456FD00D48CEC /* MindboxError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MindboxError.swift; sourceTree = ""; }; F397EEB02A44571300D48CEC /* UnknownDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnknownDecodable.swift; sourceTree = ""; }; @@ -887,6 +919,14 @@ F3D818B22A3885F50002957C /* ABTestDeviceMixerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ABTestDeviceMixerTests.swift; sourceTree = ""; }; F3D925AA2A120C0F00135C87 /* InAppImageDownloaderMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InAppImageDownloaderMock.swift; sourceTree = ""; }; F3D925AC2A1236F400135C87 /* URLSessionImageDownloaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionImageDownloaderTests.swift; sourceTree = ""; }; + F3FAD8692AB863CD00D98C03 /* missingCloseButtonColorLineWidthSize.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingCloseButtonColorLineWidthSize.json; sourceTree = ""; }; + F3FAD86B2AB8642C00D98C03 /* twoCloseButtonsInApp.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = twoCloseButtonsInApp.json; sourceTree = ""; }; + F3FAD86D2AB8656700D98C03 /* closeButtonWithOpenButton.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = closeButtonWithOpenButton.json; sourceTree = ""; }; + F3FAD86F2AB866B600D98C03 /* unknownSizeKind.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = unknownSizeKind.json; sourceTree = ""; }; + F3FAD8712AB8673100D98C03 /* missingMarginFieldInSection.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = missingMarginFieldInSection.json; sourceTree = ""; }; + F3FAD8732AB8678900D98C03 /* negativeCloseButtonSizeValues.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = negativeCloseButtonSizeValues.json; sourceTree = ""; }; + F3FAD8752AB867E700D98C03 /* closeButtonMarginAboveOne.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = closeButtonMarginAboveOne.json; sourceTree = ""; }; + F3FAD8772AB8685D00D98C03 /* closeButtonMarginBelowZero.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = closeButtonMarginBelowZero.json; sourceTree = ""; }; F78E92EE282E63320003B4A3 /* DispatchSemaphore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DispatchSemaphore.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1966,7 +2006,6 @@ isa = PBXGroup; children = ( F331DCBA2A80993600222120 /* InAppModel.swift */, - F331DCB92A80993600222120 /* InappValidator.swift */, F331DC8D2A80993600222120 /* InappForm */, ); path = InappModel; @@ -2018,7 +2057,6 @@ isa = PBXGroup; children = ( F331DC982A80993600222120 /* ContentElementSize.swift */, - F331DD572A8648DB00222120 /* ContentElementSizeValidator.swift */, F331DC992A80993600222120 /* Kind */, ); path = ContentElementSize; @@ -2045,7 +2083,6 @@ isa = PBXGroup; children = ( F331DCA12A80993600222120 /* ContentElementPositionMargin.swift */, - F331DCA42A80993600222120 /* ContentElementPositionMarginValidator.swift */, ); path = ContentElementPositionMargin; sourceTree = ""; @@ -2091,7 +2128,6 @@ F331DCDA2A80AC3300222120 /* ModelValidatorTests */ = { isa = PBXGroup; children = ( - F331DCE12A80B4C800222120 /* ContentElementPositionMarginValidatorTests.swift */, ); path = ModelValidatorTests; sourceTree = ""; @@ -2272,7 +2308,6 @@ isa = PBXGroup; children = ( F33608172A8A161200C7C9B7 /* ContentPositionMargin.swift */, - F33608192A8A163D00C7C9B7 /* ContentPositionMarginValidator.swift */, ); path = ContentPositionMargin; sourceTree = ""; @@ -2361,10 +2396,50 @@ F39117002AA9B68B00852298 /* ElementsFilter.swift */, F39117022AA9B79100852298 /* ElementsSizeFilter.swift */, F39117042AA9B92500852298 /* ElementsPositionFilter.swift */, + F391172C2AB4C61000852298 /* ElementsColorFilter.swift */, ); path = ElementsFiter; sourceTree = ""; }; + F391170C2AB4B2FC00852298 /* InappFilterServiceTests */ = { + isa = PBXGroup; + children = ( + F391170D2AB4B30600852298 /* JSON */, + F391170A2AB2E74F00852298 /* InappFilterServiceTests.swift */, + ); + path = InappFilterServiceTests; + sourceTree = ""; + }; + F391170D2AB4B30600852298 /* JSON */ = { + isa = PBXGroup; + children = ( + F3FAD8772AB8685D00D98C03 /* closeButtonMarginBelowZero.json */, + F3FAD8752AB867E700D98C03 /* closeButtonMarginAboveOne.json */, + F3FAD8732AB8678900D98C03 /* negativeCloseButtonSizeValues.json */, + F3FAD8712AB8673100D98C03 /* missingMarginFieldInSection.json */, + F3FAD86F2AB866B600D98C03 /* unknownSizeKind.json */, + F3FAD86D2AB8656700D98C03 /* closeButtonWithOpenButton.json */, + F3FAD86B2AB8642C00D98C03 /* twoCloseButtonsInApp.json */, + F3FAD8692AB863CD00D98C03 /* missingCloseButtonColorLineWidthSize.json */, + F391172A2AB4C4AD00852298 /* invalidCloseButtonColor.json */, + F39117282AB4C2EF00852298 /* missingElementsSection.json */, + F39117262AB4C2AA00852298 /* missingImageLinkInSourceLayerValue.json */, + F39117242AB4C27B00852298 /* missingValueInSourceLayer.json */, + F39117222AB4C23900852298 /* unknownSourceType.json */, + F39117202AB4C20200852298 /* emptyVariantsArray.json */, + F391171E2AB4C1C100852298 /* missingSourceSection.json */, + F391171C2AB4C0BE00852298 /* missingIntentPayloadInActionLayer.json */, + F391171A2AB4C07900852298 /* redirectUrlValueNumberInsteadOfString.json */, + F39117182AB4C02500852298 /* unknownActionLayerType.json */, + F39117162AB4BF2700852298 /* knownImageUnknownPictureLayerType.json */, + F39117142AB4BEB900852298 /* unknownLayerType.json */, + F39117122AB4BD8500852298 /* emptyLayersSection.json */, + F39117102AB4BD4500852298 /* missingBackgroundSection.json */, + F391170E2AB4B31800852298 /* unknownVariantType.json */, + ); + path = "JSON "; + sourceTree = ""; + }; F397EEAB2A4456A900D48CEC /* MindboxError */ = { isa = PBXGroup; children = ( @@ -2450,6 +2525,7 @@ F3A8B95B2A389EAD00E9C055 /* GeoServiceTests.swift */, F39B67A62A3C6C6A005C0CCA /* SegmentationServiceTests.swift */, F39116ED2AA53EE400852298 /* VariantImageUrlExtractorServiceTests.swift */, + F391170C2AB4B2FC00852298 /* InappFilterServiceTests */, ); path = InAppConfigurationMapperTests; sourceTree = ""; @@ -2693,21 +2769,34 @@ files = ( A1B940B7298104ED00B0F994 /* UnknownTargetingsModel.json in Resources */, F39B67C82A3FBEA7005C0CCA /* ConfigWithABTypeNotInapps.json in Resources */, + F3FAD8782AB8685D00D98C03 /* closeButtonMarginBelowZero.json in Resources */, + F39117132AB4BD8500852298 /* emptyLayersSection.json in Resources */, F39B67BC2A3FB9A8005C0CCA /* ConfigWithABNoSalt.json in Resources */, 31ED2DF325C4456600301FAD /* TestConfig_Invalid_1.plist in Resources */, + F39117192AB4C02500852298 /* unknownActionLayerType.json in Resources */, + F39117152AB4BEB900852298 /* unknownLayerType.json in Resources */, A153E04129BB0A8B003C34D4 /* InAppConfigurationWithOperations.json in Resources */, F31801FF2A386BE60021774C /* InappConfigResponseMonitoringInvalid.json in Resources */, 31ED2DF225C4456600301FAD /* TestConfig_Invalid_2.plist in Resources */, + F39117172AB4BF2700852298 /* knownImageUnknownPictureLayerType.json in Resources */, 31ED2DF425C4456600301FAD /* TestConfig_Invalid_3.plist in Resources */, + F3FAD8722AB8673100D98C03 /* missingMarginFieldInSection.json in Resources */, 84CC79AB25CAEBBB00C062BD /* TestEventConfig.plist in Resources */, F31801FB2A386A5B0021774C /* InappConfigResponseSettingsInvalid.json in Resources */, F39B67BE2A3FB9EF005C0CCA /* ConfigWithABUnexpectedValue.json in Resources */, A17958902978BE7000609E91 /* GeoTargetingModelValid.json in Resources */, + F3FAD86C2AB8642C00D98C03 /* twoCloseButtonsInApp.json in Resources */, + F3FAD8742AB8678900D98C03 /* negativeCloseButtonSizeValues.json in Resources */, F3A8B9452A38870100E9C055 /* MixerUUIDS.json in Resources */, + F391171B2AB4C07900852298 /* redirectUrlValueNumberInsteadOfString.json in Resources */, A179588D2978BE7000609E91 /* SegmentTargetingModelValid.json in Resources */, 9BE941F52916822900258077 /* InAppConfigurationInvalid.json in Resources */, + F3FAD8702AB866B600D98C03 /* unknownSizeKind.json in Resources */, + F3FAD86E2AB8656700D98C03 /* closeButtonWithOpenButton.json in Resources */, F39B67C22A3FBB19005C0CCA /* ConfigWithABNoUpper.json in Resources */, + F39117292AB4C2EF00852298 /* missingElementsSection.json in Resources */, F39B67C02A3FBA77005C0CCA /* ConfigWithABCrossRange.json in Resources */, + F3FAD8762AB867E700D98C03 /* closeButtonMarginAboveOne.json in Resources */, F31801FE2A386BE60021774C /* InappConfigResponseAbtestsInvalid.json in Resources */, A1A916E329C914C000D59D9E /* InAppConfigurationWithCategoryIDIn.json in Resources */, A17958922978C88B00609E91 /* AllTargetingsModelValid.json in Resources */, @@ -2715,16 +2804,26 @@ F39B67B32A3C8B1D005C0CCA /* ConfigWithAB_2.json in Resources */, A179588C2978BE7000609E91 /* OrTargetingModelValid.json in Resources */, A179588F2978BE7000609E91 /* TrueTargetingModelValid.json in Resources */, + F391172B2AB4C4AD00852298 /* invalidCloseButtonColor.json in Resources */, 31ED2DFA25C4459500301FAD /* TestConfig_Invalid_4.plist in Resources */, F39B67C62A3FBC47005C0CCA /* ConfigWithABNormal.json in Resources */, F31801F82A38649D0021774C /* InappConfigResponseValid.json in Resources */, F39B67B22A3C8B1D005C0CCA /* ConfigWithAB_1.json in Resources */, 84FCD3BD25CA10F600D1E574 /* SuccessResponse.json in Resources */, + F39117212AB4C20200852298 /* emptyVariantsArray.json in Resources */, + F39117252AB4C27B00852298 /* missingValueInSourceLayer.json in Resources */, F39B67C42A3FBB64005C0CCA /* ConfigWithABLowerBiggerThanUpper.json in Resources */, + F391171D2AB4C0BE00852298 /* missingIntentPayloadInActionLayer.json in Resources */, + F39117112AB4BD4500852298 /* missingBackgroundSection.json in Resources */, 31EB907425C402F900368FFB /* TestConfig2.plist in Resources */, 31EB907325C402F900368FFB /* TestConfig3.plist in Resources */, + F391170F2AB4B31800852298 /* unknownVariantType.json in Resources */, + F39117232AB4C23900852298 /* unknownSourceType.json in Resources */, + F391171F2AB4C1C100852298 /* missingSourceSection.json in Resources */, + F39117272AB4C2AA00852298 /* missingImageLinkInSourceLayerValue.json in Resources */, F39B67BA2A3FB943005C0CCA /* ConfigWithABBrokenRange.json in Resources */, 31A20D4925B6CBE000AAA0A3 /* TestConfig1.plist in Resources */, + F3FAD86A2AB863CD00D98C03 /* missingCloseButtonColorLineWidthSize.json in Resources */, 9BC24E7A28F6C08700C2619C /* InAppConfiguration.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2890,7 +2989,6 @@ 334F3AEB264C199900A6AC00 /* DiscountCardRequest.swift in Sources */, 31A20D4E25B6EFB600AAA0A3 /* MindboxDelegate.swift in Sources */, A179587A2978AEC600609E91 /* AndTargetingChecker.swift in Sources */, - F331DD582A8648DB00222120 /* ContentElementSizeValidator.swift in Sources */, F3482F1B2A65DC01002A41EC /* DefaultInappMessageDelegate.swift in Sources */, F331DD012A83A56500222120 /* InAppPresentationManager.swift in Sources */, 3337E6A3265FAB39006949EB /* BaseResponse.swift in Sources */, @@ -2968,6 +3066,7 @@ 84A0CD54260AF8C8004CD91B /* TrackClick.swift in Sources */, A1D017F02976CC8600CD9F99 /* OrTargeting.swift in Sources */, 334F3AEA264C199900A6AC00 /* CustomerRequest.swift in Sources */, + F391172D2AB4C61000852298 /* ElementsColorFilter.swift in Sources */, A15D701629AF810E007131E7 /* SDKLogsRequest.swift in Sources */, 33072F362664C4D7001F1AB2 /* RecommendationRequest.swift in Sources */, 84DC49CC25D1832300D5D758 /* EventWrapper.swift in Sources */, @@ -3040,7 +3139,6 @@ 33EBF0B0264E6283002A35D5 /* SessionManager.swift in Sources */, F331DD192A840D2100222120 /* ModalFormVariant.swift in Sources */, F331DD2E2A84CA8900222120 /* UrlLayerSource.swift in Sources */, - F336081A2A8A163D00C7C9B7 /* ContentPositionMarginValidator.swift in Sources */, 337C7952265646D10092B580 /* OperationBodyRequestType.swift in Sources */, 9B9C95312921116F00BB29DA /* UUIDDebugService.swift in Sources */, 6FDD1443266F7C1600A50C35 /* BalanceTypeReponse.swift in Sources */, @@ -3050,14 +3148,12 @@ 3191C2A625ADFD8000E7D6B9 /* Mindbox.swift in Sources */, A184654529C310F100E64780 /* InAppOperationJSONModel.swift in Sources */, A154E330299E0F1600F8F074 /* InAppGeoResponse.swift in Sources */, - F331DCC62A80993600222120 /* ContentElementPositionMarginValidator.swift in Sources */, F39B67A92A3C72E5005C0CCA /* ImageDownloadService.swift in Sources */, 84CC799725CACF5500C062BD /* MBEventRepository.swift in Sources */, F3482F172A65DBB7002A41EC /* MindboxURLHandlerDelegate.swift in Sources */, F33608182A8A161200C7C9B7 /* ContentPositionMargin.swift in Sources */, 847F581F25C8A3F500147A9A /* HTTPTypealiases.swift in Sources */, 33BEE8172681EC5F00993720 /* EventRoute.swift in Sources */, - F331DCD42A80993600222120 /* InappValidator.swift in Sources */, 317054CB25AF189800AE624C /* PersistenceStorage.swift in Sources */, F331DD092A83A56500222120 /* LayerFactory.swift in Sources */, F336080D2A8A142800C7C9B7 /* SnackbarFormVariant.swift in Sources */, @@ -3085,7 +3181,6 @@ A17958992978E04600609E91 /* InAppStub.swift in Sources */, F39B67A72A3C6C6A005C0CCA /* SegmentationServiceTests.swift in Sources */, F3D925AB2A120C0F00135C87 /* InAppImageDownloaderMock.swift in Sources */, - F331DCE22A80B4C800222120 /* ContentElementPositionMarginValidatorTests.swift in Sources */, A154E32E299E0D8900F8F074 /* SDKLogManagerTests.swift in Sources */, 9B52570728D1AF880029B1BC /* InAppPresentationManagerMock.swift in Sources */, 84B09FB42611C74400B0A06E /* MockDatabaseRepository.swift in Sources */, @@ -3119,6 +3214,7 @@ 848A89592620C3AE00EDFB6D /* APNSTokenGenerator.swift in Sources */, F3D818B32A3885F50002957C /* ABTestDeviceMixerTests.swift in Sources */, 9BC24E7728F6BF8C00C2619C /* InAppConfigResponseTests.swift in Sources */, + F391170B2AB2E74F00852298 /* InappFilterServiceTests.swift in Sources */, F39B67AC2A3C7315005C0CCA /* MockImageDownloadService.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Mindbox/DI/DependencyProvider.swift b/Mindbox/DI/DependencyProvider.swift index 945bad27..24a62b7e 100644 --- a/Mindbox/DI/DependencyProvider.swift +++ b/Mindbox/DI/DependencyProvider.swift @@ -74,8 +74,9 @@ final class DependencyProvider: DependencyContainer { let sourceFilter = LayersSourceFilterService() let layersFilterService = LayersFilterService(actionFilter: actionFilter, sourceFilter: sourceFilter) let sizeFilter = ElementSizeFilterService() + let colorFilter = ElementsColorFilterService() let positionFilter = ElementsPositionFilterService() - let elementsFilterService = ElementsFilterService(sizeFilter: sizeFilter, positionFilter: positionFilter) + let elementsFilterService = ElementsFilterService(sizeFilter: sizeFilter, positionFilter: positionFilter, colorFilter: colorFilter) let contentPositionFilterService = ContentPositionFilterService() let variantsFilterService = VariantFilterService(layersFilter: layersFilterService, elementsFilter: elementsFilterService, diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift index 69eedc1a..daf9d0ee 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift @@ -9,7 +9,7 @@ import Foundation protocol ContentPositionFilterProtocol { - func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition? + func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition } final class ContentPositionFilterService: ContentPositionFilterProtocol { @@ -20,7 +20,7 @@ final class ContentPositionFilterService: ContentPositionFilterProtocol { static let defaultContentPosition = ContentPosition(gravity: defaultGravity, margin: defaultMargin) } - func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition? { + func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition { guard let contentPosition = contentPosition else { return Constants.defaultContentPosition } @@ -54,7 +54,7 @@ final class ContentPositionFilterService: ContentPositionFilterProtocol { } guard let customMargin = customMargin else { - return nil + throw CustomDecodingError.unknownType("ContentPositionFilterService validation not passed. Inapp will be skipped.") } return ContentPosition(gravity: customGravity, margin: customMargin) diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsColorFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsColorFilter.swift new file mode 100644 index 00000000..10bbc678 --- /dev/null +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsColorFilter.swift @@ -0,0 +1,26 @@ +// +// ElementsColorFilterService.swift +// Mindbox +// +// Created by vailence on 15.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import Foundation + +protocol ElementsColorFilterProtocol { + func filter(_ color: String?) throws -> String +} + +final class ElementsColorFilterService: ElementsColorFilterProtocol { + enum Constants { + static let defaultColor = "#000000" + } + + func filter(_ color: String?) throws -> String { + guard let color = color else { + return Constants.defaultColor + } + return color.isHexValid() ? color : Constants.defaultColor + } +} diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift index ac997d86..782527bd 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift @@ -7,9 +7,10 @@ // import Foundation +import MindboxLogger protocol ElementsFilterProtocol { - func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement]? + func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement] } final class ElementsFilterService: ElementsFilterProtocol { @@ -21,13 +22,15 @@ final class ElementsFilterService: ElementsFilterProtocol { private let sizeFilter: ElementsSizeFilterProtocol private let positionFilter: ElementsPositionFilterProtocol + private let colorFilter: ElementsColorFilterProtocol - init(sizeFilter: ElementsSizeFilterProtocol, positionFilter: ElementsPositionFilterProtocol) { + init(sizeFilter: ElementsSizeFilterProtocol, positionFilter: ElementsPositionFilterProtocol, colorFilter: ElementsColorFilterProtocol) { self.sizeFilter = sizeFilter self.positionFilter = positionFilter + self.colorFilter = colorFilter } - func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement]? { + func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement] { guard let elements = elements, !elements.isEmpty else { return [] } @@ -41,12 +44,10 @@ final class ElementsFilterService: ElementsFilterProtocol { switch element { case .closeButton(let closeButtonElementDTO): - guard let size = try sizeFilter.filter(closeButtonElementDTO.size), - let position = try positionFilter.filter(closeButtonElementDTO.position) else { - return nil - } - - let customCloseButtonElement = CloseButtonElement(color: closeButtonElementDTO.color?.element ?? Constants.defaultColor, + let size = try sizeFilter.filter(closeButtonElementDTO.size) + let position = try positionFilter.filter(closeButtonElementDTO.position) + let color = try colorFilter.filter(closeButtonElementDTO.color?.element) + let customCloseButtonElement = CloseButtonElement(color: color, lineWidth: closeButtonElementDTO.lineWidth?.element ?? Constants.lineWidth, size: size, position: position) @@ -56,7 +57,7 @@ final class ElementsFilterService: ElementsFilterProtocol { continue elementsLoop } } - + return filteredElements } } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift index 9612d8a8..f818239c 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift @@ -9,7 +9,7 @@ import Foundation protocol ElementsPositionFilterProtocol { - func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition? + func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition } final class ElementsPositionFilterService: ElementsPositionFilterProtocol { @@ -19,7 +19,7 @@ final class ElementsPositionFilterService: ElementsPositionFilterProtocol { } - func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition? { + func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition { guard let position = position, let margin = position.margin else { return ContentElementPosition(margin: Constants.defaultMargin) @@ -48,6 +48,6 @@ final class ElementsPositionFilterService: ElementsPositionFilterProtocol { return ContentElementPosition(margin: Constants.defaultMargin) } - return nil + throw CustomDecodingError.unknownType("ElementsPositionFilterService validation not passed. In-app will be ignored.") } } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift index a3bab21c..074094ca 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift @@ -9,7 +9,7 @@ import Foundation protocol ElementsSizeFilterProtocol { - func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize? + func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize } final class ElementSizeFilterService: ElementsSizeFilterProtocol { @@ -17,7 +17,7 @@ final class ElementSizeFilterService: ElementsSizeFilterProtocol { static let defaultSize = ContentElementSize(kind: .dp, width: 24, height: 24) } - func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize? { + func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize { guard let size = size else { return Constants.defaultSize } @@ -34,6 +34,6 @@ final class ElementSizeFilterService: ElementsSizeFilterProtocol { return Constants.defaultSize } - return nil + throw CustomDecodingError.unknownType("ElementSizeFilterService validation not passed. In-app will be ignored.") } } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappFilter.swift index af2e8d8c..a254e2ce 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/InappFilter.swift @@ -15,23 +15,27 @@ protocol InappFilterProtocol { final class InappsFilterService: InappFilterProtocol { private let variantsFilter: VariantFilterProtocol + private let sdkVersionNumeric = 8 init(variantsFilter: VariantFilterProtocol) { self.variantsFilter = variantsFilter } func filter(inapps: [InAppDTO]?) -> [InApp] { - guard let inapps = inapps else { + guard var inapps = inapps else { Logger.common(message: "Received nil for in-apps. Returning an empty array.", level: .debug, category: .inAppMessages) return [] } + inapps = filterInappsBySDKVersion(inapps) + Logger.common(message: "Processing \(inapps.count) in-app(s).", level: .debug, category: .inAppMessages) var filteredInapps: [InApp] = [] for inapp in inapps { do { - if let variants = try variantsFilter.filter(inapp.form.variants), !variants.isEmpty { + let variants = try variantsFilter.filter(inapp.form.variants) + if !variants.isEmpty { let formModel = InAppForm(variants: variants) let inappModel = InApp(id: inapp.id, sdkVersion: inapp.sdkVersion, @@ -40,11 +44,24 @@ final class InappsFilterService: InappFilterProtocol { filteredInapps.append(inappModel) } } catch { - print("Error filtering variants for in-app with id \(inapp.id): \(error.localizedDescription)") + Logger.common(message: "In-app [ID:] \(inapp.id)\n[Error]: \(error)", level: .error, category: .inAppMessages) } } Logger.common(message: "Filtering process completed. \(filteredInapps.count) valid in-app(s) found.", level: .debug, category: .inAppMessages) return filteredInapps } + + func filterInappsBySDKVersion(_ inapps: [InAppDTO]) -> [InAppDTO] { + let inapps = inapps + + let filteredInapps = inapps.filter { + let minVersionValid = $0.sdkVersion.min.map { $0 <= sdkVersionNumeric } ?? false + let maxVersionValid = $0.sdkVersion.max.map { $0 >= sdkVersionNumeric } ?? true + + return minVersionValid && maxVersionValid + } + + return filteredInapps + } } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayerActionFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayerActionFilter.swift index 51c782f0..ea6c0400 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayerActionFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayerActionFilter.swift @@ -9,14 +9,14 @@ import Foundation protocol LayerActionFilterProtocol { - func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction? + func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction } final class LayerActionFilterService: LayerActionFilterProtocol { - func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction? { + func filter(_ action: ContentBackgroundLayerActionDTO?) throws -> ContentBackgroundLayerAction { guard let action = action, action.actionType != .unknown else { - return nil + throw CustomDecodingError.unknownType("LayerActionFilterService validation not passed.") } switch action { @@ -29,6 +29,6 @@ final class LayerActionFilterService: LayerActionFilterProtocol { break } - return nil + throw CustomDecodingError.unknownType("LayerActionFilterService validation not passed.") } } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift index 1ed4947d..a48374f6 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift @@ -10,7 +10,7 @@ import Foundation import MindboxLogger protocol LayersFilterProtocol { - func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer]? + func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer] } final class LayersFilterService: LayersFilterProtocol { @@ -22,24 +22,21 @@ final class LayersFilterService: LayersFilterProtocol { self.sourceFilter = sourceFilter } - func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer]? { + func filter(_ layers: [ContentBackgroundLayerDTO]?) throws -> [ContentBackgroundLayer] { var filteredLayers: [ContentBackgroundLayer] = [] guard let layers = layers else { - return nil + throw CustomDecodingError.unknownType("LayersFilterService validation not passed.") } for layer in layers { switch layer { case .image(let imageContentBackgroundLayerDTO): - if let action = try actionFilter.filter(imageContentBackgroundLayerDTO.action), - let source = try sourceFilter.filter(imageContentBackgroundLayerDTO.source) { - let imageLayer = ImageContentBackgroundLayer(action: action, source: source) - let newLayer = try ContentBackgroundLayer(type: layer.layerType, imageLayer: imageLayer) - filteredLayers.append(newLayer) - } else { - return [] - } + let action = try actionFilter.filter(imageContentBackgroundLayerDTO.action) + let source = try sourceFilter.filter(imageContentBackgroundLayerDTO.source) + let imageLayer = ImageContentBackgroundLayer(action: action, source: source) + let newLayer = try ContentBackgroundLayer(type: layer.layerType, imageLayer: imageLayer) + filteredLayers.append(newLayer) case .unknown: break } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersSourceFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersSourceFilter.swift index 2b2541bb..65a0e5d7 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersSourceFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersSourceFilter.swift @@ -9,19 +9,19 @@ import Foundation protocol LayersSourceFilterProtocol { - func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource? + func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource } final class LayersSourceFilterService: LayersSourceFilterProtocol { - func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource? { + func filter(_ source: ContentBackgroundLayerSourceDTO?) throws -> ContentBackgroundLayerSource { guard let source = source, source.sourceType != .unknown else { - return nil + throw CustomDecodingError.unknownType("LayersSourceFilterService validation not passed.") } switch source { case .url(let urlLayerSource): - if let value = urlLayerSource.value { + if let value = urlLayerSource.value, !value.isEmpty { let urlLayerSourceModel = UrlLayerSource(value: value) return try ContentBackgroundLayerSource(type: .url, urlModel: urlLayerSourceModel) } @@ -29,6 +29,6 @@ final class LayersSourceFilterService: LayersSourceFilterProtocol { break } - return nil + throw CustomDecodingError.unknownType("LayersSourceFilterService validation not passed.") } } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift index aa3435d6..312281e3 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift @@ -9,7 +9,7 @@ import Foundation protocol VariantFilterProtocol { - func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant]? + func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant] } final class VariantFilterService: VariantFilterProtocol { @@ -24,10 +24,10 @@ final class VariantFilterService: VariantFilterProtocol { self.contentPositionFilter = contentPositionFilter } - func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant]? { + func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant] { var resultVariants: [MindboxFormVariant] = [] guard let variants = variants else { - return nil + throw CustomDecodingError.unknownType("VariantFilterService validation not passed.") } variantsLoop: for variant in variants { @@ -35,13 +35,14 @@ final class VariantFilterService: VariantFilterProtocol { case .modal(let modalFormVariantDTO): guard let content = modalFormVariantDTO.content, let background = content.background else { - return nil + throw CustomDecodingError.unknownType("VariantFilterService validation not passed.") } - guard let filteredLayers = try layersFilter.filter(background.layers), - let fileterdElements = try elementsFilter.filter(content.elements) else { - return nil + let filteredLayers = try layersFilter.filter(background.layers) + if filteredLayers.isEmpty { + continue variantsLoop } + let fileterdElements = try elementsFilter.filter(content.elements) let backgroundModel = ContentBackground(layers: filteredLayers) @@ -52,14 +53,12 @@ final class VariantFilterService: VariantFilterProtocol { case .snackbar(let snackbarFormVariant): guard let content = snackbarFormVariant.content, let background = content.background else { - return nil + throw CustomDecodingError.unknownType("VariantFilterService validation not passed.") } - guard let filteredLayers = try layersFilter.filter(background.layers), - let filteredElements = try elementsFilter.filter(content.elements), - let contentPosition = try contentPositionFilter.filter(content.position) else { - return nil - } + let filteredLayers = try layersFilter.filter(background.layers) + let filteredElements = try elementsFilter.filter(content.elements) + let contentPosition = try contentPositionFilter.filter(content.position) let backgroundModel = ContentBackground(layers: filteredLayers) let contentModel = SnackbarFormVariantContent(background: backgroundModel, diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMarginValidator.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMarginValidator.swift deleted file mode 100644 index 851a1610..00000000 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementPosition/ContentElementPositionMargin/ContentElementPositionMarginValidator.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// ContentElementPositionMarginValidator.swift -// Mindbox -// -// Created by vailence on 04.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation - -class ContentElementPositionMarginValidator: Validator { - typealias T = ContentElementPositionMargin - - func isValid(item: ContentElementPositionMargin) -> Bool { - if item.kind == .unknown { - return false - } - - return isValidRange(value: item.top) && isValidRange(value: item.right) - } - - func isValidRange(value: Double?) -> Bool { - guard let value = value else { - return false - } - - return value >= 0 && value <= 1 - } -} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSizeValidator.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSizeValidator.swift deleted file mode 100644 index ad3c9cee..00000000 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentElement/ContentElementSize/ContentElementSizeValidator.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// ContentElementSizeValidator.swift -// Mindbox -// -// Created by vailence on 11.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation -import MindboxLogger - -class ContentElementSizeValidator: Validator { - typealias T = ContentElementSize - - func isValid(item: ContentElementSize) -> Bool { - guard item.width > 0 else { - Logger.common(message: "Content element size width is negative. Width: [\(item.width)", level: .error, category: .inAppMessages) - return false - - } - guard item.height > 0 else { - Logger.common(message: "Content element size height is negative. Height: [\(item.height)", level: .error, category: .inAppMessages) - return false - } - - return true - } -} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift index dc6d088b..2dfa92de 100644 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift +++ b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionGravity/ContentPositionGravity.swift @@ -22,24 +22,10 @@ enum GravityHorizontalType: String, Decodable { case left case right case center - case unknown - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let rawValue = try container.decode(RawValue.self) - self = GravityHorizontalType(rawValue: rawValue) ?? .unknown - } } enum GravityVerticalType: String, Decodable { case top case bottom case center - case unknown - - init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - let rawValue = try container.decode(RawValue.self) - self = GravityVerticalType(rawValue: rawValue) ?? .unknown - } } diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMarginValidator.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMarginValidator.swift deleted file mode 100644 index 3bb5923b..00000000 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappForm/InappFormVariant/InappFormVariantContent/ContentPosition/ContentPositionMargin/ContentPositionMarginValidator.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// ContentPositionMarginValidator.swift -// Mindbox -// -// Created by vailence on 14.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation - -class ContentPositionMarginValidator: Validator { - - typealias T = ContentPositionMargin - - func isValid(item: ContentPositionMargin) -> Bool { - if item.kind == .unknown { - return false - } - - return true - } -} diff --git a/Mindbox/InAppMessages/Models/Config/InappModel/InappValidator.swift b/Mindbox/InAppMessages/Models/Config/InappModel/InappValidator.swift deleted file mode 100644 index 9fea5641..00000000 --- a/Mindbox/InAppMessages/Models/Config/InappModel/InappValidator.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// InappValidator.swift -// Mindbox -// -// Created by vailence on 03.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation -import MindboxLogger - -class InappValidator: Validator { - typealias T = InApp - - private let sdkVersionValidator: SDKVersionValidator - - init() { - self.sdkVersionValidator = SDKVersionValidator(sdkVersionNumeric: Constants.Versions.sdkVersionNumeric) - } - - func isValid(item: InApp) -> Bool { - if item.id.isEmpty { - Logger.common(message: "In-app id cannot be empty. In-app will be ignored.", level: .error, category: .inAppMessages) - return false - } - - if !sdkVersionValidator.isValid(item: item.sdkVersion) { - Logger.common(message: "Invalid SDK version for In-app. In-app with id \(item.id) will be ignored.", level: .error, category: .inAppMessages) - return false - } - - return true - } -} diff --git a/Mindbox/Info.plist b/Mindbox/Info.plist index 5ab6c467..b7b98cc8 100644 --- a/Mindbox/Info.plist +++ b/Mindbox/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 4803 + 4888 diff --git a/MindboxTests/DI/TestDependencyProvider.swift b/MindboxTests/DI/TestDependencyProvider.swift index 53723f51..dac96f5e 100644 --- a/MindboxTests/DI/TestDependencyProvider.swift +++ b/MindboxTests/DI/TestDependencyProvider.swift @@ -11,6 +11,7 @@ import XCTest @testable import Mindbox final class TestDependencyProvider: DependencyContainer { + var inAppTargetingChecker: InAppTargetingChecker let inAppMessagesManager: InAppCoreManagerProtocol let utilitiesFetcher: UtilitiesFetcher @@ -30,6 +31,7 @@ final class TestDependencyProvider: DependencyContainer { var imageDownloadService: ImageDownloadServiceProtocol var abTestDeviceMixer: ABTestDeviceMixer var urlExtractorService: VariantImageUrlExtractorService + var inappFilterService: InappFilterProtocol init() throws { sessionTemporaryStorage = SessionTemporaryStorage() @@ -66,6 +68,18 @@ final class TestDependencyProvider: DependencyContainer { imageDownloadService = MockImageDownloadService() abTestDeviceMixer = ABTestDeviceMixer() urlExtractorService = VariantImageUrlExtractorService() + let actionFilter = LayerActionFilterService() + let sourceFilter = LayersSourceFilterService() + let layersFilterService = LayersFilterService(actionFilter: actionFilter, sourceFilter: sourceFilter) + let sizeFilter = ElementSizeFilterService() + let colorFilter = ElementsColorFilterService() + let positionFilter = ElementsPositionFilterService() + let elementsFilterService = ElementsFilterService(sizeFilter: sizeFilter, positionFilter: positionFilter, colorFilter: colorFilter) + let contentPositionFilterService = ContentPositionFilterService() + let variantsFilterService = VariantFilterService(layersFilter: layersFilterService, + elementsFilter: elementsFilterService, + contentPositionFilter: contentPositionFilterService) + inappFilterService = InappsFilterService(variantsFilter: variantsFilterService) } } diff --git a/MindboxTests/InApp/Tests/ABTesting/ABTests.swift b/MindboxTests/InApp/Tests/ABTesting/ABTests.swift index ebfe99e2..20ad9811 100644 --- a/MindboxTests/InApp/Tests/ABTesting/ABTests.swift +++ b/MindboxTests/InApp/Tests/ABTesting/ABTests.swift @@ -1,842 +1,843 @@ +//// +//// ABTests.swift +//// MindboxTests +//// +//// Created by vailence on 19.06.2023. +//// Copyright © 2023 Mindbox. All rights reserved. +//// // -// ABTests.swift -// MindboxTests -// -// Created by vailence on 19.06.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import Foundation -import XCTest -@testable import Mindbox - -class ABTests: XCTestCase { - - var container = try! TestDependencyProvider() - - var sessionTemporaryStorage: SessionTemporaryStorage { - container.sessionTemporaryStorage - } - - var persistenceStorage: PersistenceStorage { - container.persistenceStorage - } - - var networkFetcher: NetworkFetcher { - container.instanceFactory.makeNetworkFetcher() - } - - var sdkVersionValidator: SDKVersionValidator! - - private var mapper: InAppConfigutationMapper! - private let configStub = InAppConfigStub() - private let targetingChecker: InAppTargetingCheckerProtocol = InAppTargetingChecker() - private var shownInAppsIds: Set! - - override func setUp() { - super.setUp() - sdkVersionValidator = SDKVersionValidator(sdkVersionNumeric: 6) - mapper = InAppConfigutationMapper(geoService: container.geoService, - segmentationService: container.segmentationSevice, - customerSegmentsAPI: .live, - targetingChecker: targetingChecker, - sessionTemporaryStorage: sessionTemporaryStorage, - persistenceStorage: persistenceStorage, - sdkVersionValidator: sdkVersionValidator, - imageDownloadService: container.imageDownloadService, - urlExtractorService: container.urlExtractorService, - abTestDeviceMixer: container.abTestDeviceMixer) - shownInAppsIds = Set(persistenceStorage.shownInAppsIds ?? []) - } - - func test_no_abtests() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = nil - let inapps = mapper.filterInappsByABTests(abTests, responseInapps: response.inapps?.elements) - XCTAssertEqual(inapps.count, 3) - let expectedIds = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - - runInAppTestForUUID("BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - abTests: abTests, - responseInapps: response.inapps?.elements, - expectedCount: 3, expectedIds: expectedIds) - } - - func test_compare_inapps_with_cg() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 50), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 50, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .all, - inapps: nil - ) - ] - ) - ] - ) - ] - - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 0, expectedIds: []) // 25 - - let expectedIds = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 3, expectedIds: expectedIds) // 75 - } - - func test_compare_cg_and_concrete_inapps() throws { - let response = try getConfig(name: "ConfigWithAB_2") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 50), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 50, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 - let expectedIds1 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" - ] - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 2, expectedIds: expectedIds1) - - // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 4 - let expectedIds2 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "b33ca779-3c99-481f-ad46-91282b0caf04", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" - ] - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 4, expectedIds: expectedIds2) - } - - func test_compare_cg_and_concrete_inapps_and_all_inapps() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 30), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 30, upper: 65), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 65, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .all, - inapps: nil - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 0 - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 0, expectedIds: []) - - // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 2 - let expectedIds1 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 2, expectedIds: expectedIds1) - - // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 - let expectedIds2 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 3, expectedIds: expectedIds2) - } - - func test_compare_2branch_and_concrete_inapps_and_cg() throws { - let response = try getConfig(name: "ConfigWithAB_2") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 27), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 27, upper: 65), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 65, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 - let expectedIds1 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" - ] - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) - - // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 - let expectedIds2 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b", - "655f5ffa-de86-4224-a0bf-229fe208ed0d" - ] - runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) - - // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 - let expectedIds3 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) - } - - func test_compare_2branch_and_concrete_inapps() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 99), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 99, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 - let expectedIds1 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) - - // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 - let expectedIds2 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - runInAppTestForUUID("C9F84B44-01B9-A3C6-E85B-7FF816D3BA68", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) - } - - func test_aab_show_inapps_in_cg_branch() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 66), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 66, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4862ADF1-1392-9362-42A2-FF5A65629F50" with expected inapp count of 2 - let expectedIds1 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - runInAppTestForUUID("4862ADF1-1392-9362-42A2-FF5A65629F50", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 - - // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 - runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 45 - - let expectedIds2 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 - } - - func test_aab_not_show_inapps_in_cg_branch() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "c0e2682c-3d0f-4291-9308-9e48a16eb3c8", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 66), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 66, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "4862ADF1-1392-9362-42A2-FF5A65629F50" with expected inapp count of 2 - let expectedIds1 = [String]() - runInAppTestForUUID("4862ADF1-1392-9362-42A2-FF5A65629F50", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 - - // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 - runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 45 - - let expectedIds2 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 - } - - func test_ab_limit_value_check() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 99), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 99, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ) - ] - ) - ] - - // Test case for UUID "F3AB8877-CB55-CE3D-1AB3-230D2EA8A220" with expected inapp count of 2 - let expectedIds1 = ["6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] - runInAppTestForUUID("F3AB8877-CB55-CE3D-1AB3-230D2EA8A220", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 0 - - let expectedIds2 = [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - ] - // Test case for UUID "3A9F107E-9FBE-8D83-EFE9-5F093001CD54" with expected inapp count of 3 - runInAppTestForUUID("3A9F107E-9FBE-8D83-EFE9-5F093001CD54", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 33 - - let expectedIds3 = [ - "b33ca779-3c99-481f-ad46-91282b0caf04", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - ] - // Test case for UUID "59B675D6-9AF1-1805-2BB3-90C3CF11E5E0" with expected inapp count of 3 - runInAppTestForUUID("59B675D6-9AF1-1805-2BB3-90C3CF11E5E0", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 99 - } - - func test_compare_5_ab_tests_in_one_branch() throws { - let response = try getConfig(name: "ConfigWithAB_2") - let abTests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 10), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 10, upper: 20), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 20, upper: 30), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "479b3748-747e-476f-afcd-7a9ce3f0ec71", - modulus: ABTest.ABTestVariant.Modulus(lower: 30, upper: 70), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "5fb3e501-11c2-418d-b774-2ee26d31f556", - modulus: ABTest.ABTestVariant.Modulus(lower: 70, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .all, - inapps: nil - ) - ] - ) - ] - ) - ] - - // Test case for UUID "7544976E-FEA4-6A48-EB5D-85A6EEB4D306" with expected inapp count of 21 - let expectedIds1 = ["655f5ffa-de86-4224-a0bf-229fe208ed0d"] - runInAppTestForUUID("7544976E-FEA4-6A48-EB5D-85A6EEB4D306", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 5 - - let expectedIds2 = ["6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] - // Test case for UUID "618F8CA3-282D-5B18-7186-F2CF361ABD32" with expected inapp count of 1 - runInAppTestForUUID("618F8CA3-282D-5B18-7186-F2CF361ABD32", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 15 - - let expectedIds3 = ["b33ca779-3c99-481f-ad46-91282b0caf04"] - runInAppTestForUUID("DC0F2330-785B-5D80-CD34-F2F520AD618F", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 25 - - let expectedIds4 = ["d1b312bd-aa5c-414c-a0d8-8126376a2a9b"] - runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds4.count, expectedIds: expectedIds4) // 45 - - let expectedIds5 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", - "b33ca779-3c99-481f-ad46-91282b0caf04", - "d1b312bd-aa5c-414c-a0d8-8126376a2a9b"] - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds5.count, expectedIds: expectedIds5) // 75 - } - - func test_2_different_ab_tests_one() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abtests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "c0e2682c-3d0f-4291-9308-9e48a16eb3c8", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 25), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 25, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .all, - inapps: nil - ) - ] - ) - ] - ), - ABTest( - id: "1ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "b142ff09-68c4-41f9-985d-d220edfad4f", - variants: [ - ABTest.ABTestVariant( - id: "36e69720-8e73-447c-b172-7b17e2d73525", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 75), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [] - ) - ] - ), - ABTest.ABTestVariant( - id: "479b3748-747e-476f-afcd-7a9ce3f0ec71", - modulus: ABTest.ABTestVariant.Modulus(lower: 75, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - ) - ] - ) - ] - ) - ] - - let expectedIds1 = [String]() - runInAppTestForUUID("9d7f8e6c-3a2b-4d9a-b1c0-1e1e3a4b5c6d", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 23 and 29 - - runInAppTestForUUID("284c10f7-4f4c-4a1b-92e0-2318f2ae13c9", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 1 and 91 - - let expectedIds2 = ["b33ca779-3c99-481f-ad46-91282b0caf04"] - runInAppTestForUUID("677a789d-9a98-4f03-9cb2-af2563fc1d07", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 88 and 5 - - let expectedIds3 = ["b33ca779-3c99-481f-ad46-91282b0caf04", - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] - runInAppTestForUUID("d35df6c2-9e20-4f7e-9e20-51894e2c4810", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 61 and 94 - } - - func test_2_different_ab_tests_two() throws { -// XCTAssertTrue(false) - } - - func test_concrete_inapps_and_all() throws { - let response = try getConfig(name: "ConfigWithAB_1") - let abtests: [ABTest]? = [ - ABTest( - id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", - sdkVersion: SdkVersion(min: 6, max: nil), - salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", - variants: [ - ABTest.ABTestVariant( - id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", - modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 35), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .concrete, - inapps: [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - ) - ] - ), - ABTest.ABTestVariant( - id: "211f1c16-fa72-4456-bf87-af448eb84a32", - modulus: ABTest.ABTestVariant.Modulus(lower: 35, upper: 100), - objects: [ - ABTest.ABTestVariant.ABTestObject( - type: .inapps, - kind: .all, - inapps: nil - ) - ] - ) - ] - ) - ] - - // Test case for UUID "F3AB8877-CB55-CE3D-1AB3-230D2EA8A220" with expected inapp count of 2 - let expectedIds1 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04" - ] - - runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 - - let expectedIds2 = [ - "655f5ffa-de86-4224-a0bf-229fe208ed0d", - "b33ca779-3c99-481f-ad46-91282b0caf04", - "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" - ] - - runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 - } - - func test_section_ab_broken_return_nil() throws { - let response = try getConfig(name: "ConfigWithABBrokenRange") // Отсутствует диапазон 33-66 - XCTAssertNil(response.abtests) - - let response2 = try getConfig(name: "ConfigWithABNoSalt") // Отсутствует соль - XCTAssertNil(response2.abtests) - - let response3 = try getConfig(name: "ConfigWithABUnexpectedValue") // Неожиданное ключ-значение - XCTAssertNil(response3.abtests) - - let response4 = try getConfig(name: "ConfigWithABCrossRange") // Неожиданное ключ-значение - XCTAssertNil(response4.abtests) - - let response5 = try getConfig(name: "ConfigWithABNoUpper") // Отсутствует ключ upper в одном из вариантов - XCTAssertNil(response5.abtests) - - let response6 = try getConfig(name: "ConfigWithABLowerBiggerThanUpper") // Lower больше, чем Upper - XCTAssertNil(response6.abtests) - } - - func test_sdkversion_lower_than_ab_tests_version() throws { - let response = try getConfig(name: "ConfigWithABNormal") - XCTAssertNil(response.abtests) - } - - func test_ab_test_type_not_inapps_return_nil() throws { - let response = try getConfig(name: "ConfigWithABTypeNotInapps") - XCTAssertNil(response.abtests) - } -} - -private extension ABTests { - private func getConfig(name: String) throws -> ConfigResponse { - let bundle = Bundle(for: ABTests.self) - let fileURL = bundle.url(forResource: name, withExtension: "json")! - let data = try Data(contentsOf: fileURL) - return try JSONDecoder().decode(ConfigResponse.self, from: data) - } - - private func runInAppTestForUUID(_ uuid: String, abTests: [ABTest]?, responseInapps: [InApp]?, expectedCount: Int, expectedIds: [String]) { - persistenceStorage.deviceUUID = uuid - let inapps = mapper.filterInappsByABTests(abTests, responseInapps: responseInapps) - XCTAssertEqual(inapps.count, expectedCount) - for inapp in inapps { - XCTAssertTrue(expectedIds.contains { $0 == inapp.id }) - } - } -} +//import Foundation +//import XCTest +//@testable import Mindbox +// +//class ABTests: XCTestCase { +// +// var container = try! TestDependencyProvider() +// +// var sessionTemporaryStorage: SessionTemporaryStorage { +// container.sessionTemporaryStorage +// } +// +// var persistenceStorage: PersistenceStorage { +// container.persistenceStorage +// } +// +// var networkFetcher: NetworkFetcher { +// container.instanceFactory.makeNetworkFetcher() +// } +// +// var sdkVersionValidator: SDKVersionValidator! +// +// private var mapper: InAppConfigutationMapper! +// private let configStub = InAppConfigStub() +// private let targetingChecker: InAppTargetingCheckerProtocol = InAppTargetingChecker() +// private var shownInAppsIds: Set! +// +// override func setUp() { +// super.setUp() +// sdkVersionValidator = SDKVersionValidator(sdkVersionNumeric: 6) +// mapper = InAppConfigutationMapper(inappFilterService: container.inappFilterService, +// geoService: container.geoService, +// segmentationService: container.segmentationSevice, +// customerSegmentsAPI: .live, +// targetingChecker: targetingChecker, +// sessionTemporaryStorage: sessionTemporaryStorage, +// persistenceStorage: persistenceStorage, +// sdkVersionValidator: sdkVersionValidator, +// imageDownloadService: container.imageDownloadService, +// urlExtractorService: container.urlExtractorService, +// abTestDeviceMixer: container.abTestDeviceMixer) +// shownInAppsIds = Set(persistenceStorage.shownInAppsIds ?? []) +// } +// +// func test_no_abtests() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = nil +// let inapps = mapper.filterInappsByABTests(abTests, responseInapps: response.inapps?.elements) +// XCTAssertEqual(inapps.count, 3) +// let expectedIds = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// +// runInAppTestForUUID("BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// abTests: abTests, +// responseInapps: response.inapps?.elements, +// expectedCount: 3, expectedIds: expectedIds) +// } +// +// func test_compare_inapps_with_cg() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 50), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 50, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .all, +// inapps: nil +// ) +// ] +// ) +// ] +// ) +// ] +// +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 0, expectedIds: []) // 25 +// +// let expectedIds = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 3, expectedIds: expectedIds) // 75 +// } +// +// func test_compare_cg_and_concrete_inapps() throws { +// let response = try getConfig(name: "ConfigWithAB_2") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 50), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 50, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 +// let expectedIds1 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" +// ] +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 2, expectedIds: expectedIds1) +// +// // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 4 +// let expectedIds2 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "b33ca779-3c99-481f-ad46-91282b0caf04", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" +// ] +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 4, expectedIds: expectedIds2) +// } +// +// func test_compare_cg_and_concrete_inapps_and_all_inapps() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 30), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 30, upper: 65), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 65, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .all, +// inapps: nil +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 0 +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 0, expectedIds: []) +// +// // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 2 +// let expectedIds1 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 2, expectedIds: expectedIds1) +// +// // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 +// let expectedIds2 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: 3, expectedIds: expectedIds2) +// } +// +// func test_compare_2branch_and_concrete_inapps_and_cg() throws { +// let response = try getConfig(name: "ConfigWithAB_2") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 27), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 27, upper: 65), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 65, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 +// let expectedIds1 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" +// ] +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) +// +// // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 +// let expectedIds2 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b", +// "655f5ffa-de86-4224-a0bf-229fe208ed0d" +// ] +// runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) +// +// // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 +// let expectedIds3 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) +// } +// +// func test_compare_2branch_and_concrete_inapps() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 99), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 99, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4078E211-7C3F-C607-D35C-DC6B591EF355" with expected inapp count of 2 +// let expectedIds1 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) +// +// // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 +// let expectedIds2 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// runInAppTestForUUID("C9F84B44-01B9-A3C6-E85B-7FF816D3BA68", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) +// } +// +// func test_aab_show_inapps_in_cg_branch() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 66), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 66, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4862ADF1-1392-9362-42A2-FF5A65629F50" with expected inapp count of 2 +// let expectedIds1 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// runInAppTestForUUID("4862ADF1-1392-9362-42A2-FF5A65629F50", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 +// +// // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 +// runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 45 +// +// let expectedIds2 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 +// } +// +// func test_aab_not_show_inapps_in_cg_branch() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "c0e2682c-3d0f-4291-9308-9e48a16eb3c8", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 66), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 66, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "4862ADF1-1392-9362-42A2-FF5A65629F50" with expected inapp count of 2 +// let expectedIds1 = [String]() +// runInAppTestForUUID("4862ADF1-1392-9362-42A2-FF5A65629F50", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 +// +// // Test case for UUID "0809B0F8-8F21-18E8-2EF8-EC2D98938A84" with expected inapp count of 3 +// runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 45 +// +// let expectedIds2 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// // Test case for UUID "4D27710A-3F3A-FF6E-7764-375B1E06E05D" with expected inapp count of 3 +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 +// } +// +// func test_ab_limit_value_check() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 33), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 33, upper: 99), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 99, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "F3AB8877-CB55-CE3D-1AB3-230D2EA8A220" with expected inapp count of 2 +// let expectedIds1 = ["6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] +// runInAppTestForUUID("F3AB8877-CB55-CE3D-1AB3-230D2EA8A220", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 0 +// +// let expectedIds2 = [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// ] +// // Test case for UUID "3A9F107E-9FBE-8D83-EFE9-5F093001CD54" with expected inapp count of 3 +// runInAppTestForUUID("3A9F107E-9FBE-8D83-EFE9-5F093001CD54", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 33 +// +// let expectedIds3 = [ +// "b33ca779-3c99-481f-ad46-91282b0caf04", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// ] +// // Test case for UUID "59B675D6-9AF1-1805-2BB3-90C3CF11E5E0" with expected inapp count of 3 +// runInAppTestForUUID("59B675D6-9AF1-1805-2BB3-90C3CF11E5E0", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 99 +// } +// +// func test_compare_5_ab_tests_in_one_branch() throws { +// let response = try getConfig(name: "ConfigWithAB_2") +// let abTests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 10), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 10, upper: 20), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 20, upper: 30), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "479b3748-747e-476f-afcd-7a9ce3f0ec71", +// modulus: ABTest.ABTestVariant.Modulus(lower: 30, upper: 70), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "5fb3e501-11c2-418d-b774-2ee26d31f556", +// modulus: ABTest.ABTestVariant.Modulus(lower: 70, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .all, +// inapps: nil +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "7544976E-FEA4-6A48-EB5D-85A6EEB4D306" with expected inapp count of 21 +// let expectedIds1 = ["655f5ffa-de86-4224-a0bf-229fe208ed0d"] +// runInAppTestForUUID("7544976E-FEA4-6A48-EB5D-85A6EEB4D306", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 5 +// +// let expectedIds2 = ["6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] +// // Test case for UUID "618F8CA3-282D-5B18-7186-F2CF361ABD32" with expected inapp count of 1 +// runInAppTestForUUID("618F8CA3-282D-5B18-7186-F2CF361ABD32", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 15 +// +// let expectedIds3 = ["b33ca779-3c99-481f-ad46-91282b0caf04"] +// runInAppTestForUUID("DC0F2330-785B-5D80-CD34-F2F520AD618F", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 25 +// +// let expectedIds4 = ["d1b312bd-aa5c-414c-a0d8-8126376a2a9b"] +// runInAppTestForUUID("0809B0F8-8F21-18E8-2EF8-EC2D98938A84", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds4.count, expectedIds: expectedIds4) // 45 +// +// let expectedIds5 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83", +// "b33ca779-3c99-481f-ad46-91282b0caf04", +// "d1b312bd-aa5c-414c-a0d8-8126376a2a9b"] +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abTests, responseInapps: response.inapps?.elements, expectedCount: expectedIds5.count, expectedIds: expectedIds5) // 75 +// } +// +// func test_2_different_ab_tests_one() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abtests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "c0e2682c-3d0f-4291-9308-9e48a16eb3c8", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 25), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 25, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .all, +// inapps: nil +// ) +// ] +// ) +// ] +// ), +// ABTest( +// id: "1ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "b142ff09-68c4-41f9-985d-d220edfad4f", +// variants: [ +// ABTest.ABTestVariant( +// id: "36e69720-8e73-447c-b172-7b17e2d73525", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 75), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "479b3748-747e-476f-afcd-7a9ce3f0ec71", +// modulus: ABTest.ABTestVariant.Modulus(lower: 75, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// ) +// ] +// ) +// ] +// ) +// ] +// +// let expectedIds1 = [String]() +// runInAppTestForUUID("9d7f8e6c-3a2b-4d9a-b1c0-1e1e3a4b5c6d", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 23 and 29 +// +// runInAppTestForUUID("284c10f7-4f4c-4a1b-92e0-2318f2ae13c9", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 1 and 91 +// +// let expectedIds2 = ["b33ca779-3c99-481f-ad46-91282b0caf04"] +// runInAppTestForUUID("677a789d-9a98-4f03-9cb2-af2563fc1d07", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 88 and 5 +// +// let expectedIds3 = ["b33ca779-3c99-481f-ad46-91282b0caf04", +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83"] +// runInAppTestForUUID("d35df6c2-9e20-4f7e-9e20-51894e2c4810", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds3.count, expectedIds: expectedIds3) // 61 and 94 +// } +// +// func test_2_different_ab_tests_two() throws { +//// XCTAssertTrue(false) +// } +// +// func test_concrete_inapps_and_all() throws { +// let response = try getConfig(name: "ConfigWithAB_1") +// let abtests: [ABTest]? = [ +// ABTest( +// id: "0ec6be6b-421f-464b-9ee4-348a5292a5fd", +// sdkVersion: SdkVersion(min: 6, max: nil), +// salt: "BBBC2BA1-0B5B-4C9E-AB0E-95C54775B4F1", +// variants: [ +// ABTest.ABTestVariant( +// id: "155f5ffa-de86-4224-a0bf-229fe208ed0d", +// modulus: ABTest.ABTestVariant.Modulus(lower: 0, upper: 35), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .concrete, +// inapps: [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// ) +// ] +// ), +// ABTest.ABTestVariant( +// id: "211f1c16-fa72-4456-bf87-af448eb84a32", +// modulus: ABTest.ABTestVariant.Modulus(lower: 35, upper: 100), +// objects: [ +// ABTest.ABTestVariant.ABTestObject( +// type: .inapps, +// kind: .all, +// inapps: nil +// ) +// ] +// ) +// ] +// ) +// ] +// +// // Test case for UUID "F3AB8877-CB55-CE3D-1AB3-230D2EA8A220" with expected inapp count of 2 +// let expectedIds1 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04" +// ] +// +// runInAppTestForUUID("4078E211-7C3F-C607-D35C-DC6B591EF355", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds1.count, expectedIds: expectedIds1) // 25 +// +// let expectedIds2 = [ +// "655f5ffa-de86-4224-a0bf-229fe208ed0d", +// "b33ca779-3c99-481f-ad46-91282b0caf04", +// "6f93e2ef-0615-4e63-9c80-24bcb9e83b83" +// ] +// +// runInAppTestForUUID("4D27710A-3F3A-FF6E-7764-375B1E06E05D", abTests: abtests, responseInapps: response.inapps?.elements, expectedCount: expectedIds2.count, expectedIds: expectedIds2) // 75 +// } +// +// func test_section_ab_broken_return_nil() throws { +// let response = try getConfig(name: "ConfigWithABBrokenRange") // Отсутствует диапазон 33-66 +// XCTAssertNil(response.abtests) +// +// let response2 = try getConfig(name: "ConfigWithABNoSalt") // Отсутствует соль +// XCTAssertNil(response2.abtests) +// +// let response3 = try getConfig(name: "ConfigWithABUnexpectedValue") // Неожиданное ключ-значение +// XCTAssertNil(response3.abtests) +// +// let response4 = try getConfig(name: "ConfigWithABCrossRange") // Неожиданное ключ-значение +// XCTAssertNil(response4.abtests) +// +// let response5 = try getConfig(name: "ConfigWithABNoUpper") // Отсутствует ключ upper в одном из вариантов +// XCTAssertNil(response5.abtests) +// +// let response6 = try getConfig(name: "ConfigWithABLowerBiggerThanUpper") // Lower больше, чем Upper +// XCTAssertNil(response6.abtests) +// } +// +// func test_sdkversion_lower_than_ab_tests_version() throws { +// let response = try getConfig(name: "ConfigWithABNormal") +// XCTAssertNil(response.abtests) +// } +// +// func test_ab_test_type_not_inapps_return_nil() throws { +// let response = try getConfig(name: "ConfigWithABTypeNotInapps") +// XCTAssertNil(response.abtests) +// } +//} +// +//private extension ABTests { +// private func getConfig(name: String) throws -> ConfigResponse { +// let bundle = Bundle(for: ABTests.self) +// let fileURL = bundle.url(forResource: name, withExtension: "json")! +// let data = try Data(contentsOf: fileURL) +// return try JSONDecoder().decode(ConfigResponse.self, from: data) +// } +// +// private func runInAppTestForUUID(_ uuid: String, abTests: [ABTest]?, responseInapps: [InApp]?, expectedCount: Int, expectedIds: [String]) { +// persistenceStorage.deviceUUID = uuid +// let inapps = mapper.filterInappsByABTests(abTests, responseInapps: responseInapps) +// XCTAssertEqual(inapps.count, expectedCount) +// for inapp in inapps { +// XCTAssertTrue(expectedIds.contains { $0 == inapp.id }) +// } +// } +//} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/InappFilterServiceTests.swift b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/InappFilterServiceTests.swift new file mode 100644 index 00000000..9634cdf0 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/InappFilterServiceTests.swift @@ -0,0 +1,313 @@ +// +// InappFilterServiceTests.swift +// MindboxTests +// +// Created by vailence on 14.09.2023. +// Copyright © 2023 Mindbox. All rights reserved. +// + +import XCTest +@testable import Mindbox + +final class InappFilterServiceTests: XCTestCase { + + var sut: InappFilterProtocol! + var container = try! TestDependencyProvider() + + override func setUp() { + super.setUp() + sut = container.inappFilterService + } + + override func tearDown() { + sut = nil + super.tearDown() + } + + func test_unknown_type_for_variants() throws { + let config = try getConfig(name: "unknownVariantType") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_missingBackgroundSection() throws { + let config = try getConfig(name: "missingBackgroundSection") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_emptyLayersSection() throws { + let config = try getConfig(name: "emptyLayersSection") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_unknownLayerType() throws { + let config = try getConfig(name: "unknownLayerType") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_knownImageUnknownPictureLayerType() throws { + let config = try getConfig(name: "knownImageUnknownPictureLayerType") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + + case .modal(let model): + XCTAssertEqual(model.content.background.layers.count, 1) + default: + break + } + } + } + + func test_unknownActionLayerType() throws { + let config = try getConfig(name: "unknownActionLayerType") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_redirectUrlValueNumberInsteadOfString() throws { + let config = try getConfig(name: "redirectUrlValueNumberInsteadOfString") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_missingIntentPayloadInActionLayer() throws { + let config = try getConfig(name: "missingIntentPayloadInActionLayer") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_missingSourceSection() throws { + let config = try getConfig(name: "missingSourceSection") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_emptyVariantsArray() throws { + let config = try getConfig(name: "emptyVariantsArray") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_unknownSourceType() throws { + let config = try getConfig(name: "unknownSourceType") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_missingValueInSourceLayer() throws { + let config = try getConfig(name: "missingValueInSourceLayer") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_missingImageLinkInSourceLayerValue() throws { + let config = try getConfig(name: "missingImageLinkInSourceLayerValue") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_missingElementsSection() throws { + let config = try getConfig(name: "missingElementsSection") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + + case .modal(let model): + XCTAssertEqual(model.content.elements?.count, 0) + default: + break + } + } + } + + func test_invalidCloseButtonColor() throws { + let config = try getConfig(name: "invalidCloseButtonColor") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + case .modal(let model): + guard let type = model.content.elements?.first else { + assertionFailure("type not exists. ") + return + } + switch type { + case .closeButton(let model): + XCTAssertEqual(model.color, "#000000") + default: + break + } + default: + break + } + } + } + + func test_missingCloseButtonColorLineWidthSize() throws { + let config = try getConfig(name: "missingCloseButtonColorLineWidthSize") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + case .modal(let model): + guard let type = model.content.elements?.first else { + assertionFailure("type not exists.") + return + } + switch type { + case .closeButton(let model): + XCTAssertEqual(model.color, "#000000") + XCTAssertEqual(model.size.height, 24) + XCTAssertEqual(model.size.width, 24) + XCTAssertEqual(model.lineWidth, 1) + default: + break + } + default: + break + } + } + } + + func test_twoCloseButtonsInApp() throws { + let config = try getConfig(name: "twoCloseButtonsInApp") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + case .modal(let model): + guard let elements = model.content.elements else { + assertionFailure("elements not exists.") + return + } + + var counter = 0 + elements.forEach { + counter += $0.elementType == .closeButton ? 1 : 0 + } + + XCTAssertEqual(counter, 2) + default: + break + } + } + } + + func test_closeButtonWithOpenButton() throws { + let config = try getConfig(name: "closeButtonWithOpenButton") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + case .modal(let model): + guard let elements = model.content.elements else { + assertionFailure("elements not exists.") + return + } + + XCTAssertEqual(elements.count, 1) + switch elements.first! { + case .closeButton: + XCTAssertTrue(true) + return + default: + break + } + default: + break + } + } + + assertionFailure() + } + + func test_unknownSizeKind() throws { + let config = try getConfig(name: "unknownSizeKind") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 2) + + if let variant = inapps.first?.form.variants.first { + switch variant { + case .modal(let model): + guard let elements = model.content.elements else { + assertionFailure("elements not exists.") + return + } + + XCTAssertEqual(elements.count, 1) + switch elements.first! { + case .closeButton(let model): + XCTAssertEqual(model.size.kind, .dp) + XCTAssertEqual(model.size.width, 24) + XCTAssertEqual(model.size.height, 24) + return + default: + break + } + default: + break + } + } + + assertionFailure() + } + + func test_missingMarginFieldInSection() throws { + let config = try getConfig(name: "missingMarginFieldInSection") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_negativeCloseButtonSizeValues() throws { + let config = try getConfig(name: "negativeCloseButtonSizeValues") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_closeButtonMarginAboveOne() throws { + let config = try getConfig(name: "closeButtonMarginAboveOne") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + func test_closeButtonMarginBelowZero() throws { + let config = try getConfig(name: "closeButtonMarginBelowZero") + let inapps = sut.filter(inapps: config.inapps?.elements) + XCTAssertEqual(inapps.count, 1) + XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + } + + private func getConfig(name: String) throws -> ConfigResponse { + let bundle = Bundle(for: InappFilterServiceTests.self) + let fileURL = bundle.url(forResource: name, withExtension: "json")! + let data = try Data(contentsOf: fileURL) + return try JSONDecoder().decode(ConfigResponse.self, from: data) + } +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginAboveOne.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginAboveOne.json new file mode 100644 index 00000000..e704a754 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginAboveOne.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 1.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginBelowZero.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginBelowZero.json new file mode 100644 index 00000000..8a51697c --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginBelowZero.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": -0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonWithOpenButton.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonWithOpenButton.json new file mode 100644 index 00000000..47325400 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonWithOpenButton.json @@ -0,0 +1,225 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + }, + { + "$type": "openButton", + "color": "#000000", + "lineWidth": 8, + "size": { + "kind": "dp", + "width": 12, + "height": 12 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyLayersSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyLayersSection.json new file mode 100644 index 00000000..23bdddff --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyLayersSection.json @@ -0,0 +1,193 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyVariantsArray.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyVariantsArray.json new file mode 100644 index 00000000..9cca27b8 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyVariantsArray.json @@ -0,0 +1,160 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /invalidCloseButtonColor.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /invalidCloseButtonColor.json new file mode 100644 index 00000000..1aa4bf92 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /invalidCloseButtonColor.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#12345", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#0000FF", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /knownImageUnknownPictureLayerType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /knownImageUnknownPictureLayerType.json new file mode 100644 index 00000000..91b2b72a --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /knownImageUnknownPictureLayerType.json @@ -0,0 +1,218 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + }, + { + "$type": "picture", + "action": { + "$type": "redirectUrl", + "intentPayload": "", + "value": "https://weblinks.ru/wp-content/uploads/2021/11/sticker-png-number-numerical-digit-mathematics-three-openings-miscellaneous-text-730x573.png" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1644997173_1-fikiwiki-com-p-kartinki-tsifra-3-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingBackgroundSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingBackgroundSection.json new file mode 100644 index 00000000..fd32902d --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingBackgroundSection.json @@ -0,0 +1,190 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingCloseButtonColorLineWidthSize.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingCloseButtonColorLineWidthSize.json new file mode 100644 index 00000000..c2f91e83 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingCloseButtonColorLineWidthSize.json @@ -0,0 +1,199 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingElementsSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingElementsSection.json new file mode 100644 index 00000000..2e72d71a --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingElementsSection.json @@ -0,0 +1,164 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + } + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + } + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingImageLinkInSourceLayerValue.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingImageLinkInSourceLayerValue.json new file mode 100644 index 00000000..e9b1438c --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingImageLinkInSourceLayerValue.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingIntentPayloadInActionLayer.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingIntentPayloadInActionLayer.json new file mode 100644 index 00000000..52adbe8f --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingIntentPayloadInActionLayer.json @@ -0,0 +1,330 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "openUrl", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "modal payload_layer2", + "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-1-1.jpg" + }, + "source": { + "$type": "url", + "value": "https://nklk.ru/dll_image/4748.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "1496ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "snackbar", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "snackbar payload_layer1", + "value": "https://pushok-mindbox.onelink.me/13Z2/a97bb56f" + }, + "source": { + "$type": "url", + "value": "https://mobpush-images.mindbox.ru/Mpush-test/76/957c8dc6-c30a-4104-be17-839efa56ca3c.png" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-2-1.jpg" + }, + "source": { + "$type": "url", + "value": "https://nklk.ru/dll_image/4748.png" + } + } + ] + }, + "position": { + "gravity": { + "horizontal": "center", + "vertical": "bottom" + }, + "margin": { + "kind": "dp", + "top": 0.0, + "bottom": 0.0, + "left": 25.0, + "right": 25.0 + } + }, + "elements": [ + { + "$type": "closeButton", + "color": "#255F00", + "lineWidth": 3, + "size": { + "kind": "dp", + "width": 30, + "height": 30 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://cmt-shop.ru/upload/iblock/8bf/gderzvgs0nfly3flbn42ot4mxk1ozh7q/lineika_metall_kinex_1022.jpg", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingMarginFieldInSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingMarginFieldInSection.json new file mode 100644 index 00000000..1e53e7a0 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingMarginFieldInSection.json @@ -0,0 +1,205 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingSourceSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingSourceSection.json new file mode 100644 index 00000000..adee40c6 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingSourceSection.json @@ -0,0 +1,202 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingValueInSourceLayer.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingValueInSourceLayer.json new file mode 100644 index 00000000..058cb5a5 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingValueInSourceLayer.json @@ -0,0 +1,205 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /negativeCloseButtonSizeValues.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /negativeCloseButtonSizeValues.json new file mode 100644 index 00000000..2b2acf64 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /negativeCloseButtonSizeValues.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": -32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /redirectUrlValueNumberInsteadOfString.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /redirectUrlValueNumberInsteadOfString.json new file mode 100644 index 00000000..8307a76e --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /redirectUrlValueNumberInsteadOfString.json @@ -0,0 +1,332 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "modal payload_layer1", + "value": 12345 + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "modal payload_layer2", + "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-1-1.jpg" + }, + "source": { + "$type": "url", + "value": "https://nklk.ru/dll_image/4748.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "1496ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "snackbar", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "snackbar payload_layer1", + "value": 67890 + }, + "source": { + "$type": "url", + "value": "https://mobpush-images.mindbox.ru/Mpush-test/76/957c8dc6-c30a-4104-be17-839efa56ca3c.png" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "snackbar payload_layer2", + "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-2-1.jpg" + }, + "source": { + "$type": "url", + "value": "https://nklk.ru/dll_image/4748.png" + } + } + ] + }, + "position": { + "gravity": { + "horizontal": "center", + "vertical": "bottom" + }, + "margin": { + "kind": "dp", + "top": 0.0, + "bottom": 0.0, + "left": 25.0, + "right": 25.0 + } + }, + "elements": [ + { + "$type": "closeButton", + "color": "#255F00", + "lineWidth": 3, + "size": { + "kind": "dp", + "width": 30, + "height": 30 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://cmt-shop.ru/upload/iblock/8bf/gderzvgs0nfly3flbn42ot4mxk1ozh7q/lineika_metall_kinex_1022.jpg", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /twoCloseButtonsInApp.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /twoCloseButtonsInApp.json new file mode 100644 index 00000000..d2a0d102 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /twoCloseButtonsInApp.json @@ -0,0 +1,225 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 6, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + }, + { + "$type": "closeButton", + "color": "#FFFFFF", + "lineWidth": 2, + "size": { + "kind": "dp", + "width": 45, + "height": 45 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownActionLayerType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownActionLayerType.json new file mode 100644 index 00000000..8307a76e --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownActionLayerType.json @@ -0,0 +1,332 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "modal payload_layer1", + "value": 12345 + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "modal payload_layer2", + "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-1-1.jpg" + }, + "source": { + "$type": "url", + "value": "https://nklk.ru/dll_image/4748.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "1496ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "snackbar", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "snackbar payload_layer1", + "value": 67890 + }, + "source": { + "$type": "url", + "value": "https://mobpush-images.mindbox.ru/Mpush-test/76/957c8dc6-c30a-4104-be17-839efa56ca3c.png" + } + }, + { + "$type": "image", + "action": { + "$type": "openUrl", + "intentPayload": "snackbar payload_layer2", + "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-2-1.jpg" + }, + "source": { + "$type": "url", + "value": "https://nklk.ru/dll_image/4748.png" + } + } + ] + }, + "position": { + "gravity": { + "horizontal": "center", + "vertical": "bottom" + }, + "margin": { + "kind": "dp", + "top": 0.0, + "bottom": 0.0, + "left": 25.0, + "right": 25.0 + } + }, + "elements": [ + { + "$type": "closeButton", + "color": "#255F00", + "lineWidth": 3, + "size": { + "kind": "dp", + "width": 30, + "height": 30 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://cmt-shop.ru/upload/iblock/8bf/gderzvgs0nfly3flbn42ot4mxk1ozh7q/lineika_metall_kinex_1022.jpg", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0, + "bottom": 0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownLayerType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownLayerType.json new file mode 100644 index 00000000..b0a4de77 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownLayerType.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "picture", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSizeKind.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSizeKind.json new file mode 100644 index 00000000..719bdf97 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSizeKind.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "pixel", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSourceType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSourceType.json new file mode 100644 index 00000000..11802573 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSourceType.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "link", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownVariantType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownVariantType.json new file mode 100644 index 00000000..e56ba2b3 --- /dev/null +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownVariantType.json @@ -0,0 +1,206 @@ +{ + "monitoring": { + "logs": [ + { + "requestId": "4d37535e-f1c5-4c84-8622-58070601856e", + "deviceUUID": "d2170bcf-b83e-49dc-954c-67f909fbeb99", + "from": "2023-07-19T08:27:00", + "to": "2023-07-30T11:30:00" + } + ] + }, + "settings": { + "operations": { + "viewProduct": { + "systemName": "viewProduct" + }, + "viewCategory": { + "systemName": "viewCategory" + } + } + }, + "inapps": [ + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "window", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 1", + "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + }, + "source": { + "$type": "url", + "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "094c077d-d1b1-4030-8920-5fe56b4e4e27", + "sdkVersion": { + "min": 3, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "$type": "true" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", + "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "intentPayload": "test payload 1", + "$type": "simpleImage" + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 8, + "max": null + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "$type": "modal", + "imageUrl": "", + "redirectUrl": "", + "intentPayload": "", + "content": { + "background": { + "layers": [ + { + "$type": "image", + "action": { + "$type": "redirectUrl", + "intentPayload": "test payload 2", + "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + }, + "source": { + "$type": "url", + "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + } + } + ] + }, + "elements": [ + { + "$type": "closeButton", + "color": "#000000", + "lineWidth": 4, + "size": { + "kind": "dp", + "width": 32, + "height": 32 + }, + "position": { + "margin": { + "kind": "proportion", + "top": 0.03, + "right": 0.03, + "left": 0.0, + "bottom": 0.0 + } + } + } + ] + } + } + ] + } + }, + { + "id": "5696ac18-70cb-496f-80c5-a47eb7573df7", + "sdkVersion": { + "min": 4, + "max": 7 + }, + "targeting": { + "nodes": [ + { + "internalId": "93", + "systemName": "addAction", + "$type": "apiMethodCall" + } + ], + "$type": "and" + }, + "form": { + "variants": [ + { + "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", + "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "intentPayload": "test payload 2", + "$type": "simpleImage" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/MindboxTests/InApp/Tests/ModelValidatorTests/ContentElementPositionMarginValidatorTests.swift b/MindboxTests/InApp/Tests/ModelValidatorTests/ContentElementPositionMarginValidatorTests.swift deleted file mode 100644 index 1ff0dd94..00000000 --- a/MindboxTests/InApp/Tests/ModelValidatorTests/ContentElementPositionMarginValidatorTests.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// ContentElementPositionMarginValidatorTests.swift -// MindboxTests -// -// Created by vailence on 07.08.2023. -// Copyright © 2023 Mindbox. All rights reserved. -// - -import XCTest -@testable import Mindbox - -final class ContentElementPositionMarginValidatorTests: XCTestCase { - - var validator: ContentElementPositionMarginValidator! - var model: ContentElementPositionMargin! - - override func setUpWithError() throws { - validator = ContentElementPositionMarginValidator() - } - - override func tearDownWithError() throws { - validator = nil - model = nil - } - - func test_unknownCase_returnFalse() throws { - let model = ContentElementPositionMargin(kind: .unknown) - XCTAssertFalse(validator.isValid(item: model)) - } -} From e63bd3bd1bc9e0d2907eb83a63b59939792d02db Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Tue, 19 Sep 2023 13:06:27 +0600 Subject: [PATCH 11/28] MBX-2792 Fix names of url in stubs --- .../JSON /closeButtonMarginAboveOne.json | 16 ++++----- .../JSON /closeButtonMarginBelowZero.json | 18 +++++----- .../JSON /emptyLayersSection.json | 14 ++++---- .../JSON /emptyVariantsArray.json | 14 ++++---- .../JSON /invalidCloseButtonColor.json | 18 +++++----- .../knownImageUnknownPictureLayerType.json | 22 ++++++------ .../JSON /missingBackgroundSection.json | 14 ++++---- .../missingCloseButtonColorLineWidthSize.json | 18 +++++----- .../JSON /missingElementsSection.json | 16 ++++----- .../missingImageLinkInSourceLayerValue.json | 16 ++++----- .../missingIntentPayloadInActionLayer.json | 34 +++++++++---------- .../JSON /missingMarginFieldInSection.json | 18 +++++----- .../JSON /missingSourceSection.json | 16 ++++----- .../JSON /missingValueInSourceLayer.json | 16 ++++----- .../JSON /negativeCloseButtonSizeValues.json | 18 +++++----- ...redirectUrlValueNumberInsteadOfString.json | 30 ++++++++-------- .../JSON /twoCloseButtonsInApp.json | 18 +++++----- .../JSON /unknownActionLayerType.json | 30 ++++++++-------- .../JSON /unknownLayerType.json | 18 +++++----- .../JSON /unknownSizeKind.json | 18 +++++----- .../JSON /unknownSourceType.json | 18 +++++----- .../JSON /unknownVariantType.json | 18 +++++----- 22 files changed, 209 insertions(+), 209 deletions(-) diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginAboveOne.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginAboveOne.json index e704a754..31b59903 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginAboveOne.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginAboveOne.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -101,8 +101,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -140,11 +140,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -194,8 +194,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginBelowZero.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginBelowZero.json index 8a51697c..944cb679 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginBelowZero.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /closeButtonMarginBelowZero.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -101,8 +101,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -140,11 +140,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -194,8 +194,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -203,4 +203,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyLayersSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyLayersSection.json index 23bdddff..5719b9e3 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyLayersSection.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyLayersSection.json @@ -88,8 +88,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -127,11 +127,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -181,8 +181,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -190,4 +190,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyVariantsArray.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyVariantsArray.json index 9cca27b8..b92479f7 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyVariantsArray.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /emptyVariantsArray.json @@ -55,8 +55,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -94,11 +94,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -148,8 +148,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -157,4 +157,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /invalidCloseButtonColor.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /invalidCloseButtonColor.json index 1aa4bf92..ef9d3b74 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /invalidCloseButtonColor.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /invalidCloseButtonColor.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -101,8 +101,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -140,11 +140,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -194,8 +194,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -203,4 +203,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /knownImageUnknownPictureLayerType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /knownImageUnknownPictureLayerType.json index 91b2b72a..b62e65ce 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /knownImageUnknownPictureLayerType.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /knownImageUnknownPictureLayerType.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } }, { @@ -61,11 +61,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "", - "value": "https://weblinks.ru/wp-content/uploads/2021/11/sticker-png-number-numerical-digit-mathematics-three-openings-miscellaneous-text-730x573.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1644997173_1-fikiwiki-com-p-kartinki-tsifra-3-1.png" + "value": "1" } } ] @@ -113,8 +113,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -152,11 +152,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -206,8 +206,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -215,4 +215,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingBackgroundSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingBackgroundSection.json index fd32902d..e2d00bf3 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingBackgroundSection.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingBackgroundSection.json @@ -85,8 +85,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -124,11 +124,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -178,8 +178,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -187,4 +187,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingCloseButtonColorLineWidthSize.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingCloseButtonColorLineWidthSize.json index c2f91e83..74c00c49 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingCloseButtonColorLineWidthSize.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingCloseButtonColorLineWidthSize.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -94,8 +94,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -133,11 +133,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -187,8 +187,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -196,4 +196,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingElementsSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingElementsSection.json index 2e72d71a..f203b0e1 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingElementsSection.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingElementsSection.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -80,8 +80,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -119,11 +119,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -152,8 +152,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingImageLinkInSourceLayerValue.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingImageLinkInSourceLayerValue.json index e9b1438c..fe43e6b1 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingImageLinkInSourceLayerValue.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingImageLinkInSourceLayerValue.json @@ -49,7 +49,7 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", @@ -101,8 +101,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -140,11 +140,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -194,8 +194,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -203,4 +203,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingIntentPayloadInActionLayer.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingIntentPayloadInActionLayer.json index 52adbe8f..6d866c1f 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingIntentPayloadInActionLayer.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingIntentPayloadInActionLayer.json @@ -48,11 +48,11 @@ "$type": "image", "action": { "$type": "openUrl", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } }, { @@ -60,11 +60,11 @@ "action": { "$type": "openUrl", "intentPayload": "modal payload_layer2", - "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-1-1.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://nklk.ru/dll_image/4748.png" + "value": "1" } } ] @@ -112,8 +112,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -149,22 +149,22 @@ "action": { "$type": "redirectUrl", "intentPayload": "snackbar payload_layer1", - "value": "https://pushok-mindbox.onelink.me/13Z2/a97bb56f" + "value": "1" }, "source": { "$type": "url", - "value": "https://mobpush-images.mindbox.ru/Mpush-test/76/957c8dc6-c30a-4104-be17-839efa56ca3c.png" + "value": "1" } }, { "$type": "image", "action": { "$type": "openUrl", - "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-2-1.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://nklk.ru/dll_image/4748.png" + "value": "1" } } ] @@ -225,8 +225,8 @@ "form": { "variants": [ { - "imageUrl": "https://cmt-shop.ru/upload/iblock/8bf/gderzvgs0nfly3flbn42ot4mxk1ozh7q/lineika_metall_kinex_1022.jpg", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -264,11 +264,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -318,8 +318,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -327,4 +327,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingMarginFieldInSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingMarginFieldInSection.json index 1e53e7a0..12c41f7e 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingMarginFieldInSection.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingMarginFieldInSection.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -100,8 +100,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -139,11 +139,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -193,8 +193,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -202,4 +202,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingSourceSection.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingSourceSection.json index adee40c6..031292aa 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingSourceSection.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingSourceSection.json @@ -49,7 +49,7 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" } } ] @@ -97,8 +97,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -136,11 +136,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -190,8 +190,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -199,4 +199,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingValueInSourceLayer.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingValueInSourceLayer.json index 058cb5a5..85ae154c 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingValueInSourceLayer.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /missingValueInSourceLayer.json @@ -49,7 +49,7 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url" @@ -100,8 +100,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -139,11 +139,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -193,8 +193,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -202,4 +202,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /negativeCloseButtonSizeValues.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /negativeCloseButtonSizeValues.json index 2b2acf64..aa2b698f 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /negativeCloseButtonSizeValues.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /negativeCloseButtonSizeValues.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -101,8 +101,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -140,11 +140,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -194,8 +194,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -203,4 +203,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /redirectUrlValueNumberInsteadOfString.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /redirectUrlValueNumberInsteadOfString.json index 8307a76e..cd8732c3 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /redirectUrlValueNumberInsteadOfString.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /redirectUrlValueNumberInsteadOfString.json @@ -53,7 +53,7 @@ }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } }, { @@ -61,11 +61,11 @@ "action": { "$type": "openUrl", "intentPayload": "modal payload_layer2", - "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-1-1.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://nklk.ru/dll_image/4748.png" + "value": "1" } } ] @@ -113,8 +113,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -154,7 +154,7 @@ }, "source": { "$type": "url", - "value": "https://mobpush-images.mindbox.ru/Mpush-test/76/957c8dc6-c30a-4104-be17-839efa56ca3c.png" + "value": "1" } }, { @@ -162,11 +162,11 @@ "action": { "$type": "openUrl", "intentPayload": "snackbar payload_layer2", - "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-2-1.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://nklk.ru/dll_image/4748.png" + "value": "1" } } ] @@ -227,8 +227,8 @@ "form": { "variants": [ { - "imageUrl": "https://cmt-shop.ru/upload/iblock/8bf/gderzvgs0nfly3flbn42ot4mxk1ozh7q/lineika_metall_kinex_1022.jpg", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -266,11 +266,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -320,8 +320,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -329,4 +329,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /twoCloseButtonsInApp.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /twoCloseButtonsInApp.json index d2a0d102..f45591ed 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /twoCloseButtonsInApp.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /twoCloseButtonsInApp.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -120,8 +120,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -159,11 +159,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -213,8 +213,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -222,4 +222,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownActionLayerType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownActionLayerType.json index 8307a76e..cd8732c3 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownActionLayerType.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownActionLayerType.json @@ -53,7 +53,7 @@ }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } }, { @@ -61,11 +61,11 @@ "action": { "$type": "openUrl", "intentPayload": "modal payload_layer2", - "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-1-1.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://nklk.ru/dll_image/4748.png" + "value": "1" } } ] @@ -113,8 +113,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -154,7 +154,7 @@ }, "source": { "$type": "url", - "value": "https://mobpush-images.mindbox.ru/Mpush-test/76/957c8dc6-c30a-4104-be17-839efa56ca3c.png" + "value": "1" } }, { @@ -162,11 +162,11 @@ "action": { "$type": "openUrl", "intentPayload": "snackbar payload_layer2", - "value": "https://otkrit-ka.ru/uploads/posts/2021-07/foto-kartinki-cifra-2-1.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://nklk.ru/dll_image/4748.png" + "value": "1" } } ] @@ -227,8 +227,8 @@ "form": { "variants": [ { - "imageUrl": "https://cmt-shop.ru/upload/iblock/8bf/gderzvgs0nfly3flbn42ot4mxk1ozh7q/lineika_metall_kinex_1022.jpg", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -266,11 +266,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -320,8 +320,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -329,4 +329,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownLayerType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownLayerType.json index b0a4de77..f4237c4f 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownLayerType.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownLayerType.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -101,8 +101,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -140,11 +140,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -194,8 +194,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -203,4 +203,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSizeKind.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSizeKind.json index 719bdf97..d75098be 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSizeKind.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSizeKind.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -101,8 +101,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -140,11 +140,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -194,8 +194,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -203,4 +203,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSourceType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSourceType.json index 11802573..51eab6a9 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSourceType.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownSourceType.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "link", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -101,8 +101,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -140,11 +140,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -194,8 +194,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -203,4 +203,4 @@ } } ] -} \ No newline at end of file +} diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownVariantType.json b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownVariantType.json index e56ba2b3..af322c39 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownVariantType.json +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/JSON /unknownVariantType.json @@ -49,11 +49,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 1", - "value": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png" + "value": "1" }, "source": { "$type": "url", - "value": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg" + "value": "1" } } ] @@ -101,8 +101,8 @@ "form": { "variants": [ { - "imageUrl": "https://klike.net/uploads/posts/2020-06/1593061853_23.jpg", - "redirectUrl": "https://w7.pngwing.com/pngs/715/287/png-transparent-number-1-number-1-creative-cartoon.png", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 1", "$type": "simpleImage" } @@ -140,11 +140,11 @@ "action": { "$type": "redirectUrl", "intentPayload": "test payload 2", - "value": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg" + "value": "1" }, "source": { "$type": "url", - "value": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png" + "value": "1" } } ] @@ -194,8 +194,8 @@ "form": { "variants": [ { - "imageUrl": "https://fikiwiki.com/uploads/posts/2022-02/1645022241_1-fikiwiki-com-p-kartinki-tsifra-2-1.png", - "redirectUrl": "https://img.freepik.com/free-psd/a-3d-letter-2-with-a-yellow-background_220664-4522.jpg", + "imageUrl": "1", + "redirectUrl": "1", "intentPayload": "test payload 2", "$type": "simpleImage" } @@ -203,4 +203,4 @@ } } ] -} \ No newline at end of file +} From 0e7872e6b596316b298ab5645103ce2dcc8396b9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Sep 2023 20:21:00 +0000 Subject: [PATCH 12/28] Update dependency fastlane to v2.216.0 --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 428e2559..fac16515 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -17,8 +17,8 @@ GEM artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.824.0) - aws-sdk-core (3.181.1) + aws-partitions (1.825.0) + aws-sdk-core (3.182.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.5) From c546aa14b82402e6fe83474cbbbc0ba57c34ae04 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Wed, 20 Sep 2023 16:06:19 +0600 Subject: [PATCH 13/28] MBX-2792 New stuff --- .../InappFilterService/ElementsFiter/ElementsFilter.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift index 782527bd..f098971c 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift @@ -16,8 +16,8 @@ protocol ElementsFilterProtocol { final class ElementsFilterService: ElementsFilterProtocol { enum Constants { - static let defaultColor = "#000000" - static let lineWidth = 1 + static let defaultColor = "#FFFFFF" + static let lineWidth = 2 } private let sizeFilter: ElementsSizeFilterProtocol From 70ff74942eb264327834a58dd0dc1ca56405b1f2 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Wed, 20 Sep 2023 16:07:08 +0600 Subject: [PATCH 14/28] 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 f383302ed902029cfdb01037e1a6e3783295e290 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Thu, 21 Sep 2023 00:30:25 +0600 Subject: [PATCH 15/28] MBX-2792 Add default logs --- .../InappFilterService/ContentPositionFilter.swift | 7 +++++++ .../ElementsFiter/ElementsColorFilter.swift | 9 ++++++--- .../ElementsFiter/ElementsFilter.swift | 10 ++++++++-- .../ElementsFiter/ElementsPositionFilter.swift | 3 +++ .../ElementsFiter/ElementsSizeFilter.swift | 3 +++ .../Services/InappFilterService/VariantsFilter.swift | 1 + 6 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift index daf9d0ee..134729b3 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ContentPositionFilter.swift @@ -7,6 +7,7 @@ // import Foundation +import MindboxLogger protocol ContentPositionFilterProtocol { func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition @@ -22,6 +23,7 @@ final class ContentPositionFilterService: ContentPositionFilterProtocol { func filter(_ contentPosition: ContentPositionDTO?) throws -> ContentPosition { guard let contentPosition = contentPosition else { + Logger.common(message: "Content position is invalid or missing. Default value set: [\(Constants.defaultContentPosition)].", level: .debug, category: .inAppMessages) return Constants.defaultContentPosition } @@ -31,6 +33,7 @@ final class ContentPositionFilterService: ContentPositionFilterProtocol { let horizontal = gravity.horizontal ?? .center customGravity = ContentPositionGravity(vertical: vertical, horizontal: horizontal) } else { + Logger.common(message: "Gravity is invalid or missing. Default value set: [\(Constants.defaultGravity)].", level: .debug, category: .inAppMessages) customGravity = Constants.defaultGravity } @@ -49,8 +52,12 @@ final class ContentPositionFilterService: ContentPositionFilterProtocol { customMargin = ContentPositionMargin(kind: margin.kind, top: top, right: right, left: left, bottom: bottom) } case .unknown: + Logger.common(message: "Content position margin kind is unknown. Default value set: [\(Constants.defaultMargin)].", level: .debug, category: .inAppMessages) customMargin = Constants.defaultMargin } + } else { + Logger.common(message: "Content position margin is invalid or missing. Default value set: [\(Constants.defaultMargin)].", level: .debug, category: .inAppMessages) + customMargin = Constants.defaultMargin } guard let customMargin = customMargin else { diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsColorFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsColorFilter.swift index 10bbc678..8de5a184 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsColorFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsColorFilter.swift @@ -7,6 +7,7 @@ // import Foundation +import MindboxLogger protocol ElementsColorFilterProtocol { func filter(_ color: String?) throws -> String @@ -14,13 +15,15 @@ protocol ElementsColorFilterProtocol { final class ElementsColorFilterService: ElementsColorFilterProtocol { enum Constants { - static let defaultColor = "#000000" + static let defaultColor = "#FFFFFF" } func filter(_ color: String?) throws -> String { - guard let color = color else { + guard let color = color, color.isHexValid() else { + Logger.common(message: "Color is invalid or missing. Default value set: [\(Constants.defaultColor)]", level: .debug, category: .inAppMessages) return Constants.defaultColor } - return color.isHexValid() ? color : Constants.defaultColor + + return color } } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift index f098971c..4221fb55 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift @@ -16,7 +16,6 @@ protocol ElementsFilterProtocol { final class ElementsFilterService: ElementsFilterProtocol { enum Constants { - static let defaultColor = "#FFFFFF" static let lineWidth = 2 } @@ -47,8 +46,15 @@ final class ElementsFilterService: ElementsFilterProtocol { let size = try sizeFilter.filter(closeButtonElementDTO.size) let position = try positionFilter.filter(closeButtonElementDTO.position) let color = try colorFilter.filter(closeButtonElementDTO.color?.element) + var lineWidth: Int + if let lineWidthDTO = closeButtonElementDTO.lineWidth?.element { + lineWidth = lineWidthDTO + } else { + lineWidth = Constants.lineWidth + Logger.common(message: "Line width is invalid or missing. Default value set: [\(Constants.lineWidth)].", level: .debug, category: .inAppMessages) + } let customCloseButtonElement = CloseButtonElement(color: color, - lineWidth: closeButtonElementDTO.lineWidth?.element ?? Constants.lineWidth, + lineWidth: lineWidth, size: size, position: position) let element = try ContentElement(type: .closeButton, closeButton: customCloseButtonElement) diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift index f818239c..672d9a7c 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsPositionFilter.swift @@ -7,6 +7,7 @@ // import Foundation +import MindboxLogger protocol ElementsPositionFilterProtocol { func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition @@ -22,6 +23,7 @@ final class ElementsPositionFilterService: ElementsPositionFilterProtocol { func filter(_ position: ContentElementPositionDTO?) throws -> ContentElementPosition { guard let position = position, let margin = position.margin else { + Logger.common(message: "Position or margin is invalid or missing. Default value set: [\(Constants.defaultMargin)].", level: .debug, category: .inAppMessages) return ContentElementPosition(margin: Constants.defaultMargin) } @@ -45,6 +47,7 @@ final class ElementsPositionFilterService: ElementsPositionFilterProtocol { return ContentElementPosition(margin: customMargin) } case .unknown: + Logger.common(message: "Unknown type of ContentElementPosition. Default value set: [\(Constants.defaultMargin)].", level: .debug, category: .inAppMessages) return ContentElementPosition(margin: Constants.defaultMargin) } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift index 074094ca..3dd87127 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsSizeFilter.swift @@ -7,6 +7,7 @@ // import Foundation +import MindboxLogger protocol ElementsSizeFilterProtocol { func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize @@ -19,6 +20,7 @@ final class ElementSizeFilterService: ElementsSizeFilterProtocol { func filter(_ size: ContentElementSizeDTO?) throws -> ContentElementSize { guard let size = size else { + Logger.common(message: "Size is invalid or missing. Default value set: [\(Constants.defaultSize)].", level: .debug, category: .inAppMessages) return Constants.defaultSize } @@ -31,6 +33,7 @@ final class ElementSizeFilterService: ElementsSizeFilterProtocol { return ContentElementSize(kind: size.kind, width: width, height: height) } case .unknown: + Logger.common(message: "Unknown type of ContentElementSize. Default value set: [\(Constants.defaultSize)].", level: .debug, category: .inAppMessages) return Constants.defaultSize } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift index 312281e3..87cd5455 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift @@ -7,6 +7,7 @@ // import Foundation +import MindboxLogger protocol VariantFilterProtocol { func filter(_ variants: [MindboxFormVariantDTO]?) throws -> [MindboxFormVariant] From 007803c6f24bdd17a22a3432fd81c7d9f52ae21a Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Thu, 21 Sep 2023 00:42:06 +0600 Subject: [PATCH 16/28] MBX-2792 Added missed logs --- .../InappFilterService/ElementsFiter/ElementsFilter.swift | 1 + .../InappFilterService/LayersFilter/LayersFilter.swift | 5 +++++ .../Services/InappFilterService/VariantsFilter.swift | 4 +--- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift index 4221fb55..43cc0117 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift @@ -31,6 +31,7 @@ final class ElementsFilterService: ElementsFilterProtocol { func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement] { guard let elements = elements, !elements.isEmpty else { + Logger.common(message: "Elements are missing or empty. The variant will be skipped.", level: .debug, category: .inAppMessages) return [] } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift index a48374f6..a4eb6df3 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/LayersFilter/LayersFilter.swift @@ -38,10 +38,15 @@ final class LayersFilterService: LayersFilterProtocol { let newLayer = try ContentBackgroundLayer(type: layer.layerType, imageLayer: imageLayer) filteredLayers.append(newLayer) case .unknown: + Logger.common(message: "Unknown type of layer. Layer will be skipped.", level: .debug, category: .inAppMessages) break } } + if filteredLayers.isEmpty { + throw CustomDecodingError.unknownType("Layers cannot be empty. In-app will be skipped.") + } + return filteredLayers.filter { $0.layerType != .unknown } } } diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift index 87cd5455..d52c9476 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/VariantsFilter.swift @@ -40,9 +40,6 @@ final class VariantFilterService: VariantFilterProtocol { } let filteredLayers = try layersFilter.filter(background.layers) - if filteredLayers.isEmpty { - continue variantsLoop - } let fileterdElements = try elementsFilter.filter(content.elements) let backgroundModel = ContentBackground(layers: filteredLayers) @@ -69,6 +66,7 @@ final class VariantFilterService: VariantFilterProtocol { let mindboxFormVariant = try MindboxFormVariant(type: .snackbar, snackbarVariant: snackbarFormVariant) resultVariants.append(mindboxFormVariant) case .unknown: + Logger.common(message: "Unknown type of variant. Variant will be skipped.", level: .debug, category: .inAppMessages) continue } } From 99f2b37af2fe460f2dbf7d80c408efa7a108bce3 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Fri, 22 Sep 2023 12:36:37 +0600 Subject: [PATCH 17/28] MBX-2792 Fix log about elements --- .../InappFilterService/ElementsFiter/ElementsFilter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift index 43cc0117..3091772e 100644 --- a/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift +++ b/Mindbox/InAppMessages/InAppConfigurationMapper/Services/InappFilterService/ElementsFiter/ElementsFilter.swift @@ -31,7 +31,7 @@ final class ElementsFilterService: ElementsFilterProtocol { func filter(_ elements: [ContentElementDTO]?) throws -> [ContentElement] { guard let elements = elements, !elements.isEmpty else { - Logger.common(message: "Elements are missing or empty. The variant will be skipped.", level: .debug, category: .inAppMessages) + Logger.common(message: "Elements are missing or empty.", level: .debug, category: .inAppMessages) return [] } From a26447e9bf0391d48efafe1dd311349b3e44930e Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Mon, 25 Sep 2023 14:42:54 +0600 Subject: [PATCH 18/28] MBX-2792 Fix unit tests --- Mindbox/Info.plist | 2 +- .../InappFilterServiceTests.swift | 53 +++++++++++-------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/Mindbox/Info.plist b/Mindbox/Info.plist index b7b98cc8..ff4d699a 100644 --- a/Mindbox/Info.plist +++ b/Mindbox/Info.plist @@ -17,6 +17,6 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 4888 + 4895 diff --git a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/InappFilterServiceTests.swift b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/InappFilterServiceTests.swift index 9634cdf0..361d00cb 100644 --- a/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/InappFilterServiceTests.swift +++ b/MindboxTests/InApp/Tests/InAppConfigurationMapperTests/InappFilterServiceTests/InappFilterServiceTests.swift @@ -10,6 +10,13 @@ import XCTest @testable import Mindbox final class InappFilterServiceTests: XCTestCase { + + enum Constants { + static let defaultID = "5696ac18-70cb-496f-80c5-a47eb7573df7" + static let defaultColor = "#FFFFFF" + static let defaultLineWidth = 2 + static let defaultSize: Double = 24 + } var sut: InappFilterProtocol! var container = try! TestDependencyProvider() @@ -28,28 +35,28 @@ final class InappFilterServiceTests: XCTestCase { let config = try getConfig(name: "unknownVariantType") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_missingBackgroundSection() throws { let config = try getConfig(name: "missingBackgroundSection") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_emptyLayersSection() throws { let config = try getConfig(name: "emptyLayersSection") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_unknownLayerType() throws { let config = try getConfig(name: "unknownLayerType") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_knownImageUnknownPictureLayerType() throws { @@ -72,56 +79,56 @@ final class InappFilterServiceTests: XCTestCase { let config = try getConfig(name: "unknownActionLayerType") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_redirectUrlValueNumberInsteadOfString() throws { let config = try getConfig(name: "redirectUrlValueNumberInsteadOfString") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_missingIntentPayloadInActionLayer() throws { let config = try getConfig(name: "missingIntentPayloadInActionLayer") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_missingSourceSection() throws { let config = try getConfig(name: "missingSourceSection") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_emptyVariantsArray() throws { let config = try getConfig(name: "emptyVariantsArray") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_unknownSourceType() throws { let config = try getConfig(name: "unknownSourceType") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_missingValueInSourceLayer() throws { let config = try getConfig(name: "missingValueInSourceLayer") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_missingImageLinkInSourceLayerValue() throws { let config = try getConfig(name: "missingImageLinkInSourceLayerValue") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_missingElementsSection() throws { @@ -154,7 +161,7 @@ final class InappFilterServiceTests: XCTestCase { } switch type { case .closeButton(let model): - XCTAssertEqual(model.color, "#000000") + XCTAssertEqual(model.color, Constants.defaultColor) default: break } @@ -178,10 +185,10 @@ final class InappFilterServiceTests: XCTestCase { } switch type { case .closeButton(let model): - XCTAssertEqual(model.color, "#000000") - XCTAssertEqual(model.size.height, 24) - XCTAssertEqual(model.size.width, 24) - XCTAssertEqual(model.lineWidth, 1) + XCTAssertEqual(model.color, Constants.defaultColor) + XCTAssertEqual(model.size.height, Constants.defaultSize) + XCTAssertEqual(model.size.width, Constants.defaultSize) + XCTAssertEqual(model.lineWidth, Constants.defaultLineWidth) default: break } @@ -262,8 +269,8 @@ final class InappFilterServiceTests: XCTestCase { switch elements.first! { case .closeButton(let model): XCTAssertEqual(model.size.kind, .dp) - XCTAssertEqual(model.size.width, 24) - XCTAssertEqual(model.size.height, 24) + XCTAssertEqual(model.size.width, Constants.defaultSize) + XCTAssertEqual(model.size.height, Constants.defaultSize) return default: break @@ -280,28 +287,28 @@ final class InappFilterServiceTests: XCTestCase { let config = try getConfig(name: "missingMarginFieldInSection") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_negativeCloseButtonSizeValues() throws { let config = try getConfig(name: "negativeCloseButtonSizeValues") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_closeButtonMarginAboveOne() throws { let config = try getConfig(name: "closeButtonMarginAboveOne") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } func test_closeButtonMarginBelowZero() throws { let config = try getConfig(name: "closeButtonMarginBelowZero") let inapps = sut.filter(inapps: config.inapps?.elements) XCTAssertEqual(inapps.count, 1) - XCTAssertEqual(inapps.first?.id, "5696ac18-70cb-496f-80c5-a47eb7573df7") + XCTAssertEqual(inapps.first?.id, Constants.defaultID) } private func getConfig(name: String) throws -> ConfigResponse { From 338df1db5d7140c9da48fa62cd7e628ee5c8a400 Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Tue, 26 Sep 2023 13:01:37 +0600 Subject: [PATCH 19/28] 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 20/28] 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 21/28] 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 22/28] 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 23/28] 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 24/28] 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 25/28] 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 26/28] 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 27/28] 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.") From 139d808d97b948471d38143f5dc635672065fd5f Mon Sep 17 00:00:00 2001 From: Akylbek Utekeshev Date: Fri, 6 Oct 2023 20:16:41 +0600 Subject: [PATCH 28/28] Version UP 2.8.0 --- Mindbox.podspec | 2 +- MindboxNotifications.podspec | 2 +- SDKVersionProvider/SDKVersionConfig.xcconfig | 2 +- SDKVersionProvider/SDKVersionProvider.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Mindbox.podspec b/Mindbox.podspec index d95d9ab5..f9274af9 100644 --- a/Mindbox.podspec +++ b/Mindbox.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "Mindbox" - spec.version = "2.8.0-rc" + spec.version = "2.8.0" spec.summary = "SDK for integration with Mindbox" spec.description = "This library allows you to integrate data transfer to Mindbox Marketing Cloud" spec.homepage = "https://github.com/mindbox-cloud/ios-sdk" diff --git a/MindboxNotifications.podspec b/MindboxNotifications.podspec index 7565b752..79169eea 100644 --- a/MindboxNotifications.podspec +++ b/MindboxNotifications.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "MindboxNotifications" - spec.version = "2.8.0-rc" + spec.version = "2.8.0" spec.summary = "SDK for integration notifications with Mindbox" spec.description = "This library allows you to integrate notifications and transfer them to Mindbox Marketing Cloud" spec.homepage = "https://github.com/mindbox-cloud/ios-sdk" diff --git a/SDKVersionProvider/SDKVersionConfig.xcconfig b/SDKVersionProvider/SDKVersionConfig.xcconfig index 33935eff..2f2ba19a 100644 --- a/SDKVersionProvider/SDKVersionConfig.xcconfig +++ b/SDKVersionProvider/SDKVersionConfig.xcconfig @@ -1 +1 @@ -MARKETING_VERSION = 2.7.0 +MARKETING_VERSION = 2.8.0 diff --git a/SDKVersionProvider/SDKVersionProvider.swift b/SDKVersionProvider/SDKVersionProvider.swift index 1e6baf12..d752a873 100644 --- a/SDKVersionProvider/SDKVersionProvider.swift +++ b/SDKVersionProvider/SDKVersionProvider.swift @@ -8,5 +8,5 @@ import Foundation public class SDKVersionProvider { - public static let sdkVersion = "2.8.0-rc" + public static let sdkVersion = "2.8.0" }