diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt b/app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt index 2bd3f9aa74..87ab039469 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt @@ -313,6 +313,7 @@ sealed class ActionData { val yStart: Int, val xEnd: Int, val yEnd: Int, + val fingerCount: Int, val duration: Int, val description: String? ) : ActionData() { diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt b/app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt index 83ce11ed48..1ef7431b4c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt @@ -108,6 +108,7 @@ object ActionDataEntityMapper { var yStart = 0; var xEnd = 0; var yEnd = 0; + var fingerCount = 1; var duration = 250; if (splitData.isNotEmpty()) { @@ -127,7 +128,11 @@ object ActionDataEntityMapper { } if (splitData.size >= 5) { - duration = splitData[4].trim().toInt() + fingerCount = splitData[4].trim().toInt() + } + + if (splitData.size >= 6) { + duration = splitData[5].trim().toInt() } val description = entity.extras.getData(ActionEntity.EXTRA_COORDINATE_DESCRIPTION) @@ -138,6 +143,7 @@ object ActionDataEntityMapper { yStart = yStart, xEnd = xEnd, yEnd = yEnd, + fingerCount = fingerCount, duration = duration, description = description ) @@ -450,7 +456,7 @@ object ActionDataEntityMapper { is ActionData.AppShortcut -> data.uri is ActionData.PhoneCall -> data.number is ActionData.TapScreen -> "${data.x},${data.y}" - is ActionData.SwipeScreen -> "${data.xStart},${data.yStart},${data.xEnd},${data.yEnd},${data.duration}" + is ActionData.SwipeScreen -> "${data.xStart},${data.yStart},${data.xEnd},${data.yEnd},${data.fingerCount},${data.duration}" is ActionData.Text -> data.text is ActionData.Url -> data.url is ActionData.Sound -> data.soundUid diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/BaseActionUiHelper.kt b/app/src/main/java/io/github/sds100/keymapper/actions/BaseActionUiHelper.kt index cb7abe07b1..462e905dfa 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/BaseActionUiHelper.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/BaseActionUiHelper.kt @@ -301,12 +301,12 @@ abstract class BaseActionUiHelper, A : Action>( is ActionData.SwipeScreen -> if (action.description.isNullOrBlank()) { getString( R.string.description_swipe_coordinate_default, - arrayOf(action.xStart, action.yStart, action.xEnd, action.yEnd, action.duration) + arrayOf(action.fingerCount, action.xStart, action.yStart, action.xEnd, action.yEnd, action.duration) ) } else { getString( R.string.description_swipe_coordinate_with_description, - arrayOf(action.xStart, action.yStart, action.xEnd, action.yEnd, action.duration, action.description) + arrayOf(action.fingerCount, action.xStart, action.yStart, action.xEnd, action.yEnd, action.duration, action.description) ) } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionViewModel.kt b/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionViewModel.kt index 1873030558..462c4fd8b0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionViewModel.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionViewModel.kt @@ -1,7 +1,6 @@ package io.github.sds100.keymapper.actions import android.text.InputType -import android.util.Log import io.github.sds100.keymapper.R import io.github.sds100.keymapper.actions.swipescreen.SwipePickCoordinateResult import io.github.sds100.keymapper.actions.tapscreen.PickCoordinateResult @@ -10,9 +9,22 @@ import io.github.sds100.keymapper.system.camera.CameraLensUtils import io.github.sds100.keymapper.system.display.Orientation import io.github.sds100.keymapper.system.display.OrientationUtils import io.github.sds100.keymapper.system.intents.ConfigIntentResult -import io.github.sds100.keymapper.system.volume.* -import io.github.sds100.keymapper.util.ui.* -import timber.log.Timber +import io.github.sds100.keymapper.system.volume.DndMode +import io.github.sds100.keymapper.system.volume.DndModeUtils +import io.github.sds100.keymapper.system.volume.RingerMode +import io.github.sds100.keymapper.system.volume.RingerModeUtils +import io.github.sds100.keymapper.system.volume.VolumeStream +import io.github.sds100.keymapper.system.volume.VolumeStreamUtils +import io.github.sds100.keymapper.util.ui.MultiChoiceItem +import io.github.sds100.keymapper.util.ui.NavDestination +import io.github.sds100.keymapper.util.ui.NavigationViewModel +import io.github.sds100.keymapper.util.ui.NavigationViewModelImpl +import io.github.sds100.keymapper.util.ui.PopupUi +import io.github.sds100.keymapper.util.ui.PopupViewModel +import io.github.sds100.keymapper.util.ui.PopupViewModelImpl +import io.github.sds100.keymapper.util.ui.ResourceProvider +import io.github.sds100.keymapper.util.ui.navigate +import io.github.sds100.keymapper.util.ui.showPopup /** * Created by sds100 on 26/07/2021. @@ -321,6 +333,7 @@ class CreateActionViewModelImpl( oldData.yStart, oldData.xEnd, oldData.yEnd, + oldData.fingerCount, oldData.duration, oldData.description ?: "" ) @@ -344,6 +357,7 @@ class CreateActionViewModelImpl( result.yStart, result.xEnd, result.yEnd, + result.fingerCount, result.duration, description ) diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/PerformActionsUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/actions/PerformActionsUseCase.kt index 0a5aedad38..98059017c2 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/PerformActionsUseCase.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/PerformActionsUseCase.kt @@ -270,7 +270,7 @@ class PerformActionsUseCaseImpl( } is ActionData.SwipeScreen -> { - result = accessibilityService.swipeScreen(action.xStart, action.yStart, action.xEnd, action.yEnd, action.duration, inputEventType) + result = accessibilityService.swipeScreen(action.xStart, action.yStart, action.xEnd, action.yEnd, action.fingerCount, action.duration, inputEventType) } is ActionData.Text -> { diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickCoordinateResult.kt b/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickCoordinateResult.kt index 8616d6b3ce..e38427beee 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickCoordinateResult.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickCoordinateResult.kt @@ -3,4 +3,12 @@ package io.github.sds100.keymapper.actions.swipescreen import kotlinx.serialization.Serializable @Serializable -data class SwipePickCoordinateResult(val xStart: Int, val yStart: Int, val xEnd: Int, val yEnd: Int, val duration: Int, val description: String) +data class SwipePickCoordinateResult( + val xStart: Int, + val yStart: Int, + val xEnd: Int, + val yEnd: Int, + val fingerCount: Int, + val duration: Int, + val description: String +) diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateFragment.kt b/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateFragment.kt index c5319ef908..84d278079e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateFragment.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateFragment.kt @@ -29,22 +29,13 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json - -enum class ScreenshotType { - START, - END -} +import timber.log.Timber class SwipePickDisplayCoordinateFragment : Fragment() { companion object { const val EXTRA_RESULT = "extra_result" } - private var currentScreenshotType: ScreenshotType = ScreenshotType.START; - - private val isStartScreenshot: Boolean = false; - private val isEndScreenshot: Boolean = false; - private val args: SwipePickDisplayCoordinateFragmentArgs by navArgs() private val requestKey: String by lazy { args.requestKey } @@ -128,17 +119,10 @@ class SwipePickDisplayCoordinateFragment : Fragment() { viewLifecycleOwner.launchRepeatOnLifecycle(Lifecycle.State.RESUMED) { binding.imageViewScreenshot.pointCoordinates.collectLatest { point -> if (point != null) { - if (currentScreenshotType == ScreenshotType.START) { - viewModel.onScreenshotStartTouch( - point.x.toFloat() / binding.imageViewScreenshot.width, - point.y.toFloat() / binding.imageViewScreenshot.height - ) - } else if (currentScreenshotType == ScreenshotType.END) { - viewModel.onScreenshotEndTouch( - point.x.toFloat() / binding.imageViewScreenshot.width, - point.y.toFloat() / binding.imageViewScreenshot.height - ) - } + viewModel.onScreenshotTouch( + point.x.toFloat() / binding.imageViewScreenshot.width, + point.y.toFloat() / binding.imageViewScreenshot.height + ) } } } @@ -154,13 +138,7 @@ class SwipePickDisplayCoordinateFragment : Fragment() { } } - binding.setOnSelectScreenshotStartClick { - currentScreenshotType = ScreenshotType.START - screenshotLauncher.launch(FileUtils.MIME_TYPE_IMAGES) - } - - binding.setOnSelectScreenshotEndClick { - currentScreenshotType = ScreenshotType.END + binding.setOnSelectScreenshotClick { screenshotLauncher.launch(FileUtils.MIME_TYPE_IMAGES) } } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateViewModel.kt b/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateViewModel.kt index de7d306d29..57a9bb2d6e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateViewModel.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/swipescreen/SwipePickDisplayCoordinateViewModel.kt @@ -9,68 +9,99 @@ import io.github.sds100.keymapper.R import io.github.sds100.keymapper.util.ui.* import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch +import timber.log.Timber import kotlin.math.roundToInt - +enum class ScreenshotTouchType { + START, + END +} class SwipePickDisplayCoordinateViewModel( resourceProvider: ResourceProvider ) : ViewModel(), ResourceProvider by resourceProvider, PopupViewModel by PopupViewModelImpl() { + public val screenshotTouchTypeStart = ScreenshotTouchType.START; + public val screenshotTouchTypeEnd = ScreenshotTouchType.END; private val xStart = MutableStateFlow(null) private val yStart = MutableStateFlow(null) private val xEnd = MutableStateFlow(null) private val yEnd = MutableStateFlow(null) + private val fingerCount = MutableStateFlow(1) private val duration = MutableStateFlow(null) + private val _bitmap = MutableStateFlow(null) + private val _returnResult = MutableSharedFlow() + private val _screenshotTouchType = MutableStateFlow(ScreenshotTouchType.START) + + private val description: MutableStateFlow = MutableStateFlow(null) + val xStartString = xStart.map { it ?: return@map "" it.toString() - }.stateIn(viewModelScope, SharingStarted.Lazily, "") + }.stateIn(viewModelScope, SharingStarted.Lazily, null) val yStartString = yStart.map { it ?: return@map "" it.toString() - }.stateIn(viewModelScope, SharingStarted.Lazily, "") + }.stateIn(viewModelScope, SharingStarted.Lazily, null) val xEndString = xEnd.map { it ?: return@map "" it.toString() - }.stateIn(viewModelScope, SharingStarted.Lazily, "") + }.stateIn(viewModelScope, SharingStarted.Lazily, null) val yEndString = yEnd.map { it ?: return@map "" it.toString() - }.stateIn(viewModelScope, SharingStarted.Lazily, "") + }.stateIn(viewModelScope, SharingStarted.Lazily, null) + + val fingerCountString = fingerCount.map { + it ?: return@map "" + + it.toString() + }.stateIn(viewModelScope, SharingStarted.Lazily, null) val durationString = duration.map { it ?: return@map "" it.toString() - }.stateIn(viewModelScope, SharingStarted.Lazily, "") + }.stateIn(viewModelScope, SharingStarted.Lazily, null) + + val bitmap = _bitmap.asStateFlow() + val returnResult = _returnResult.asSharedFlow() + + val isSelectStartEndSwitchEnabled:StateFlow = combine(bitmap) { + bitmap?.value != null + }.stateIn(viewModelScope, SharingStarted.Lazily, false) - val isDoneButtonEnabled: StateFlow = combine(xStart, yStart, xEnd, yEnd, duration) { xStart, yStart, xEnd, yEnd, duration -> + private val isCoordinatesValid: StateFlow = combine(xStart, yStart, xEnd, yEnd) { xStart, yStart, xEnd, yEnd -> xStart ?: return@combine false yStart ?: return@combine false xEnd ?: return@combine false yEnd ?: return@combine false - duration ?: return@combine false - xStart >= 0 && yStart >= 0 && xEnd >= 0 && yEnd >= 0 && duration >= 0 + xStart >= 0 && yStart >= 0 && xEnd >= 0 && yEnd >= 0 }.stateIn(viewModelScope, SharingStarted.Lazily, false) - private val _bitmap = MutableStateFlow(null) - val bitmap = _bitmap.asStateFlow() + private val isOptionsValid: StateFlow = combine(fingerCount, duration) { fingerCount, duration -> + fingerCount ?: return@combine false + duration ?: return@combine false - private val _returnResult = MutableSharedFlow() - val returnResult = _returnResult.asSharedFlow() + fingerCount >= 1 && duration > 0 + }.stateIn(viewModelScope, SharingStarted.Lazily, false) - private val description: MutableStateFlow = MutableStateFlow(null) + val isDoneButtonEnabled: StateFlow = combine(isCoordinatesValid, isOptionsValid) { isCoordinatesValid, isOptionsValid -> + isCoordinatesValid && isOptionsValid + }.stateIn(viewModelScope, SharingStarted.Lazily, false) fun selectedScreenshot(newBitmap: Bitmap, displaySize: Point) { + + _screenshotTouchType.value = ScreenshotTouchType.START; + //check whether the height and width of the bitmap match the display size, even when it is rotated. if ( (displaySize.x != newBitmap.width @@ -109,33 +140,35 @@ class SwipePickDisplayCoordinateViewModel( this.yEnd.value = y.toIntOrNull() } + fun setFingerCount(fingerCount: String) { + this.fingerCount.value = fingerCount.toIntOrNull() + } + fun setDuration(duration: String) { this.duration.value = duration.toIntOrNull() } + fun setStartOrEndCoordinates(isChecked:Boolean, type: ScreenshotTouchType) { + if (isChecked) this._screenshotTouchType.value = type + } + /** * [screenshotXRatio] The ratio between the point where the user pressed to the width of the image. * [screenshotYRatio] The ratio between the point where the user pressed to the height of the image. */ - fun onScreenshotStartTouch(screenshotXRatio: Float, screenshotYRatio: Float) { - bitmap.value?.let { - - val displayX = it.width * screenshotXRatio - val displayY = it.height * screenshotYRatio - - xStart.value = displayX.roundToInt() - yStart.value = displayY.roundToInt() - } - } - - fun onScreenshotEndTouch(screenshotXRatio: Float, screenshotYRatio: Float) { + fun onScreenshotTouch(screenshotXRatio: Float, screenshotYRatio: Float) { bitmap.value?.let { val displayX = it.width * screenshotXRatio val displayY = it.height * screenshotYRatio - xEnd.value = displayX.roundToInt() - yEnd.value = displayY.roundToInt() + if (_screenshotTouchType.value == ScreenshotTouchType.START) { + xStart.value = displayX.roundToInt() + yStart.value = displayY.roundToInt() + } else { + xEnd.value = displayX.roundToInt() + yEnd.value = displayY.roundToInt() + } } } @@ -145,6 +178,7 @@ class SwipePickDisplayCoordinateViewModel( val yStart = yStart.value ?: return@launch val xEnd = xEnd.value ?: return@launch val yEnd = yEnd.value ?: return@launch + val fingerCount = fingerCount.value ?: return@launch val duration = duration.value ?: return@launch val description = showPopup( @@ -156,7 +190,7 @@ class SwipePickDisplayCoordinateViewModel( ) ) ?: return@launch - _returnResult.emit(SwipePickCoordinateResult(xStart, yStart, xEnd, yEnd, duration, description)) + _returnResult.emit(SwipePickCoordinateResult(xStart, yStart, xEnd, yEnd, fingerCount, duration, description)) } } @@ -166,6 +200,7 @@ class SwipePickDisplayCoordinateViewModel( yStart.value = result.yStart xEnd.value = result.xEnd yEnd.value = result.yEnd + fingerCount.value = result.fingerCount duration.value = result.duration description.value = result.description } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/IAccessibilityService.kt b/app/src/main/java/io/github/sds100/keymapper/system/accessibility/IAccessibilityService.kt index f1e51af2fb..c9799b5d34 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/IAccessibilityService.kt +++ b/app/src/main/java/io/github/sds100/keymapper/system/accessibility/IAccessibilityService.kt @@ -13,7 +13,7 @@ interface IAccessibilityService { fun doGlobalAction(action: Int): Result<*> fun tapScreen(x: Int, y: Int, inputEventType: InputEventType): Result<*> - fun swipeScreen(xStart: Int, yStart: Int, xEnd: Int, yEnd: Int, duration: Int, inputEventType: InputEventType): Result<*> + fun swipeScreen(xStart: Int, yStart: Int, xEnd: Int, yEnd: Int, fingerCount: Int, duration: Int, inputEventType: InputEventType): Result<*> val isFingerprintGestureDetectionAvailable: Boolean diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt b/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt index dfed8abb44..78df3b5392 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt +++ b/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt @@ -8,9 +8,9 @@ import android.app.ActivityManager import android.app.Service import android.content.* import android.graphics.Path +import android.graphics.Point import android.os.Build import android.os.IBinder -import android.util.Log import android.view.KeyEvent import android.view.accessibility.AccessibilityEvent import androidx.core.content.getSystemService @@ -384,8 +384,8 @@ class MyAccessibilityService : AccessibilityService(), LifecycleOwner, IAccessib val success = dispatchGesture(gestureDescription, null, null) - if (success) { - return Success(Unit) + return if (success) { + Success(Unit) } else { Error.FailedToDispatchGesture } @@ -395,22 +395,68 @@ class MyAccessibilityService : AccessibilityService(), LifecycleOwner, IAccessib return Error.SdkVersionTooLow(Build.VERSION_CODES.N) } - override fun swipeScreen(xStart: Int, yStart: Int, xEnd: Int, yEnd: Int, duration: Int, inputEventType: InputEventType): Result<*> { - Timber.d("ACCESSIBILITY SWIPE SCREEN %d, %d, %d, %d, %d, %s", xStart, yStart, xEnd, yEnd, duration, inputEventType); + override fun swipeScreen(xStart: Int, yStart: Int, xEnd: Int, yEnd: Int, fingerCount: Int, duration: Int, inputEventType: InputEventType): Result<*> { + Timber.d("ACCESSIBILITY SWIPE SCREEN %d, %d, %d, %d, %s, %d, %s", xStart, yStart, xEnd, yEnd, fingerCount, duration, inputEventType); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + val pStart = Point(xStart, yStart) + val pEnd = Point(xEnd, yEnd) + val gestureBuilder = GestureDescription.Builder() - val path = Path() - path.moveTo(xStart.toFloat(), yStart.toFloat()) - path.lineTo(xEnd.toFloat(), yEnd.toFloat()) + if (fingerCount == 1) { + val p = Path() + p.moveTo(pStart.x.toFloat(), pStart.y.toFloat()) + p.lineTo(pEnd.x.toFloat(), pEnd.y.toFloat()) + gestureBuilder.addStroke(StrokeDescription(p, 0, duration.toLong())) + } else { + // virtual distance between the fingers + val fingerDistance = 10L + // segments between fingers + val segmentCount = fingerCount - 1 + // the line of the perpendicular line which will be created to place the virtual fingers on it + val perpendicularLineLength = (fingerDistance * fingerCount).toInt() + // the length of each segment between fingers + val segmentLength = perpendicularLineLength / segmentCount + // perpendicular line of the start swipe point + val perpendicularLineStart = getPerpendicularOfLine(pStart, pEnd, + perpendicularLineLength + ); + // perpendicular line of the end swipe point + val perpendicularLineEnd = getPerpendicularOfLine(pEnd, pStart, + perpendicularLineLength, true); + + + val startFingerCoordinatesList = mutableListOf() + val endFingerCoordinatesList = mutableListOf() + // this is the angle between start and end point to rotate all virtual fingers on the perpendicular lines in the same direction + val angle = angleBetweenPoints(Point(xStart, yStart), Point(xEnd, yEnd)) - 90; + + // create the virtual fingers + for (index in 0..segmentCount) { + // offset of each finger + val fingerOffsetLength = index * segmentLength * 2; + // move the coordinates of the current virtual finger on the perpendicular line for the start coordinates + val startFingerCoordinateWithOffset = movePointByDistanceAndAngle(perpendicularLineStart.start, fingerOffsetLength, angle) + // move the coordinates of the current virtual finger on the perpendicular line for the end coordinates + val endFingerCoordinateWithOffset = movePointByDistanceAndAngle(perpendicularLineEnd.start, fingerOffsetLength, angle) + + // create a path for each finger, move the the coordinates on the perpendicular line and draw it to the end coordinates of the perpendicular line of the end swipe point + val p = Path() + p.moveTo(startFingerCoordinateWithOffset.x.toFloat(), startFingerCoordinateWithOffset.y.toFloat()) + p.lineTo(endFingerCoordinateWithOffset.x.toFloat(), endFingerCoordinateWithOffset.y.toFloat()) + + //startFingerCoordinatesList.add(startFingerCoordinateWithOffset) + //endFingerCoordinatesList.add(endFingerCoordinateWithOffset) + gestureBuilder.addStroke(StrokeDescription(p, 0, duration.toLong())) + } - gestureBuilder.addStroke(StrokeDescription(path, 0, duration.toLong())) + } val success = dispatchGesture(gestureBuilder.build(), null, null); - if (success) { - return Success(Unit) + return if (success) { + Success(Unit) } else { Error.FailedToDispatchGesture } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/MathUtils.kt b/app/src/main/java/io/github/sds100/keymapper/util/MathUtils.kt new file mode 100644 index 0000000000..fa87ee6d33 --- /dev/null +++ b/app/src/main/java/io/github/sds100/keymapper/util/MathUtils.kt @@ -0,0 +1,54 @@ +package io.github.sds100.keymapper.util + +import android.graphics.Point +import kotlin.math.atan2 +import kotlin.math.cos +import kotlin.math.hypot +import kotlin.math.sin + +data class Line( + val start: Point, + val end: Point +) + +fun deg2rad(degrees: Double): Double { + return degrees * Math.PI / 180; +} + +fun rad2deg(radians: Double): Double { + return radians * 180 / Math.PI; +} + +fun getPerpendicularOfLine( + p1: Point, + p2: Point, + length: Int, + reverse: Boolean = false +): Line { + var px = p1.y - p2.y + var py = p2.x - p1.x + + val len = (length / hypot(px.toFloat(), py.toFloat())).toInt() + px *= len + py *= len + + val start = Point(p1.x + px, p1.y + py) + val end = Point(p1.x - px, p1.y - py) + + return if (!reverse) { + Line(start, end) + } else { + Line(end, start) + } +} + +fun movePointByDistanceAndAngle(p: Point, distance: Int, degrees: Double): Point { + val newX = (p.x + cos(deg2rad(degrees)) * distance).toInt(); + val newY = (p.y + sin(deg2rad(degrees)) * distance).toInt(); + + return Point(newX, newY) +} + +fun angleBetweenPoints(p1: Point, p2: Point): Double { + return rad2deg(atan2((p2.y - p1.y).toDouble(), (p2.x - p1.x).toDouble())) +} diff --git a/app/src/main/res/layout/fragment_swipe_pick_coordinates.xml b/app/src/main/res/layout/fragment_swipe_pick_coordinates.xml index 762afa79ff..b4de38136d 100644 --- a/app/src/main/res/layout/fragment_swipe_pick_coordinates.xml +++ b/app/src/main/res/layout/fragment_swipe_pick_coordinates.xml @@ -12,11 +12,7 @@ type="io.github.sds100.keymapper.actions.swipescreen.SwipePickDisplayCoordinateViewModel" /> - - @@ -89,11 +85,12 @@ tools:text="241" /> + - + app:layout_constraintTop_toBottomOf="@+id/endLayout"> - + android:layout_weight="0.5" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="parent" + android:hint="@string/extra_label_swipe_duration" + android:padding="8dp" + app:errorWhenEmpty="@{true}"> - + - + + + + + + + + + +