Skip to content

Commit

Permalink
Merge pull request #26 from p-x9/feature/displaymode
Browse files Browse the repository at this point in the history
  • Loading branch information
p-x9 authored Aug 23, 2023
2 parents d5518f9 + 0d99579 commit adff033
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 14 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Text("Hello")
.touchPointColor(.orange) // color of mark on touched point
.touchPointBorder(true, color: .blue, width: 1) // applying a border to touched points
.touchPointShadow(true, color: .purple, radius: 3) // shadow on touched points
.touchPointDisplayMode(.recordingOnly) // display mode of touched points
.showLocationLabel(true) // show touch coordinate
```
![Example](https://user-images.githubusercontent.com/50244599/231509731-d3ea5df0-1981-4911-9a14-2b57bf575eb7.PNG)
Expand Down
19 changes: 18 additions & 1 deletion Sources/TouchTracker/Cocoa/TouchTrackingUIView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public class TouchTrackingUIView: UIView {
/// A boolean value that indicates whatever adding show coordinates label or not
public var isShowLocation: Bool

/// display mode of touched points.
public var displayMode: DisplayMode


var touches: Set<UITouch> = []
var locations: [CGPoint] = [] {
Expand Down Expand Up @@ -67,6 +70,7 @@ public class TouchTrackingUIView: UIView {
/// - shadowOffset: shadow offset of mark on touched point
/// - image: Image to be displayed at the touched point mark
/// - isShowLocation: A boolean value that indicates whatever adding show coordinates label or not
/// - displayMode: display mode of touched points.
public init(
radius: CGFloat = 20,
color: UIColor = .red,
Expand All @@ -79,7 +83,8 @@ public class TouchTrackingUIView: UIView {
shadowRadius: CGFloat = 3,
shadowOffset: CGPoint = .zero,
image: UIImage? = nil,
isShowLocation: Bool = false
isShowLocation: Bool = false,
displayMode: DisplayMode = .always
) {
self.radius = radius
self.color = color
Expand All @@ -93,6 +98,7 @@ public class TouchTrackingUIView: UIView {
self.shadowOffset = shadowOffset
self.image = image
self.isShowLocation = isShowLocation
self.displayMode = displayMode

super.init(frame: .null)

Expand Down Expand Up @@ -160,6 +166,15 @@ public class TouchTrackingUIView: UIView {
}

func updatePoints() {
let isCaptured = window?.screen.isCaptured ?? false
let shouldDisplay = displayMode.shouldDisplay(captured: isCaptured)

if !shouldDisplay {
pointWindows.forEach { $0.isHidden = true }
pointWindows = []
return
}

if pointWindows.count > touches.count {
pointWindows[touches.count..<pointWindows.count].forEach {
$0.isHidden = true
Expand Down Expand Up @@ -187,6 +202,8 @@ public class TouchTrackingUIView: UIView {
}
}

let locations = touches.map { $0.location(in: nil) }

zip(pointWindows, locations).forEach { window, location in
window.location = location
window.center = .init(x: location.x + offset.x,
Expand Down
36 changes: 36 additions & 0 deletions Sources/TouchTracker/Model/DisplayMode.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// DisplayMode.swift
//
//
// Created by p-x9 on 2023/08/23.
//
//

#if canImport(UIKit)
import UIKit
#endif

public enum DisplayMode {
case always
case debugOnly
case recordingOnly
}

#if canImport(UIKit)
extension DisplayMode {
func shouldDisplay(captured: Bool) -> Bool {
switch self {
case .always:
return true
case .debugOnly:
#if DEBUG
return true
#else
return false
#endif
case .recordingOnly:
return captured
}
}
}
#endif
8 changes: 7 additions & 1 deletion Sources/TouchTracker/Model/TouchPointStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ public struct TouchPointStyle: Equatable {

/// A boolean value that indicates whatever adding show coordinates label or not
public var isShowLocation: Bool

/// display mode of touched points.
public var displayMode: DisplayMode

/// Initializer
/// - Parameters:
Expand All @@ -49,6 +52,7 @@ public struct TouchPointStyle: Equatable {
/// - shadowRadius: shadow radius of mark on touched point
/// - shadowOffset: shadow offset of mark on touched point
/// - isShowLocation: A boolean value that indicates whatever adding show coordinates label or not
/// - displayMode: display mode of touched points.
public init(
radius: CGFloat = 20,
color: Color = .red,
Expand All @@ -60,7 +64,8 @@ public struct TouchPointStyle: Equatable {
shadowColor: Color = .black,
shadowRadius: CGFloat = 3,
shadowOffset: CGPoint = .zero,
isShowLocation: Bool = false
isShowLocation: Bool = false,
displayMode: DisplayMode = .always
) {
self.radius = radius
self.color = color
Expand All @@ -73,5 +78,6 @@ public struct TouchPointStyle: Equatable {
self.shadowRadius = shadowRadius
self.shadowOffset = shadowOffset
self.isShowLocation = isShowLocation
self.displayMode = displayMode
}
}
18 changes: 9 additions & 9 deletions Sources/TouchTracker/TouchLocationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,39 @@ import UIKit

struct TouchLocationView<Content: View>: UIViewControllerRepresentable {
@Binding var locations: [CGPoint]
@Binding var isCaptured: Bool
let content: () -> Content

init(_ locations: Binding<[CGPoint]>, content: @escaping () -> Content) {
init(_ locations: Binding<[CGPoint]>, isCaptured: Binding<Bool>, content: @escaping () -> Content) {
self._locations = locations
self._isCaptured = isCaptured
self.content = content
}

func makeUIViewController(context: Context) -> some UIViewController {
let controller = TouchLocationWrapView(rootView: content())
controller.touchesChangeHandler = { locations in
controller.touchesChangeHandler = { [weak controller] locations in
self.$locations.wrappedValue = locations
self.$isCaptured.wrappedValue = controller?.isCaptured ?? false
}
return controller
}

func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
guard let controller = uiViewController as? TouchLocationWrapView<Content> else { return }
controller.rootView = content()
controller.touchesChangeHandler = { locations in
controller.touchesChangeHandler = { [weak controller] locations in
self.$locations.wrappedValue = locations
self.$isCaptured.wrappedValue = controller?.isCaptured ?? false
}
}

}

class TouchLocationWrapView<Content: View>: UIHostingController<Content> {
var touchesChangeHandler: (([CGPoint]) -> Void)?

var touches: Set<UITouch> = []
var locations: [CGPoint] = [] {
didSet {
touchesChangeHandler?(locations)
}
var isCaptured: Bool {
view.window?.screen.isCaptured ?? false
}

lazy var trackLocationUIView: TouchLocationCocoaView = {
Expand Down
17 changes: 14 additions & 3 deletions Sources/TouchTracker/TouchTracker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public struct TouchTrackingView<Content: View>: View {
let content: Content

@State var locations: [CGPoint] = []
@State var isCaptured: Bool = false

var radius: CGFloat = 20
var color: Color = .red
Expand All @@ -28,6 +29,8 @@ public struct TouchTrackingView<Content: View>: View {

var isShowLocation: Bool = false

var displayMode: DisplayMode = .always

public init(_ content: Content) {
self.content = content
#if canImport(UIKit)
Expand Down Expand Up @@ -68,11 +71,13 @@ public struct TouchTrackingView<Content: View>: View {
.hidden()
.background(
ZStack {
TouchLocationView($locations) {
TouchLocationView($locations, isCaptured: $isCaptured) {
content
}
touchPointsView
.zIndex(.infinity)
if displayMode.shouldDisplay(captured: isCaptured){
touchPointsView
.zIndex(.infinity)
}
}
)
#endif
Expand Down Expand Up @@ -124,6 +129,11 @@ extension TouchTrackingView {
set(enabled, for: \.isShowLocation)
}

/// display mode of touched points.
public func touchPointDisplayMode(_ mode: DisplayMode) -> Self {
set(mode, for: \.displayMode)
}

public func setTouchPointStyle(_ style: TouchPointStyle) -> Self {
self
.set(style.radius, for: \.radius)
Expand All @@ -137,6 +147,7 @@ extension TouchTrackingView {
.set(style.shadowRadius, for: \.shadowRadius)
.set(style.shadowOffset, for: \.shadowOffset)
.set(style.isShowLocation, for: \.isShowLocation)
.set(style.displayMode, for: \.displayMode)
}

private func set<T>(_ value: T, for keyPath: WritableKeyPath<TouchTrackingView, T>) -> Self {
Expand Down

0 comments on commit adff033

Please sign in to comment.