diff --git a/Framework/FloatingPanel.xcodeproj/project.pbxproj b/Framework/FloatingPanel.xcodeproj/project.pbxproj index 10e685e..2521373 100644 --- a/Framework/FloatingPanel.xcodeproj/project.pbxproj +++ b/Framework/FloatingPanel.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 542753C622C49A6E00D17955 /* FloatingPanelLayoutTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 542753C522C49A6E00D17955 /* FloatingPanelLayoutTests.swift */; }; + 542753C822C49A8F00D17955 /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 542753C722C49A8F00D17955 /* Utils.swift */; }; 54352E9621A51A2500CBCA08 /* FloatingPanelTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54352E9521A51A2500CBCA08 /* FloatingPanelTransitioning.swift */; }; 54352E9821A521CA00CBCA08 /* FloatingPanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54352E9721A521CA00CBCA08 /* FloatingPanelView.swift */; }; 5450EEE421646DF500135936 /* FloatingPanelBehavior.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5450EEE321646DF500135936 /* FloatingPanelBehavior.swift */; }; @@ -18,7 +20,7 @@ 545DBA2B2152383100CA77B8 /* GrabberHandleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545DBA2A2152383100CA77B8 /* GrabberHandleView.swift */; }; 54A6B6B122968B530077F348 /* FloatingPanelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54A6B6B022968B530077F348 /* FloatingPanelTests.swift */; }; 54A6B6B622968F710077F348 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 54A6B6B522968F710077F348 /* LaunchScreen.storyboard */; }; - 54A6B6B82296A8520077F348 /* FloatingPanelViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54A6B6B72296A8520077F348 /* FloatingPanelViewTests.swift */; }; + 54A6B6B82296A8520077F348 /* FloatingPanelSurfaceViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54A6B6B72296A8520077F348 /* FloatingPanelSurfaceViewTests.swift */; }; 54ABD7AF216CCFF7002E6C13 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54ABD7AE216CCFF7002E6C13 /* Logger.swift */; }; 54CDC5D3215B6D5A007D205C /* FloatingPanelSurfaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CDC5D2215B6D5A007D205C /* FloatingPanelSurfaceView.swift */; }; 54CDC5D5215B6D8D007D205C /* FloatingPanelBackdropView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54CDC5D4215B6D8D007D205C /* FloatingPanelBackdropView.swift */; }; @@ -45,6 +47,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 542753C522C49A6E00D17955 /* FloatingPanelLayoutTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelLayoutTests.swift; sourceTree = ""; }; + 542753C722C49A8F00D17955 /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 54352E9521A51A2500CBCA08 /* FloatingPanelTransitioning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelTransitioning.swift; sourceTree = ""; }; 54352E9721A521CA00CBCA08 /* FloatingPanelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelView.swift; sourceTree = ""; }; 5450EEE321646DF500135936 /* FloatingPanelBehavior.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelBehavior.swift; sourceTree = ""; }; @@ -59,7 +63,7 @@ 545DBA2A2152383100CA77B8 /* GrabberHandleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GrabberHandleView.swift; sourceTree = ""; }; 54A6B6B022968B530077F348 /* FloatingPanelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelTests.swift; sourceTree = ""; }; 54A6B6B522968F710077F348 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; - 54A6B6B72296A8520077F348 /* FloatingPanelViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelViewTests.swift; sourceTree = ""; }; + 54A6B6B72296A8520077F348 /* FloatingPanelSurfaceViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelSurfaceViewTests.swift; sourceTree = ""; }; 54ABD7AE216CCFF7002E6C13 /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; }; 54CDC5D2215B6D5A007D205C /* FloatingPanelSurfaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelSurfaceView.swift; sourceTree = ""; }; 54CDC5D4215B6D8D007D205C /* FloatingPanelBackdropView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanelBackdropView.swift; sourceTree = ""; }; @@ -140,8 +144,10 @@ isa = PBXGroup; children = ( 54A6B6B022968B530077F348 /* FloatingPanelTests.swift */, - 54A6B6B72296A8520077F348 /* FloatingPanelViewTests.swift */, + 542753C522C49A6E00D17955 /* FloatingPanelLayoutTests.swift */, + 54A6B6B72296A8520077F348 /* FloatingPanelSurfaceViewTests.swift */, 545DB9CF2151169500CA77B8 /* FloatingPanelControllerTests.swift */, + 542753C722C49A8F00D17955 /* Utils.swift */, 545DB9D12151169500CA77B8 /* Info.plist */, ); path = Tests; @@ -309,6 +315,7 @@ 545DBA2B2152383100CA77B8 /* GrabberHandleView.swift in Sources */, 54352E9621A51A2500CBCA08 /* FloatingPanelTransitioning.swift in Sources */, 545DB9DE215118C800CA77B8 /* UIExtensions.swift in Sources */, + 542753C822C49A8F00D17955 /* Utils.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -318,7 +325,8 @@ files = ( 54A6B6B122968B530077F348 /* FloatingPanelTests.swift in Sources */, 545DB9D02151169500CA77B8 /* FloatingPanelControllerTests.swift in Sources */, - 54A6B6B82296A8520077F348 /* FloatingPanelViewTests.swift in Sources */, + 542753C622C49A6E00D17955 /* FloatingPanelLayoutTests.swift in Sources */, + 54A6B6B82296A8520077F348 /* FloatingPanelSurfaceViewTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Framework/FloatingPanel.xcodeproj/xcshareddata/xcschemes/FloatingPanel.xcscheme b/Framework/FloatingPanel.xcodeproj/xcshareddata/xcschemes/FloatingPanel.xcscheme index fbc7569..0270258 100644 --- a/Framework/FloatingPanel.xcodeproj/xcshareddata/xcschemes/FloatingPanel.xcscheme +++ b/Framework/FloatingPanel.xcodeproj/xcshareddata/xcschemes/FloatingPanel.xcscheme @@ -29,7 +29,9 @@ shouldUseLaunchSchemeArgsEnv = "YES"> + skipped = "NO" + parallelizable = "YES" + testExecutionOrdering = "random"> CGFloat { - let topY = layoutAdapter.topY - let middleY = layoutAdapter.middleY - let bottomY = layoutAdapter.bottomY let currentY = surfaceView.frame.minY - - switch targetPosition { - case .full: - return CGFloat(abs(currentY - topY)) - case .half: - return CGFloat(abs(currentY - middleY)) - case .tip: - return CGFloat(abs(currentY - bottomY)) - case .hidden: - fatalError("Now .hidden must not be used for a user interaction") - } + let targetY = layoutAdapter.positionY(for: targetPosition) + return CGFloat(abs(currentY - targetY)) } private func directionalPosition(at currentY: CGFloat, with translation: CGPoint) -> FloatingPanelPosition { diff --git a/Framework/Sources/FloatingPanelController.swift b/Framework/Sources/FloatingPanelController.swift index 5154cbb..9c2ba07 100644 --- a/Framework/Sources/FloatingPanelController.swift +++ b/Framework/Sources/FloatingPanelController.swift @@ -68,6 +68,10 @@ public enum FloatingPanelPosition: Int { case half case tip case hidden + + static var allCases: [FloatingPanelPosition] { + return [.full, .half, .tip, .hidden] + } } /// @@ -145,7 +149,7 @@ open class FloatingPanelController: UIViewController, UIScrollViewDelegate, UIGe } private var _contentViewController: UIViewController? - private var floatingPanel: FloatingPanel! + private(set) var floatingPanel: FloatingPanel! private var preSafeAreaInsets: UIEdgeInsets = .zero // Capture the latest one private var safeAreaInsetsObservation: NSKeyValueObservation? private let modalTransition = FloatingPanelModalTransition() diff --git a/Framework/Sources/FloatingPanelLayout.swift b/Framework/Sources/FloatingPanelLayout.swift index 4fa6fd2..c0b0755 100644 --- a/Framework/Sources/FloatingPanelLayout.swift +++ b/Framework/Sources/FloatingPanelLayout.swift @@ -181,13 +181,11 @@ class FloatingPanelLayoutAdapter { } var topMostState: FloatingPanelPosition { - if supportedPositions.contains(.full) { - return .full - } - if supportedPositions.contains(.half) { - return .half - } - return .tip + return supportedPositions.sorted(by: { $0.rawValue < $1.rawValue }).first ?? .hidden + } + + var bottomMostState: FloatingPanelPosition { + return supportedPositions.sorted(by: { $0.rawValue < $1.rawValue }).last ?? .hidden } var topY: CGFloat { diff --git a/Framework/Tests/FloatingPanelControllerTests.swift b/Framework/Tests/FloatingPanelControllerTests.swift index 9758b95..4e4b665 100644 --- a/Framework/Tests/FloatingPanelControllerTests.swift +++ b/Framework/Tests/FloatingPanelControllerTests.swift @@ -30,12 +30,8 @@ class FloatingPanelControllerTests: XCTestCase { guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else { fatalError() } let fpc = FloatingPanelController() fpc.addPanel(toParent: rootVC) - - waitRunLoop(secs: 1.0) XCTAssert(fpc.surfaceView.frame.minY == (fpc.view.bounds.height - fpc.layoutInsets.bottom) - fpc.layout.insetFor(position: .half)!) - - fpc.move(to: .tip, animated: true) - waitRunLoop(secs: 1.0) + fpc.move(to: .tip, animated: false) XCTAssert(fpc.surfaceView.frame.minY == (fpc.view.bounds.height - fpc.layoutInsets.bottom) - fpc.layout.insetFor(position: .tip)!) } @@ -58,11 +54,7 @@ class FloatingPanelControllerTests: XCTestCase { } } -func waitRunLoop(secs: TimeInterval = 0) { - RunLoop.main.run(until: Date(timeIntervalSinceNow: secs)) -} - -class MyZombieViewController: UIViewController, FloatingPanelLayout, FloatingPanelBehavior, FloatingPanelControllerDelegate { +private class MyZombieViewController: UIViewController, FloatingPanelLayout, FloatingPanelBehavior, FloatingPanelControllerDelegate { var fpc: FloatingPanelController? override func viewDidLoad() { fpc = FloatingPanelController(delegate: self) diff --git a/Framework/Tests/FloatingPanelLayoutTests.swift b/Framework/Tests/FloatingPanelLayoutTests.swift new file mode 100644 index 0000000..a5985e9 --- /dev/null +++ b/Framework/Tests/FloatingPanelLayoutTests.swift @@ -0,0 +1,41 @@ +// +// Created by Shin Yamamoto on 2019/06/27. +// Copyright © 2019 scenee. All rights reserved. +// + +import XCTest +@testable import FloatingPanel + +class FloatingPanelLayoutTests: XCTestCase { + override func setUp() {} + override func tearDown() {} + + func test_layoutAdapter_topAndBottomMostState() { + let fpc = FloatingPanelController(delegate: nil) + fpc.loadViewIfNeeded() + fpc.view.frame = CGRect(x: 0, y: 0, width: 375, height: 667) + XCTAssertEqual(fpc.floatingPanel.layoutAdapter.topMostState, .full) + XCTAssertEqual(fpc.floatingPanel.layoutAdapter.bottomMostState, .tip) + + class FloatingPanelLayoutWithHidden: FloatingPanelLayout { + func insetFor(position: FloatingPanelPosition) -> CGFloat? { return nil } + let initialPosition: FloatingPanelPosition = .hidden + let supportedPositions: Set = [.hidden, .half, .full] + } + class FloatingPanelLayout2Positions: FloatingPanelLayout { + func insetFor(position: FloatingPanelPosition) -> CGFloat? { return nil } + let initialPosition: FloatingPanelPosition = .tip + let supportedPositions: Set = [.tip, .half] + } + let delegate = FloatingPanelTestDelegate() + delegate.layout = FloatingPanelLayoutWithHidden() + fpc.delegate = delegate + XCTAssertEqual(fpc.floatingPanel.layoutAdapter.topMostState, .full) + XCTAssertEqual(fpc.floatingPanel.layoutAdapter.bottomMostState, .half) // Will fixed on fix-hidden-position branch + + delegate.layout = FloatingPanelLayout2Positions() + fpc.delegate = delegate + XCTAssertEqual(fpc.floatingPanel.layoutAdapter.topMostState, .half) + XCTAssertEqual(fpc.floatingPanel.layoutAdapter.bottomMostState, .tip) + } +} diff --git a/Framework/Tests/FloatingPanelViewTests.swift b/Framework/Tests/FloatingPanelSurfaceViewTests.swift similarity index 69% rename from Framework/Tests/FloatingPanelViewTests.swift rename to Framework/Tests/FloatingPanelSurfaceViewTests.swift index 55b316b..2048824 100644 --- a/Framework/Tests/FloatingPanelViewTests.swift +++ b/Framework/Tests/FloatingPanelSurfaceViewTests.swift @@ -6,8 +6,7 @@ import XCTest @testable import FloatingPanel -class FloatingPanelViewTests: XCTestCase { - +class FloatingPanelSurfaceViewTests: XCTestCase { override func setUp() {} override func tearDown() {} @@ -24,6 +23,26 @@ class FloatingPanelViewTests: XCTestCase { XCTAssert(surface.backgroundColor == surface.containerView.backgroundColor) } + func test_surfaceView_constraintsUpdate() { + let window = UIWindow() + let surface = FloatingPanelSurfaceView(frame: CGRect(x: 0.0, y: 0.0, width: 320.0, height: 480.0)) + window.addSubview(surface) + window.makeKeyAndVisible() + XCTAssert(surface.contentView == nil) + surface.layoutIfNeeded() + XCTAssert(surface.grabberHandle.frame.minY == 6.0) + XCTAssert(surface.grabberHandle.frame.width == surface.grabberHandleWidth) + XCTAssert(surface.grabberHandle.frame.height == surface.grabberHandleHeight) + + surface.grabberHandleWidth = 44.0 + surface.grabberHandleHeight = 12.0 + surface.layoutIfNeeded() + waitRunLoop(secs: 0.000_001) + XCTAssert(surface.grabberHandle.frame.width == surface.grabberHandleWidth, "\(surface.grabberHandle.frame.width) == \(surface.grabberHandleWidth)") + XCTAssert(surface.grabberHandle.frame.height == surface.grabberHandleHeight, "\(surface.grabberHandle.frame.height) == \(surface.grabberHandleHeight)") + window.resignKey() + } + func test_surfaceView_cornderRaduis() { let surface = FloatingPanelSurfaceView(frame: CGRect(x: 0.0, y: 0.0, width: 320.0, height: 480.0)) XCTAssert(surface.cornerRadius == 0.0) diff --git a/Framework/Tests/FloatingPanelTests.swift b/Framework/Tests/FloatingPanelTests.swift index e9530b6..992127e 100644 --- a/Framework/Tests/FloatingPanelTests.swift +++ b/Framework/Tests/FloatingPanelTests.swift @@ -62,4 +62,17 @@ class FloatingPanelTests: XCTestCase { XCTAssertEqual(contentVC2.tableView.showsVerticalScrollIndicator, false) XCTAssertEqual(contentVC2.tableView.bounces, false) } + +} + +private protocol FloatingPanelTestLayout: FloatingPanelLayout {} +private extension FloatingPanelTestLayout { + func insetFor(position: FloatingPanelPosition) -> CGFloat? { + switch position { + case .full: return 18.0 + case .half: return 262.0 + case .tip: return 69.0 + default: return nil + } + } } diff --git a/Framework/Tests/Utils.swift b/Framework/Tests/Utils.swift new file mode 100644 index 0000000..4485aed --- /dev/null +++ b/Framework/Tests/Utils.swift @@ -0,0 +1,18 @@ +// +// Created by Shin Yamamoto on 2019/06/27. +// Copyright © 2019 scenee. All rights reserved. +// + +import Foundation +@testable import FloatingPanel + +func waitRunLoop(secs: TimeInterval = 0) { + RunLoop.main.run(until: Date(timeIntervalSinceNow: secs)) +} + +class FloatingPanelTestDelegate: FloatingPanelControllerDelegate { + var layout: FloatingPanelLayout? + func floatingPanel(_ vc: FloatingPanelController, layoutFor newCollection: UITraitCollection) -> FloatingPanelLayout? { + return layout + } +}