Coverage Summary for Class: TransformGestureDetectorWithEndCallbacksKt (com.vsevolodganin.clicktrack.utils.compose)

Class Method, % Branch, % Line, % Instruction, %
TransformGestureDetectorWithEndCallbacksKt 0% (0/1) 0% (0/4) 0% (0/25)
TransformGestureDetectorWithEndCallbacksKt$detectTransformGesturesWithEndCallbacks$4 0% (0/1) 0% (0/32) 0% (0/42) 0% (0/246)
Total 0% (0/2) 0% (0/32) 0% (0/46) 0% (0/271)


 package com.vsevolodganin.clicktrack.utils.compose
 
 import androidx.compose.foundation.gestures.awaitEachGesture
 import androidx.compose.foundation.gestures.awaitFirstDown
 import androidx.compose.foundation.gestures.calculateCentroid
 import androidx.compose.foundation.gestures.calculateCentroidSize
 import androidx.compose.foundation.gestures.calculatePan
 import androidx.compose.foundation.gestures.calculateRotation
 import androidx.compose.foundation.gestures.calculateZoom
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.pointer.PointerInputChange
 import androidx.compose.ui.input.pointer.PointerInputScope
 import androidx.compose.ui.input.pointer.positionChanged
 import androidx.compose.ui.util.fastAny
 import androidx.compose.ui.util.fastForEach
 import kotlin.math.PI
 import kotlin.math.abs
 
 suspend fun PointerInputScope.detectTransformGesturesWithEndCallbacks(
     panZoomLock: Boolean = false,
     onGesture: (centroid: Offset, pan: Offset, zoom: Float, rotation: Float) -> Unit,
     onGestureEnd: () -> Unit = {},
     onGestureCancel: () -> Unit = {},
 ) {
     awaitEachGesture {
         var rotation = 0f
         var zoom = 1f
         var pan = Offset.Zero
         var pastTouchSlop = false
         val touchSlop = viewConfiguration.touchSlop
         var lockedToPanZoom = false
         var canceled: Boolean
 
         awaitFirstDown(requireUnconsumed = false)
         do {
             val event = awaitPointerEvent()
             canceled = event.changes.fastAny(PointerInputChange::isConsumed)
             if (!canceled) {
                 val zoomChange = event.calculateZoom()
                 val rotationChange = event.calculateRotation()
                 val panChange = event.calculatePan()
 
                 if (!pastTouchSlop) {
                     zoom *= zoomChange
                     rotation += rotationChange
                     pan += panChange
 
                     val centroidSize = event.calculateCentroidSize(useCurrent = false)
                     val zoomMotion = abs(1 - zoom) * centroidSize
                     val rotationMotion = abs(rotation * PI.toFloat() * centroidSize / 180f)
                     val panMotion = pan.getDistance()
 
                     if (zoomMotion > touchSlop ||
                         rotationMotion > touchSlop ||
                         panMotion > touchSlop
                     ) {
                         pastTouchSlop = true
                         lockedToPanZoom = panZoomLock && rotationMotion < touchSlop
                     }
                 }
 
                 if (pastTouchSlop) {
                     val centroid = event.calculateCentroid(useCurrent = false)
                     val effectiveRotation = if (lockedToPanZoom) 0f else rotationChange
                     if (effectiveRotation != 0f ||
                         zoomChange != 1f ||
                         panChange != Offset.Zero
                     ) {
                         onGesture(centroid, panChange, zoomChange, effectiveRotation)
                     }
                     event.changes.fastForEach {
                         if (it.positionChanged()) {
                             it.consume()
                         }
                     }
                 }
             }
         } while (!canceled && event.changes.fastAny { it.pressed })
 
         if (canceled) {
             onGestureCancel()
         } else {
             onGestureEnd()
         }
     }
 }