diff --git a/client/ios/LayoutKit/LayoutKit/Blocks/BlockTooltip+Layout.swift b/client/ios/LayoutKit/LayoutKit/Blocks/BlockTooltip+Layout.swift index d448d1c96..d4087f839 100644 --- a/client/ios/LayoutKit/LayoutKit/Blocks/BlockTooltip+Layout.swift +++ b/client/ios/LayoutKit/LayoutKit/Blocks/BlockTooltip+Layout.swift @@ -8,7 +8,7 @@ extension BlockTooltip { constrainedBy bounds: CGRect ) -> CGRect { let size = block.intrinsicSize - let result = CGRect( + var result = CGRect( coordinate: targetRect.coordinate(of: position), ofPosition: position.opposite, size: size @@ -16,33 +16,82 @@ extension BlockTooltip { if result.intersection(bounds) == result { return result + } else { + result.move(to: bounds) + return result } - - var alternativePosition = position - if result.maxY > bounds.maxY { - alternativePosition = alternativePosition.movingUp - } - if result.minY < bounds.minY { - alternativePosition = alternativePosition.movingDown - } - if result.minX < bounds.minX { - alternativePosition = alternativePosition.movingRight - } - if result.maxX > bounds.maxX { - alternativePosition = alternativePosition.movingLeft - } - - let alternativeFrame = CGRect( - coordinate: targetRect.coordinate(of: alternativePosition), - ofPosition: alternativePosition.opposite, - size: size - ).offset(by: offset) - return alternativeFrame.intersection(bounds) == alternativeFrame - ? alternativeFrame - : result } } +extension CGRect { + fileprivate mutating func move(to bounds: CGRect) { + for direction in MoveDirection.allCases { + let (minPos, maxPos) = minAndMaxPos(direction) + let (minBound, maxBound) = bounds.minAndMaxPos(direction) + + var newOrigin: CGFloat = origin(direction) + + if self.size(direction) > bounds.size(direction) { + switch (minPos, maxPos) { + case let (min, _) where min > minBound: + newOrigin = minBound + case let (_, max) where max < maxBound: + newOrigin -= maxBound - max + default: + break + } + } else { + switch (minPos, maxPos) { + case let (min, _) where min < minBound: + newOrigin = minBound + case let (_, max) where max > maxBound: + newOrigin -= max - maxBound + default: + break + } + } + + switch direction { + case .horizontal: + origin.x = newOrigin + case .vertical: + origin.y = newOrigin + } + } + } + + private func origin(_ direction: MoveDirection) -> CGFloat { + switch direction { + case .horizontal: + origin.x + case .vertical: + origin.y + } + } + + private func size(_ direction: MoveDirection) -> CGFloat { + switch direction { + case .horizontal: + width + case .vertical: + height + } + } + + private func minAndMaxPos( + _ direction: MoveDirection + ) -> (min: CGFloat, max: CGFloat) { + switch direction { + case .horizontal: + (minX, maxX) + case .vertical: + (minY, maxY) + } + } + + fileprivate typealias MoveDirection = ScrollDirection +} + extension CGRect { fileprivate func coordinate(of position: BlockTooltip.Position) -> CGPoint { switch position { @@ -73,38 +122,6 @@ extension BlockTooltip.Position { case .center: .center } } - - fileprivate var movingUp: Self { - switch self { - case .topLeft, .left, .bottomLeft: .topLeft - case .top, .center, .bottom: .top - case .topRight, .right, .bottomRight: .topRight - } - } - - fileprivate var movingDown: Self { - switch self { - case .topLeft, .left, .bottomLeft: .bottomLeft - case .top, .center, .bottom: .bottom - case .topRight, .right, .bottomRight: .bottomRight - } - } - - fileprivate var movingLeft: Self { - switch self { - case .topLeft, .top, .topRight: .topLeft - case .left, .center, .right: .left - case .bottomLeft, .bottom, .bottomRight: .bottomLeft - } - } - - fileprivate var movingRight: Self { - switch self { - case .topLeft, .top, .topRight: .topRight - case .left, .center, .right: .right - case .bottomLeft, .bottom, .bottomRight: .bottomRight - } - } } extension CGRect { diff --git a/client/ios/LayoutKit/LayoutKit/ViewModels/ScrollDirection.swift b/client/ios/LayoutKit/LayoutKit/ViewModels/ScrollDirection.swift index 006aa3de5..9b2394eaa 100644 --- a/client/ios/LayoutKit/LayoutKit/ViewModels/ScrollDirection.swift +++ b/client/ios/LayoutKit/LayoutKit/ViewModels/ScrollDirection.swift @@ -1,7 +1,7 @@ import Foundation @frozen -public enum ScrollDirection: Equatable { +public enum ScrollDirection: Equatable, CaseIterable { case horizontal case vertical diff --git a/client/ios/LayoutKit/LayoutKitTests/Blocks/BlockTooltipTests.swift b/client/ios/LayoutKit/LayoutKitTests/Blocks/BlockTooltipTests.swift index 70af34c2b..9d1d19fe8 100644 --- a/client/ios/LayoutKit/LayoutKitTests/Blocks/BlockTooltipTests.swift +++ b/client/ios/LayoutKit/LayoutKitTests/Blocks/BlockTooltipTests.swift @@ -15,8 +15,10 @@ final class BlockTooltipTests: XCTestCase { private var testCaseOffsets: [CGPoint] { [ CGPoint(x: 0.0, y: 0.0), // fits - CGPoint(x: 200.0, y: 0.0), // doesn't fit horisontally - CGPoint(x: 0.0, y: 450.0), // doesn't fit vertically + CGPoint(x: tooltipSize.width, y: 0.0), // doesn't fit horisontally + CGPoint(x: -tooltipSize.width, y: 0.0), // doesn't fit horisontally + CGPoint(x: 0.0, y: tooltipSize.height), // doesn't fit vertically + CGPoint(x: 0.0, y: -tooltipSize.height), // doesn't fit vertically ] }