mirror of
https://github.com/yattee/yattee.git
synced 2026-02-20 01:39:46 +00:00
Yattee v2 rewrite
This commit is contained in:
150
Yattee/Views/Player/Gestures/TapZoneCalculator.swift
Normal file
150
Yattee/Views/Player/Gestures/TapZoneCalculator.swift
Normal file
@@ -0,0 +1,150 @@
|
||||
//
|
||||
// TapZoneCalculator.swift
|
||||
// Yattee
|
||||
//
|
||||
// Calculator for determining tap zone hit-testing and frames.
|
||||
//
|
||||
|
||||
#if os(iOS)
|
||||
import CoreGraphics
|
||||
import Foundation
|
||||
|
||||
/// Utility for calculating tap zone positions and hit-testing.
|
||||
enum TapZoneCalculator {
|
||||
/// Safe margin from screen edges to avoid system gesture conflicts.
|
||||
static let safeMargin: CGFloat = 25
|
||||
|
||||
/// Determines which zone was tapped based on the layout and tap point.
|
||||
/// - Parameters:
|
||||
/// - point: The tap location in the bounds coordinate system.
|
||||
/// - bounds: The total gesture-recognizable area bounds.
|
||||
/// - layout: The current tap zone layout.
|
||||
/// - Returns: The zone position that was tapped, or nil if outside safe margins.
|
||||
static func zone(
|
||||
for point: CGPoint,
|
||||
in bounds: CGRect,
|
||||
layout: TapZoneLayout
|
||||
) -> TapZonePosition? {
|
||||
// Check safe margins
|
||||
let safeArea = bounds.insetBy(dx: safeMargin, dy: safeMargin)
|
||||
guard safeArea.contains(point) else { return nil }
|
||||
|
||||
// Normalize point to 0-1 range within safe area
|
||||
let normalizedX = (point.x - safeArea.minX) / safeArea.width
|
||||
let normalizedY = (point.y - safeArea.minY) / safeArea.height
|
||||
|
||||
switch layout {
|
||||
case .single:
|
||||
return .full
|
||||
|
||||
case .horizontalSplit:
|
||||
return normalizedX < 0.5 ? .left : .right
|
||||
|
||||
case .verticalSplit:
|
||||
return normalizedY < 0.5 ? .top : .bottom
|
||||
|
||||
case .threeColumns:
|
||||
if normalizedX < 1.0 / 3.0 {
|
||||
return .leftThird
|
||||
} else if normalizedX < 2.0 / 3.0 {
|
||||
return .center
|
||||
} else {
|
||||
return .rightThird
|
||||
}
|
||||
|
||||
case .quadrants:
|
||||
let isTop = normalizedY < 0.5
|
||||
let isLeft = normalizedX < 0.5
|
||||
|
||||
if isTop {
|
||||
return isLeft ? .topLeft : .topRight
|
||||
} else {
|
||||
return isLeft ? .bottomLeft : .bottomRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the frame for a specific zone position within bounds.
|
||||
/// - Parameters:
|
||||
/// - position: The zone position.
|
||||
/// - bounds: The total gesture-recognizable area bounds.
|
||||
/// - layout: The current tap zone layout.
|
||||
/// - Returns: The frame for the zone, or nil if position doesn't match layout.
|
||||
static func frame(
|
||||
for position: TapZonePosition,
|
||||
in bounds: CGRect,
|
||||
layout: TapZoneLayout
|
||||
) -> CGRect? {
|
||||
// Use safe area for calculations
|
||||
let safeArea = bounds.insetBy(dx: safeMargin, dy: safeMargin)
|
||||
|
||||
switch layout {
|
||||
case .single:
|
||||
guard position == .full else { return nil }
|
||||
return safeArea
|
||||
|
||||
case .horizontalSplit:
|
||||
let halfWidth = safeArea.width / 2
|
||||
switch position {
|
||||
case .left:
|
||||
return CGRect(x: safeArea.minX, y: safeArea.minY,
|
||||
width: halfWidth, height: safeArea.height)
|
||||
case .right:
|
||||
return CGRect(x: safeArea.minX + halfWidth, y: safeArea.minY,
|
||||
width: halfWidth, height: safeArea.height)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
case .verticalSplit:
|
||||
let halfHeight = safeArea.height / 2
|
||||
switch position {
|
||||
case .top:
|
||||
return CGRect(x: safeArea.minX, y: safeArea.minY,
|
||||
width: safeArea.width, height: halfHeight)
|
||||
case .bottom:
|
||||
return CGRect(x: safeArea.minX, y: safeArea.minY + halfHeight,
|
||||
width: safeArea.width, height: halfHeight)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
case .threeColumns:
|
||||
let thirdWidth = safeArea.width / 3
|
||||
switch position {
|
||||
case .leftThird:
|
||||
return CGRect(x: safeArea.minX, y: safeArea.minY,
|
||||
width: thirdWidth, height: safeArea.height)
|
||||
case .center:
|
||||
return CGRect(x: safeArea.minX + thirdWidth, y: safeArea.minY,
|
||||
width: thirdWidth, height: safeArea.height)
|
||||
case .rightThird:
|
||||
return CGRect(x: safeArea.minX + thirdWidth * 2, y: safeArea.minY,
|
||||
width: thirdWidth, height: safeArea.height)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
case .quadrants:
|
||||
let halfWidth = safeArea.width / 2
|
||||
let halfHeight = safeArea.height / 2
|
||||
switch position {
|
||||
case .topLeft:
|
||||
return CGRect(x: safeArea.minX, y: safeArea.minY,
|
||||
width: halfWidth, height: halfHeight)
|
||||
case .topRight:
|
||||
return CGRect(x: safeArea.minX + halfWidth, y: safeArea.minY,
|
||||
width: halfWidth, height: halfHeight)
|
||||
case .bottomLeft:
|
||||
return CGRect(x: safeArea.minX, y: safeArea.minY + halfHeight,
|
||||
width: halfWidth, height: halfHeight)
|
||||
case .bottomRight:
|
||||
return CGRect(x: safeArea.minX + halfWidth, y: safeArea.minY + halfHeight,
|
||||
width: halfWidth, height: halfHeight)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user