Skip to content

Commit

Permalink
Merge pull request #235 from enaboapps/iss234
Browse files Browse the repository at this point in the history
Implement edit menu
  • Loading branch information
enaboapps authored Mar 14, 2024
2 parents d21aba8 + cab0c2b commit 5b31cfc
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.enaboapps.switchify.service.menu

import com.enaboapps.switchify.service.SwitchifyAccessibilityService
import com.enaboapps.switchify.service.menu.menus.edit.EditMenu
import com.enaboapps.switchify.service.menu.menus.gestures.GesturesMenu
import com.enaboapps.switchify.service.menu.menus.gestures.SwipeGesturesMenu
import com.enaboapps.switchify.service.menu.menus.gestures.TapGesturesMenu
Expand Down Expand Up @@ -110,6 +111,14 @@ class MenuManager {
openMenu(deviceMenu.build())
}

/**
* This function opens the edit menu
*/
fun openEditMenu() {
val editMenu = EditMenu(accessibilityService!!)
openMenu(editMenu.build())
}

/**
* This function opens the volume control menu
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.enaboapps.switchify.service.menu.menus.edit

import android.view.accessibility.AccessibilityNodeInfo
import com.enaboapps.switchify.service.SwitchifyAccessibilityService
import com.enaboapps.switchify.service.gestures.GesturePoint
import com.enaboapps.switchify.service.menu.MenuItem
import com.enaboapps.switchify.service.menu.menus.BaseMenu
import com.enaboapps.switchify.service.nodes.Node
import com.enaboapps.switchify.service.nodes.NodeExaminer

class EditMenu(accessibilityService: SwitchifyAccessibilityService) :
BaseMenu(accessibilityService, buildEditMenuItems(accessibilityService)) {
companion object {
private fun buildEditMenuItems(accessibilityService: SwitchifyAccessibilityService): List<MenuItem> {
val currentPoint = GesturePoint.getPoint()
val cutNode = NodeExaminer.findNodeForAction(currentPoint, Node.ActionType.CUT)
val copyNode = NodeExaminer.findNodeForAction(currentPoint, Node.ActionType.COPY)
val pasteNode = NodeExaminer.findNodeForAction(currentPoint, Node.ActionType.PASTE)
return listOfNotNull(
if (cutNode != null) {
MenuItem("Cut") {
cutNode.performAction(AccessibilityNodeInfo.ACTION_CUT)
}
} else null,
if (copyNode != null) {
MenuItem("Copy") {
copyNode.performAction(AccessibilityNodeInfo.ACTION_COPY)
}
} else null,
if (pasteNode != null) {
MenuItem("Paste") {
pasteNode.performAction(AccessibilityNodeInfo.ACTION_PASTE)
}
} else null
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.enaboapps.switchify.service.gestures.GesturePoint
import com.enaboapps.switchify.service.menu.MenuItem
import com.enaboapps.switchify.service.menu.MenuManager
import com.enaboapps.switchify.service.menu.menus.BaseMenu
import com.enaboapps.switchify.service.nodes.NodeExaminer
import com.enaboapps.switchify.service.scanning.ScanMethod
import com.enaboapps.switchify.service.utils.KeyboardInfo

Expand Down Expand Up @@ -35,6 +36,13 @@ class MainMenu(accessibilityService: SwitchifyAccessibilityService) :
MenuManager.getInstance().openDeviceMenu()
})

val canEdit = NodeExaminer.canPerformEditActions(GesturePoint.getPoint())
if (canEdit) {
menuItems.add(MenuItem("Edit", isLinkToMenu = true) {
MenuManager.getInstance().openEditMenu()
})
}

if (!KeyboardInfo.isKeyboardVisible) {
menuItems.add(MenuItem(MenuManager.getInstance().getTypeToSwitchTo()) {
MenuManager.getInstance().changeBetweenCursorAndItemScan()
Expand Down
23 changes: 23 additions & 0 deletions app/src/main/java/com/enaboapps/switchify/service/nodes/Node.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.enaboapps.switchify.service.window.SwitchifyAccessibilityWindow
* This class represents a node
*/
class Node : ScanNodeInterface {
private var nodeInfo: AccessibilityNodeInfo? = null
private var x: Int = 0
private var y: Int = 0
private var centerX: Int = 0
Expand All @@ -41,6 +42,7 @@ class Node : ScanNodeInterface {
val node = Node()
val rect = Rect()
nodeInfo.getBoundsInScreen(rect)
node.nodeInfo = nodeInfo
node.x = rect.left
node.y = rect.top
node.centerX = rect.centerX()
Expand All @@ -51,6 +53,27 @@ class Node : ScanNodeInterface {
}
}

enum class ActionType {
CUT, COPY, PASTE
}

fun isActionable(actionType: ActionType): Boolean {
return when (actionType) {
ActionType.CUT -> nodeInfo?.actionList?.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_CUT)
?: false

ActionType.COPY -> nodeInfo?.actionList?.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_COPY)
?: false

ActionType.PASTE -> nodeInfo?.actionList?.contains(AccessibilityNodeInfo.AccessibilityAction.ACTION_PASTE)
?: false
}
}

fun performAction(action: Int) {
nodeInfo?.performAction(action)
}

override fun getMidX(): Int {
return centerX
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,42 @@ object NodeExaminer {
allNodes
}

/**
* Finds the node that can perform the given action at the given point.
*
* @param point The point to find the node at.
* @param actionType The action to find the node for.
* @return The node that can perform the given action at the given point.
*/
fun findNodeForAction(point: PointF, actionType: Node.ActionType): Node? {
for (node in currentNodes) {
val width = node.getWidth()
val height = node.getHeight()
val left = node.getLeft()
val top = node.getTop()
if (point.x >= left && point.x <= left + width &&
point.y >= top && point.y <= top + height &&
node.isActionable(actionType)
) {
return node
}
}
return null
}

/**
* Checks if a node can perform any edit actions at the given point.
*
* @param point The point to check for edit actions.
* @return True if a node can perform any edit actions at the given point, false otherwise.
*/
fun canPerformEditActions(point: PointF): Boolean {
val cutNode = findNodeForAction(point, Node.ActionType.CUT)
val copyNode = findNodeForAction(point, Node.ActionType.COPY)
val pasteNode = findNodeForAction(point, Node.ActionType.PASTE)
return cutNode != null || copyNode != null || pasteNode != null
}

/**
* Finds the closest node to a given point on the screen.
*
Expand Down

0 comments on commit 5b31cfc

Please sign in to comment.