From 4c35a63d757848a7d5ff078582e79a36d7012baf Mon Sep 17 00:00:00 2001 From: ArtemPavlov72 Date: Tue, 12 Sep 2023 16:46:45 +0500 Subject: [PATCH 1/4] To CubesScreenInteractor added hapticService - added func playHapticFeedback() - added func stopHapticFeedback() --- .../Interactor/CubesScreenInteractor.swift | 13 ++++++++++++- .../CubesScreenModule/View/CubesScreenView.swift | 6 +++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift index 44c3f85c..165b5a76 100644 --- a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift +++ b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift @@ -52,8 +52,9 @@ final class CubesScreenInteractor: CubesScreenInteractorInput { // MARK: - Private property - private var storageService: StorageService + private let storageService: StorageService private let buttonCounterService: ButtonCounterService + private let hapticService: HapticService private var cubesScreenModel: CubesScreenModel? { get { storageService.getData(from: CubesScreenModel.self) @@ -69,6 +70,7 @@ final class CubesScreenInteractor: CubesScreenInteractorInput { init(services: ApplicationServices) { storageService = services.storageService buttonCounterService = services.buttonCounterService + hapticService = services.hapticService } // MARK: - Internal func @@ -139,6 +141,15 @@ final class CubesScreenInteractor: CubesScreenInteractorInput { getContent() output?.cleanButtonWasSelected() } + + func playHapticFeedback() { + hapticService.play(isRepeat: true, + patternType: .feedingCrocodile) { _ in } + } + + func stopHapticFeedback() { + hapticService.stop() + } } // MARK: - Appearance diff --git a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift index b8c463c5..0634c468 100644 --- a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift +++ b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift @@ -72,7 +72,7 @@ final class CubesScreenView: CubesScreenViewProtocol { func updateContentWith(cubesType: CubesScreenModel.CubesType) { cubesSegmentedControl.selectedSegmentIndex = cubesType.rawValue cubesView.updateCubesWith(type: cubesType) - setButtinTitle() + setButtonTitle() } func updateContentWith(listResult: [String]) { @@ -165,7 +165,7 @@ private extension CubesScreenView { ]) } - func setButtinTitle() { + func setButtonTitle() { let appearance = Appearance() let cubeType = CubesScreenModel.CubesType(rawValue: cubesSegmentedControl.selectedSegmentIndex) ?? .cubesTwo let buttonTitle = cubeType == .cubesOne ? appearance.buttonOneCubeTitle : appearance.buttonSomeCubeTitle @@ -183,7 +183,7 @@ private extension CubesScreenView { output?.updateSelectedCountCubes(cubeType) cubesView.updateCubesWith(type: cubeType) - setButtinTitle() + setButtonTitle() } } From d5684ca28d05310f4c7535eeb9dc13f9f18612aa Mon Sep 17 00:00:00 2001 From: ArtemPavlov72 Date: Wed, 13 Sep 2023 23:44:37 +0500 Subject: [PATCH 2/4] playHapticFeedback add to CubesScreenModule --- .../Interactor/CubesScreenInteractor.swift | 6 ++++++ .../CubesScreenModule/Presenter/CubesScreenModule.swift | 2 ++ 2 files changed, 8 insertions(+) diff --git a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift index 165b5a76..57b74316 100644 --- a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift +++ b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift @@ -38,6 +38,12 @@ protocol CubesScreenInteractorInput { /// Кубики были подкинуты /// - Parameter totalValue: Сумма всех кубиков func diceAction(totalValue: Int) + + /// Запустить обратную связь от моторчика + func playHapticFeedback() + + /// Остановить обратную связь от моторчика + func stopHapticFeedback() /// Показать список генераций результатов /// - Parameter isShow: показать список генераций результатов diff --git a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Presenter/CubesScreenModule.swift b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Presenter/CubesScreenModule.swift index 99581298..70a97999 100644 --- a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Presenter/CubesScreenModule.swift +++ b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Presenter/CubesScreenModule.swift @@ -122,6 +122,7 @@ extension CubesScreenViewController: CubesScreenViewOutput { func diceAction(totalValue: Int) { interactor.diceAction(totalValue: totalValue) + interactor.playHapticFeedback() let listResult = factory.reverseListResult(interactor.returnCurrentModel().listResult) moduleView.updateContentWith(listResult: listResult) } @@ -137,6 +138,7 @@ extension CubesScreenViewController: CubesScreenInteractorOutput { func didReceive(model: CubesScreenModel) { moduleView.updateContentWith(cubesType: model.cubesType) copyButton.isEnabled = !interactor.returnCurrentModel().listResult.isEmpty + interactor.stopHapticFeedback() moduleView.listGenerated(isShow: model.isShowlistGenerated) } } From 81485bef9de20caf7340fcf867cdeb84caf2891e Mon Sep 17 00:00:00 2001 From: ArtemPavlov72 Date: Fri, 15 Sep 2023 01:20:27 +0500 Subject: [PATCH 3/4] Add func physicsWorls to CubesView + updated walls in CubesView + add feedbackGeneratorAction() in CubesView --- .../Interactor/CubesScreenInteractor.swift | 14 ++-- .../Presenter/CubesScreenModule.swift | 6 +- .../View/CubesScreenView.swift | 8 +++ .../CubesScreenModule/View/CubesView.swift | 68 ++++++++++++++++--- 4 files changed, 74 insertions(+), 22 deletions(-) diff --git a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift index 57b74316..a41bd46e 100644 --- a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift +++ b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Interactor/CubesScreenInteractor.swift @@ -41,9 +41,6 @@ protocol CubesScreenInteractorInput { /// Запустить обратную связь от моторчика func playHapticFeedback() - - /// Остановить обратную связь от моторчика - func stopHapticFeedback() /// Показать список генераций результатов /// - Parameter isShow: показать список генераций результатов @@ -149,12 +146,11 @@ final class CubesScreenInteractor: CubesScreenInteractorInput { } func playHapticFeedback() { - hapticService.play(isRepeat: true, - patternType: .feedingCrocodile) { _ in } - } - - func stopHapticFeedback() { - hapticService.stop() + DispatchQueue.main.async { [weak self] in + self?.hapticService.play(isRepeat: false, + patternType: .splash, + completion: {_ in }) + } } } diff --git a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Presenter/CubesScreenModule.swift b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Presenter/CubesScreenModule.swift index 70a97999..2467c2c1 100644 --- a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Presenter/CubesScreenModule.swift +++ b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/Presenter/CubesScreenModule.swift @@ -116,13 +116,16 @@ final class CubesScreenViewController: CubesScreenModule { // MARK: - CubesScreenViewOutput extension CubesScreenViewController: CubesScreenViewOutput { + func playHapticFeedbackAction() { + interactor.playHapticFeedback() + } + func updateSelectedCountCubes(_ cubesType: CubesScreenModel.CubesType) { interactor.updateSelectedCountCubes(cubesType) } func diceAction(totalValue: Int) { interactor.diceAction(totalValue: totalValue) - interactor.playHapticFeedback() let listResult = factory.reverseListResult(interactor.returnCurrentModel().listResult) moduleView.updateContentWith(listResult: listResult) } @@ -138,7 +141,6 @@ extension CubesScreenViewController: CubesScreenInteractorOutput { func didReceive(model: CubesScreenModel) { moduleView.updateContentWith(cubesType: model.cubesType) copyButton.isEnabled = !interactor.returnCurrentModel().listResult.isEmpty - interactor.stopHapticFeedback() moduleView.listGenerated(isShow: model.isShowlistGenerated) } } diff --git a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift index 0634c468..b021399c 100644 --- a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift +++ b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift @@ -20,6 +20,9 @@ protocol CubesScreenViewOutput: AnyObject { /// Кубики были подкинуты /// - Parameter totalValue: Сумма всех кубиков func diceAction(totalValue: Int) + + /// Пользователь нажал на кнопку генерации + func playHapticFeedbackAction() } /// События которые отправляем от Presenter ко View @@ -128,6 +131,10 @@ private extension CubesScreenView { self.counter = .zero } } + + cubesView.feedbackGeneratorAction = { [weak self] in + self?.output?.playHapticFeedbackAction() + } } func setupConstraints() { @@ -174,6 +181,7 @@ private extension CubesScreenView { @objc func generateButtonAction() { + output?.playHapticFeedbackAction() cubesView.handleTap() } diff --git a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesView.swift b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesView.swift index af703f90..520b04af 100644 --- a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesView.swift +++ b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesView.swift @@ -17,6 +17,7 @@ final class CubesView: UIView { // MARK: - Internal properties var totalValueDiceAction: ((Int) -> Void)? + var feedbackGeneratorAction: (() -> Void)? // MARK: - Private properties @@ -60,6 +61,27 @@ final class CubesView: UIView { } } +// MARK: - SCNPhysicsContactDelegate + +extension CubesView: SCNPhysicsContactDelegate { + func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) { + let appearance = Appearance() + + if (contact.nodeA.name == appearance.cubesNodeName && contact.nodeB.name == appearance.positionFloor) || + (contact.nodeA.name == appearance.positionFloor && contact.nodeB.name == appearance.cubesNodeName) || + (contact.nodeA.name == appearance.cubesNodeName && contact.nodeB.name == appearance.positionLeft) || + (contact.nodeA.name == appearance.positionLeft && contact.nodeB.name == appearance.cubesNodeName) || + (contact.nodeA.name == appearance.cubesNodeName && contact.nodeB.name == appearance.positionRight) || + (contact.nodeA.name == appearance.positionRight && contact.nodeB.name == appearance.cubesNodeName) || + (contact.nodeA.name == appearance.cubesNodeName && contact.nodeB.name == appearance.positionFront) || + (contact.nodeA.name == appearance.positionFront && contact.nodeB.name == appearance.cubesNodeName) || + (contact.nodeA.name == appearance.cubesNodeName && contact.nodeB.name == appearance.positionBack) || + (contact.nodeA.name == appearance.positionBack && contact.nodeB.name == appearance.cubesNodeName) { + feedbackGeneratorAction?() + } + } +} + // MARK: - SCNSceneRendererDelegate extension CubesView: SCNSceneRendererDelegate { @@ -99,10 +121,10 @@ private extension SCNVector3 { private extension CubesView { func randomPosition() -> SCNVector3 { - let x = Float.random(in: -5...5) - let y = Float.random(in: 0...10) - let z = Float.random(in: -5...5) - return SCNVector3(x, y, z) + let x = Float.random(in: -5...5) + let y = Float.random(in: 0...10) + let z = Float.random(in: -5...5) + return SCNVector3(x, y, z) } func reposition(_ node: SCNNode, to position: SCNVector3, with normal: SCNVector3) { @@ -132,12 +154,14 @@ private extension CubesView { func wall(at position: SCNVector3, with normal: SCNVector3, sized size: CGSize, + name: String, color: UIColor = .clear) -> SCNNode { let geometry = SCNPlane(width: size.width, height: size.height) geometry.materials.first?.diffuse.contents = color geometry.materials.first?.isDoubleSided = true let geometryNode = SCNNode(geometry: geometry) + geometryNode.name = name geometryNode.physicsBody = SCNPhysicsBody(type: .static, shape: nil) geometryNode.physicsBody?.collisionBitMask = 1 geometryNode.physicsBody?.contactTestBitMask = 1 @@ -229,6 +253,7 @@ private extension CubesView { } func setupScene() { + let appearance = Appearance() scnView.scene = scnScene setupCamera() setupLight() @@ -238,21 +263,33 @@ private extension CubesView { let walls = [ // верхняя стена X,Y,Z - (position: SCNVector3(0, 13, 0), normal: SCNVector3Make(0, -1, 0)), + (position: SCNVector3(0, 13, 0), + normal: SCNVector3Make(0, -1, 0), + name: appearance.positionTop), // нижняя стена X,Y,Z - (position: SCNVector3(0, -8, 0), normal: SCNVector3Make(0, 1, 0)), + (position: SCNVector3(0, -8, 0), + normal: SCNVector3Make(0, 1, 0), + name: appearance.positionFloor), // правая стена X,Y,Z - (position: SCNVector3(7, -8, 0), normal: SCNVector3Make(-1, 0, 0)), + (position: SCNVector3(7, -8, 0), + normal: SCNVector3Make(-1, 0, 0), + name: appearance.positionRight), // левая стена X,Y,Z - (position: SCNVector3(-7, -8, 0), normal: SCNVector3Make(1, 0, 0)), + (position: SCNVector3(-7, -8, 0), + normal: SCNVector3Make(1, 0, 0), + name: appearance.positionLeft), // задняя стена X,Y,Z - (position: SCNVector3(0, -8, 11), normal: SCNVector3Make(0, 0, -1)), + (position: SCNVector3(0, -8, 11), + normal: SCNVector3Make(0, 0, -1), + name: appearance.positionBack), // передняя стена X,Y,Z - (position: SCNVector3(0, -8, -11), normal: SCNVector3Make(0, 0, 1)) + (position: SCNVector3(0, -8, -11), + normal: SCNVector3Make(0, 0, 1), + name: appearance.positionFront) ] for wall in walls { - let panel = self.wall(at: wall.position, with: wall.normal, sized: wallSize) + let panel = self.wall(at: wall.position, with: wall.normal, sized: wallSize, name: wall.name) scnScene.rootNode.addChildNode(panel) } } @@ -407,5 +444,14 @@ private extension CubesView { let numberFour: Int = 4 let numberFive: Int = 5 let numberSix: Int = 6 + + let positionTop = "Top" + let positionFloor = "Floor" + let positionRight = "Right" + let positionLeft = "Left" + let positionBack = "Back" + let positionFront = "Front" + + let cubesNodeName = "Cube" } } From 0262eb4e3b30cf7ab57631818560fe9f0b97150e Mon Sep 17 00:00:00 2001 From: ArtemPavlov72 Date: Sun, 17 Sep 2023 00:12:24 +0500 Subject: [PATCH 4/4] fix coinScreenView & cubesScreenView --- .../MainScreen/CoinScreenModule/View/CoinScreenView.swift | 1 - .../MainScreen/CubesScreenModule/View/CubesScreenView.swift | 1 - 2 files changed, 2 deletions(-) diff --git a/Random/App/Sources/Modules/MainScreen/CoinScreenModule/View/CoinScreenView.swift b/Random/App/Sources/Modules/MainScreen/CoinScreenModule/View/CoinScreenView.swift index 270923e4..ce1fd07b 100644 --- a/Random/App/Sources/Modules/MainScreen/CoinScreenModule/View/CoinScreenView.swift +++ b/Random/App/Sources/Modules/MainScreen/CoinScreenModule/View/CoinScreenView.swift @@ -158,7 +158,6 @@ private extension CoinScreenView { @objc func generateButtonAction() { - output?.playHapticFeedbackAction() output?.generateButtonAction() resultLabel.text = "" coinView.handleTap() diff --git a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift index b021399c..eedca5b0 100644 --- a/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift +++ b/Random/App/Sources/Modules/MainScreen/CubesScreenModule/View/CubesScreenView.swift @@ -181,7 +181,6 @@ private extension CubesScreenView { @objc func generateButtonAction() { - output?.playHapticFeedbackAction() cubesView.handleTap() }