diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/dao/EventEntityDao.java b/app/src/main/java/com/auto/clicker/autoclicker/room/dao/EventEntityDao.java index e879ffa..e0f384c 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/room/dao/EventEntityDao.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/room/dao/EventEntityDao.java @@ -12,12 +12,5 @@ import java.util.List; @Dao public interface EventEntityDao { @Insert - long insertEventEntity(EventEntity eventEntity); // 返回新插入的 eventId - - @Delete - int deleteEventEntity(EventEntity eventEntity); - - // 查询某个方案下的所有事件实体,按顺序排序 - @Query("SELECT * FROM events WHERE solution_id = :solutionId ORDER BY order_in_solution ASC") - List getEventsForSolution(long solutionId); + long insertEventEntity(EventEntity eventEntity); } diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/dao/SolutionDao.java b/app/src/main/java/com/auto/clicker/autoclicker/room/dao/SolutionDao.java index 9230d35..a3e64ac 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/room/dao/SolutionDao.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/room/dao/SolutionDao.java @@ -20,26 +20,10 @@ public interface SolutionDao { @Query("SELECT * FROM solutions") List getAllSolutions(); - @Query("SELECT * FROM solutions WHERE solutionId = :solutionId LIMIT 1") - Solution getSolutionById(long solutionId); - - @Query("SELECT * FROM solutions WHERE solution_name = :solutionName LIMIT 1") - Solution getSolutionByName(String solutionName); - - @Delete - int deleteSolution(Solution solution); - - @Update - int updateSolution(Solution solution); - @Transaction @Query("SELECT * FROM solutions WHERE solutionId = :solutionId LIMIT 1") SolutionWithEventsAndPoints getSolutionWithEventsAndPoints(long solutionId); - @Transaction - @Query("SELECT * FROM solutions") - List getAllSolutionsWithEventsAndPoints(); - @Query("UPDATE solutions SET solution_name = :newName WHERE solutionId = :solutionId") int updateSolutionName(long solutionId, String newName); diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/dao/TouchPointDao.java b/app/src/main/java/com/auto/clicker/autoclicker/room/dao/TouchPointDao.java index f16fc3a..fded059 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/room/dao/TouchPointDao.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/room/dao/TouchPointDao.java @@ -11,14 +11,5 @@ import com.auto.clicker.autoclicker.room.entity.TouchPoint; @Dao public interface TouchPointDao { @Insert - long insertPoint(TouchPoint touchPoint); // 返回新插入的 pointId - - @Query("SELECT * FROM touchPoints WHERE pointId = :pointId LIMIT 1") - TouchPoint getPointById(long pointId); - - @Delete - int deletePoint(TouchPoint touchPoint); - - @Update - int updatePoint(TouchPoint touchPoint); + long insertPoint(TouchPoint touchPoint); } diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/repository/EventRepository.java b/app/src/main/java/com/auto/clicker/autoclicker/room/repository/EventRepository.java index a426c66..a63437c 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/room/repository/EventRepository.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/room/repository/EventRepository.java @@ -61,7 +61,7 @@ public class EventRepository { throw new RuntimeException("Failed to insert touch point for PointEvent."); EventEntity eventEntity = new EventEntity( - solutionId, // 使用 long 类型的 solutionId + solutionId, wrapper.getType().name(), order, pointId, @@ -86,13 +86,13 @@ public class EventRepository { throw new RuntimeException("Failed to insert end touch point for SlideEvent."); EventEntity eventEntity = new EventEntity( - solutionId, // 使用 long 类型的 solutionId + solutionId, wrapper.getType().name(), order, null, startPointId, endPointId, - 0 // duration for slide events, you might want to get this from SlideEvent + 0 ); eventEntityId = eventEntityDao.insertEventEntity(eventEntity); if (eventEntityId == -1) @@ -198,7 +198,7 @@ public class EventRepository { } EventEntity newEventEntity = new EventEntity( - newSolutionId, // 关联到新生成的方案ID + newSolutionId, eventWithPoints.eventEntity.eventType, eventWithPoints.eventEntity.orderInSolution, newClickPointId, @@ -235,7 +235,6 @@ public class EventRepository { public void saveDuplicateSolution(SolutionWithEventsAndPoints originalData, RepositoryCallback callback) { databaseWriteExecutor.execute(() -> { try { - // 创建新的 Solution 实例 Solution newSolution = new Solution(originalData.solution.solutionName + " (1)", originalData.solution.mode); long newSolutionId = solutionDao.insertSolution(newSolution); @@ -268,7 +267,6 @@ public class EventRepository { throw new RuntimeException("Failed to duplicate slide end point."); } - // 创建新的 EventEntity 实例 EventEntity newEventEntity = new EventEntity( newSolutionId, eventWithPoints.eventEntity.eventType, diff --git a/app/src/main/java/com/auto/clicker/autoclicker/service/AutoClickService.java b/app/src/main/java/com/auto/clicker/autoclicker/service/AutoClickService.java index 8eda466..35dfcaf 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/service/AutoClickService.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/service/AutoClickService.java @@ -153,19 +153,18 @@ public class AutoClickService extends AccessibilityService { isRunning = true; currentEventIndex = 0; - currentLoop = 0; // 重置循环计数 - startTimeMillis = System.currentTimeMillis(); // 记录开始时间 + currentLoop = 0; + startTimeMillis = System.currentTimeMillis(); EventViewBinder.setAllTouchPointsDraggable(false); - // 根据循环设置调整日志输出 String loopInfo; if (loopCount > 0) { loopInfo = "循环 " + (loopCount == 1 ? "1 次" : loopCount + " 次"); } else if (loopTimeMillis > 0) { loopInfo = "循环 " + (loopTimeMillis / 1000) + " 秒"; } else { - loopInfo = "无限循环"; // 如果两者都为0 + loopInfo = "无限循环"; } logDebug("开始执行事件队列 - 共 " + runtimeEvents.size() + " 个事件. " + loopInfo); @@ -266,7 +265,7 @@ public class AutoClickService extends AccessibilityService { int finalClickY = correctedViewTopY + touchPointSize / 2; Path path = new Path(); - path.moveTo(finalClickX, finalClickY); // 使用最终计算出的点击中心坐标 + path.moveTo(finalClickX, finalClickY); GestureDescription.StrokeDescription stroke = new GestureDescription.StrokeDescription(path, 0, clickDuration); GestureDescription gesture = @@ -278,8 +277,7 @@ public class AutoClickService extends AccessibilityService { logDebug("点击完成"); if (isRunning) { int feedbackIndex = currentEventIndex; - currentEventIndex++; // 事件索引递增 - // 延迟执行下一个事件,循环逻辑在executeEventsByType中处理 + currentEventIndex++; handler.postDelayed(() -> executeEventsByType(), clickInterval); flashTouchFeedback(feedbackIndex); } @@ -289,8 +287,7 @@ public class AutoClickService extends AccessibilityService { public void onCancelled(GestureDescription gestureDescription) { Log.e(TAG, "点击被取消"); if (isRunning) { - currentEventIndex++; // 事件索引递增 - // 延迟执行下一个事件 + currentEventIndex++; handler.postDelayed(() -> executeEventsByType(), clickInterval + 300); } } @@ -324,7 +321,6 @@ public class AutoClickService extends AccessibilityService { logDebug("滑动终点(修正后): (" + finalEndX + ", " + finalEndY + ")"); Path path = new Path(); - // 这里必须使用修正后的坐标,才能确保手势在正确的位置执行 path.moveTo(finalStartX, finalStartY); path.lineTo(finalEndX, finalEndY); @@ -339,8 +335,7 @@ public class AutoClickService extends AccessibilityService { logDebug("滑动完成"); if (isRunning) { int feedbackIndex = currentEventIndex; - currentEventIndex++; // 事件索引递增 - // 延迟执行下一个事件 + currentEventIndex++; handler.postDelayed(() -> executeEventsByType(), clickInterval); flashTouchFeedback(feedbackIndex); } @@ -353,8 +348,7 @@ public class AutoClickService extends AccessibilityService { public void onCancelled(GestureDescription gestureDescription) { Log.e(TAG, "滑动被取消"); if (isRunning) { - currentEventIndex++; // 事件索引递增 - // 延迟执行下一个事件 + currentEventIndex++; handler.postDelayed(() -> executeEventsByType(), clickInterval + 300); } logDebug("--- onCancelled: 下一个事件将是 index " + currentEventIndex + " ---"); diff --git a/app/src/main/java/com/auto/clicker/autoclicker/ui/activity/main/MainActivity.java b/app/src/main/java/com/auto/clicker/autoclicker/ui/activity/main/MainActivity.java index c49802f..ac72f1a 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/ui/activity/main/MainActivity.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/ui/activity/main/MainActivity.java @@ -44,6 +44,8 @@ public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; + private boolean isPermissionFlowActive = false; + public static final int FLOATING_NONE = 0; public static final int FLOATING_SINGLE = 1; public static final int FLOATING_MULTI = 2; @@ -66,10 +68,6 @@ public class MainActivity extends AppCompatActivity { isFloatingShown = intent.getIntExtra("isShown", FLOATING_NONE); logDebug("接收到浮窗状态广播: isShown = " + isFloatingShown); - if (isFloatingShown == FLOATING_NONE) { - } else { - selectedFloatingMode = isFloatingShown; - } updateSelectionButtons(); } }; @@ -95,9 +93,19 @@ public class MainActivity extends AppCompatActivity { @Override protected void onResume() { super.onResume(); - logDebug("onResume: 检查权限和同步服务状态"); - checkPermissions(); + logDebug("onResume: 同步服务状态并更新启动按钮状态"); syncServiceState(); + updateStartButtonState(); + if (isPermissionFlowActive) { + binding.getRoot().postDelayed(this::checkAllPermissionsAndRequestInSequence, 300); + } + } + + private void updateStartButtonState() { + boolean accessibilityGranted = isAccessibilityServiceEnabled(); + boolean overlayGranted = Settings.canDrawOverlays(this); + boolean batteryOptimizationIgnored = isIgnoringBatteryOptimizations(); + setStartButtonEnabled(accessibilityGranted && overlayGranted && batteryOptimizationIgnored); } private void initData() { @@ -116,10 +124,7 @@ public class MainActivity extends AppCompatActivity { permissionLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { logDebug("权限回调结果: " + result.getResultCode()); - binding.getRoot().postDelayed(() -> { - checkPermissions(); - syncServiceState(); - }, 300); + binding.getRoot().postDelayed(this::checkAllPermissionsAndRequestInSequence, 300); }); setVideo(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.bolangblue)); @@ -141,7 +146,12 @@ public class MainActivity extends AppCompatActivity { startActivity(intent); }); - binding.animatedView.setOnClickListener(v -> onToggleFloatingWindowClicked()); + binding.animatedView.setOnClickListener(v -> { + if (checkAllPermissionsAndRequestInSequence()) { + isPermissionFlowActive = false; + onToggleFloatingWindowClicked(); + } + }); binding.single.setOnClickListener(v -> { if (isFloatingShown != FLOATING_NONE) { @@ -155,7 +165,7 @@ public class MainActivity extends AppCompatActivity { binding.multi.setOnClickListener(v -> { if (isFloatingShown != FLOATING_NONE) { - Toast.makeText(this, "请先关闭悬浮窗再切换模式", Toast.LENGTH_SHORT).show(); + Toast.makeText(this, "Please close the floating window first and then switch the mode", Toast.LENGTH_SHORT).show(); return; } selectedFloatingMode = FLOATING_MULTI; @@ -166,11 +176,47 @@ public class MainActivity extends AppCompatActivity { handleIncomingIntent(getIntent()); } + private boolean checkAllPermissionsAndRequestInSequence() { + boolean accessibilityGranted = isAccessibilityServiceEnabled(); + boolean overlayGranted = Settings.canDrawOverlays(this); + boolean batteryOptimizationIgnored = isIgnoringBatteryOptimizations(); + + logDebug("检查权限 (序列流程): 无障碍服务=" + accessibilityGranted + ", 悬浮窗=" + overlayGranted + ", 电池优化=" + batteryOptimizationIgnored); + + if (!accessibilityGranted) { + logDebug("无障碍服务未启用,请求权限"); + showPermissionRequest(Settings.ACTION_ACCESSIBILITY_SETTINGS, "Please enable accessibility services to ensure the application works properly", "Accessibility Settings cannot be enabled"); + setStartButtonEnabled(false); + return false; + } + + if (!overlayGranted) { + logDebug("悬浮窗权限未授予,请求权限"); + Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); + showPermissionRequest(intent, "Please grant the floating window permission; otherwise, the floating window cannot be displayed", "The floating window setting cannot be opened"); + setStartButtonEnabled(false); + return false; + } + + if (!batteryOptimizationIgnored) { + logDebug("电池优化未忽略,请求权限"); + Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); + intent.setData(Uri.parse("package:" + getPackageName())); + showPermissionRequest(intent, "Please disable battery optimization to ensure the stable operation of the application in the background", "The battery optimization Settings cannot be opened"); + setStartButtonEnabled(false); + return false; + } + + logDebug("所有权限均已授予"); + setStartButtonEnabled(true); + isPermissionFlowActive = false; + return true; + } + @Override protected void onNewIntent(@NonNull Intent intent) { super.onNewIntent(intent); - // 如果 MainActivity 已经在运行,并且再次通过 Intent 启动,会调用 onNewIntent - setIntent(intent); // 更新当前的 Intent + setIntent(intent); handleIncomingIntent(intent); } @@ -197,7 +243,7 @@ public class MainActivity extends AppCompatActivity { if (!accessibilityGranted) { logDebug("无障碍服务未启用,请求权限"); - showPermissionRequest(Settings.ACTION_ACCESSIBILITY_SETTINGS, "请启用无障碍服务以便应用正常工作", "无法打开无障碍设置"); + showPermissionRequest(Settings.ACTION_ACCESSIBILITY_SETTINGS, "Please enable accessibility services to ensure the application works properly", "Accessibility Settings cannot be enabled"); setStartButtonEnabled(false); return; @@ -206,7 +252,7 @@ public class MainActivity extends AppCompatActivity { if (!overlayGranted) { logDebug("悬浮窗权限未授予,请求权限"); Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); - showPermissionRequest(intent, "请授予悬浮窗权限,否则无法显示浮窗", "无法打开悬浮窗设置"); + showPermissionRequest(intent, "Please grant the floating window permission; otherwise, the floating window cannot be displayed", "The floating window setting cannot be opened"); setStartButtonEnabled(false); return; @@ -216,7 +262,7 @@ public class MainActivity extends AppCompatActivity { logDebug("电池优化未忽略,请求权限"); Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); intent.setData(Uri.parse("package:" + getPackageName())); - showPermissionRequest(intent, "请禁用电池优化,以确保应用在后台稳定运行", "无法打开电池优化设置"); + showPermissionRequest(intent, "Please disable battery optimization to ensure the stable operation of the application in the background", "The battery optimization Settings cannot be opened"); setStartButtonEnabled(false); return; @@ -424,9 +470,9 @@ public class MainActivity extends AppCompatActivity { private void showDebounceToast() { if (debounceToast == null) { - debounceToast = Toast.makeText(this, "点击太频繁", Toast.LENGTH_SHORT); + debounceToast = Toast.makeText(this, "Click too frequently", Toast.LENGTH_SHORT); } else { - debounceToast.setText("点击太频繁"); + debounceToast.setText("Click too frequently"); } debounceToast.show(); } diff --git a/app/src/main/java/com/auto/clicker/autoclicker/ui/activity/menu/ScriptsActivity.java b/app/src/main/java/com/auto/clicker/autoclicker/ui/activity/menu/ScriptsActivity.java index 58ed125..4340b08 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/ui/activity/menu/ScriptsActivity.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/ui/activity/menu/ScriptsActivity.java @@ -155,13 +155,13 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte private void showRenameDialog(final Solution solution) { AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("重命名方案"); + builder.setTitle("Renaming script"); final EditText input = new EditText(this); input.setText(solution.getSolutionName()); builder.setView(input); - builder.setPositiveButton("确定", (dialog, which) -> { + builder.setPositiveButton("Sure", (dialog, which) -> { String newName = input.getText().toString().trim(); if (!newName.isEmpty() && !newName.equals(solution.getSolutionName())) { floatingViewManager.getEventRepository().updateSolutionName(solution.getSolutionId(), newName, new EventRepository.RepositoryCallback() { @@ -181,7 +181,7 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte }); } }); - builder.setNegativeButton("取消", (dialog, which) -> dialog.cancel()); + builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel()); builder.show(); } @@ -220,10 +220,10 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte private void showDeleteConfirmationDialog(final Solution solution) { new AlertDialog.Builder(this) - .setTitle("删除方案") - .setMessage("确定要删除方案 '" + solution.getSolutionName() + "' 吗?\n此操作不可撤销!") - .setPositiveButton("删除", (dialog, which) -> deleteSolution(solution)) - .setNegativeButton("取消", null) + .setTitle("Delete the script") + .setMessage("Are you sure you want to delete the script '" + solution.getSolutionName() + "'?\nThis action cannot be undone!") + .setPositiveButton("Delete", (dialog, which) -> deleteSolution(solution)) + .setNegativeButton("Cancel", null) .show(); } @@ -300,12 +300,11 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte SolutionWithEventsAndPoints importedData = floatingViewManager.getEventRepository().importSolutionFromJson(jsonString); if (importedData != null && importedData.solution != null) { - // 保存到数据库 floatingViewManager.getEventRepository().importSolutionFromData(importedData, new EventRepository.RepositoryCallback() { @Override public void onComplete(Void result) { new Handler(Looper.getMainLooper()).post(() -> { - loadSolutions(); // 刷新列表 + loadSolutions(); }); } diff --git a/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/floating/SolutionAdapter.java b/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/floating/SolutionAdapter.java index f8262ff..da8230e 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/floating/SolutionAdapter.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/floating/SolutionAdapter.java @@ -23,7 +23,6 @@ public class SolutionAdapter extends RecyclerView.Adapter solutionList, OnSolutionClickListener listener) { this.solutionList = solutionList; this.listener = listener; - this.optionMenuListener = null; // 设置为 null,表示不需要选项菜单 + this.optionMenuListener = null; } @NonNull @@ -56,7 +54,7 @@ public class SolutionAdapter extends RecyclerView.Adapter { applySettingsToService(); - Toast.makeText(getContext(), "设置已保存并应用!", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), "The Settings have been saved and applied!", Toast.LENGTH_SHORT).show(); }); return binding.getRoot(); @@ -113,9 +113,9 @@ public class ActionFragment extends Fragment { binding.advancedSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { if (isChecked) { - Toast.makeText(getContext(), "防检测模式已开启", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), "The anti-detection mode has been enabled", Toast.LENGTH_SHORT).show(); } else { - Toast.makeText(getContext(), "防检测模式已关闭", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), "The anti-detection mode has been turned off", Toast.LENGTH_SHORT).show(); } }); } @@ -246,11 +246,11 @@ public class ActionFragment extends Fragment { private void showInputValue(int type, String value, String unitText) { String typeName = ""; switch (type) { - case TYPE_INTERVAL: typeName = "点击间隔"; break; - case TYPE_SWIPE_DURATION: typeName = "滑动时长"; break; - case TYPE_REPEAT: typeName = "循环模式"; break; + case TYPE_INTERVAL: typeName = "Click interval"; break; + case TYPE_SWIPE_DURATION: typeName = "Sliding duration"; break; + case TYPE_REPEAT: typeName = "Circular mode"; break; } - String message = typeName + " 值: " + (value.isEmpty() ? "未输入" : value) + ", 单位: " + unitText; + String message = typeName + " Value: " + (value.isEmpty() ? "Not entered" : value) + ", Unit: " + unitText; Toast.makeText(getContext(), message, Toast.LENGTH_SHORT).show(); } @@ -293,7 +293,7 @@ public class ActionFragment extends Fragment { AutoClickService service = AutoClickService.getInstance(); if (service == null) { - Toast.makeText(getContext(), "自动点击服务未运行,无法应用设置。", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), "The auto-click service is not running and the Settings cannot be applied.", Toast.LENGTH_SHORT).show(); Log.e(TAG, "AutoClickService 实例为空,无法应用设置。"); return; } @@ -311,7 +311,7 @@ public class ActionFragment extends Fragment { Log.d(TAG, "应用点击间隔到服务: " + intervalValue + "ms"); } catch (NumberFormatException e) { Log.e(TAG, "点击间隔值解析错误: " + currentIntervalValue, e); - Toast.makeText(getContext(), "点击间隔值无效,请输入有效数字。", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), "The click interval value is invalid. Please enter a significant number.", Toast.LENGTH_SHORT).show(); } } else { Log.d(TAG, "点击间隔值为空,未应用到服务。"); @@ -328,7 +328,7 @@ public class ActionFragment extends Fragment { Log.d(TAG, "应用滑动时长到服务: " + slideDurationValue + "ms"); } catch (NumberFormatException e) { Log.e(TAG, "滑动时长值解析错误: " + currentDurationValue, e); - Toast.makeText(getContext(), "滑动时长值无效,请输入有效数字。", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), "The sliding duration value is invalid. Please enter a significant number.", Toast.LENGTH_SHORT).show(); } } else { Log.d(TAG, "滑动时长值为空,未应用到服务。"); @@ -347,7 +347,7 @@ public class ActionFragment extends Fragment { Log.d(TAG, "应用重复时长: " + repeatDurationMillis + "ms。"); } catch (NumberFormatException e) { Log.e(TAG, "重复时长值解析错误: " + currentRepeatValue, e); - Toast.makeText(getContext(), "重复时长值无效,请输入有效数字或正确的时间格式。", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), "Repeated duration values are invalid. Please enter significant figures or the correct time format.", Toast.LENGTH_SHORT).show(); service.setLoopTime(0); } } else { @@ -364,7 +364,7 @@ public class ActionFragment extends Fragment { Log.d(TAG, "应用重复次数: " + repeatCount + "次。"); } catch (NumberFormatException e) { Log.e(TAG, "重复次数值解析错误: " + currentRepeatValue, e); - Toast.makeText(getContext(), "重复次数值无效,请输入有效数字。", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), "Duplicate values are invalid. Please enter significant figures.", Toast.LENGTH_SHORT).show(); service.setLoopCount(1); } } else { diff --git a/app/src/main/java/com/auto/clicker/autoclicker/ui/fragment/setting/UISizeFragment.java b/app/src/main/java/com/auto/clicker/autoclicker/ui/fragment/setting/UISizeFragment.java index bf98384..9796c59 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/ui/fragment/setting/UISizeFragment.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/ui/fragment/setting/UISizeFragment.java @@ -41,7 +41,7 @@ public class UISizeFragment extends Fragment { setupPointSizeControl(); setupControlBarSizeControl(); } else { - Toast.makeText(getContext(), "自动化服务未运行,UI大小设置功能不可用。", Toast.LENGTH_LONG).show(); + Toast.makeText(getContext(), "The automated service is not running and the UI size setting function is unavailable.", Toast.LENGTH_LONG).show(); disableAllControlUI(); } @@ -74,7 +74,7 @@ public class UISizeFragment extends Fragment { int finalSize = seekBar.getProgress() + MIN_POINT_SIZE; floatingViewManager.setTouchPointSize(finalSize); Log.d(TAG, "触摸点大小设置为: " + finalSize + "px"); - Toast.makeText(getContext(), "触摸点大小已更新", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), "The size of the touch points has been updated", Toast.LENGTH_SHORT).show(); } }); } @@ -109,7 +109,7 @@ public class UISizeFragment extends Fragment { int finalWidthPx = seekBar.getProgress() + minControlBarWidthPx; floatingViewManager.setControlBarSize(finalWidthPx); Log.d(TAG, "控制栏大小设置为: " + pxToDp(finalWidthPx) + "dp (" + finalWidthPx + "px)"); - Toast.makeText(getContext(), "控制栏大小已更新", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), "The size of the control bar has been updated", Toast.LENGTH_SHORT).show(); } }); } diff --git a/app/src/main/java/com/auto/clicker/autoclicker/util/DraggableHelper.java b/app/src/main/java/com/auto/clicker/autoclicker/util/DraggableHelper.java index 9e45218..2a95f57 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/util/DraggableHelper.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/util/DraggableHelper.java @@ -1,61 +1,8 @@ package com.auto.clicker.autoclicker.util; -import android.view.MotionEvent; -import android.view.View; -import android.view.WindowManager; - public class DraggableHelper { public interface DragCallback { void onPositionChanged(int x, int y); } - - public static void makeDraggable(View view, - WindowManager.LayoutParams params, - WindowManager windowManager, - int screenWidth, int screenHeight, - DragCallback callback) { - - view.setOnTouchListener(new View.OnTouchListener() { - private float lastX, lastY; - private float paramX, paramY; - - @Override - public boolean onTouch(View v, MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - lastX = event.getRawX(); - lastY = event.getRawY(); - paramX = params.x; - paramY = params.y; - return true; - - case MotionEvent.ACTION_MOVE: - float dx = event.getRawX() - lastX; - float dy = event.getRawY() - lastY; - - int newX = (int) (paramX + dx); - int newY = (int) (paramY + dy); - - newX = Math.max(0, Math.min(newX, screenWidth - view.getWidth())); - newY = Math.max(0, Math.min(newY, screenHeight - view.getHeight())); - - params.x = newX; - params.y = newY; - - windowManager.updateViewLayout(view, params); - - if (callback != null) { - callback.onPositionChanged(newX, newY); - } - return true; - - case MotionEvent.ACTION_UP: - v.performClick(); - return true; - } - return false; - } - }); - } } \ No newline at end of file diff --git a/app/src/main/java/com/auto/clicker/autoclicker/util/EventViewBinder.java b/app/src/main/java/com/auto/clicker/autoclicker/util/EventViewBinder.java index 0506c75..80202bf 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/util/EventViewBinder.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/util/EventViewBinder.java @@ -103,7 +103,6 @@ public class EventViewBinder { startView.setOnTouchListener(startTouchListener); activeDragListeners.put(startView, startTouchListener); // 保存监听器 - // 拖动终点 - 创建并保存监听器 View.OnTouchListener endTouchListener = createTouchListener( endView, endParams, windowManager, screenWidth, screenHeight, (x, y) -> { @@ -113,7 +112,7 @@ public class EventViewBinder { if (callback != null) callback.onPositionChanged(x, y); }); endView.setOnTouchListener(endTouchListener); - activeDragListeners.put(endView, endTouchListener); // 保存监听器 + activeDragListeners.put(endView, endTouchListener); windowManager.addView(lineView, lineParams); windowManager.addView(startView, startParams); diff --git a/app/src/main/java/com/auto/clicker/autoclicker/view/ConnectingLineView.java b/app/src/main/java/com/auto/clicker/autoclicker/view/ConnectingLineView.java index 1997b75..b5a8976 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/view/ConnectingLineView.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/view/ConnectingLineView.java @@ -15,28 +15,20 @@ import com.auto.clicker.autoclicker.R; public class ConnectingLineView extends View { - // 画笔,用于绘制连接带。设置为填充样式。 private final Paint connectionBandPaint; - // 连接带的宽度,单位 dp。 private final float CONNECTION_BAND_WIDTH_DP = 30f; - // 连接带在屏幕上的实际像素宽度。 private float connectionBandWidthPx; - // 绘制时,连接带的逻辑起始点和结束点(在 View 自身的坐标系中)。 private float drawStartX, drawStartY, drawEndX, drawEndY; - // 连接带的长度。 private float lineLength; - // 连接带的旋转角度(以度为单位)。 private float rotationAngle; - // 用于表示方向的 Drawable 图标。 private Drawable startArrowDrawable; private Drawable endArrowDrawable; public ConnectingLineView(Context context) { super(context); - // 将 dp 单位的宽度转换为像素单位,以便在 Canvas 上绘制。 connectionBandWidthPx = dpToPx(context, CONNECTION_BAND_WIDTH_DP); connectionBandPaint = new Paint(); @@ -56,16 +48,11 @@ public class ConnectingLineView extends View { public void setPoints(float startX, float startY, float endX, float endY) { - // 计算两点间的X和Y坐标差。 float deltaX = endX - startX; float deltaY = endY - startY; - // 计算连接带的长度(两点间的直线距离)。 this.lineLength = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY); - // 计算连接带的旋转角度。 - // Math.atan2(y, x) 返回的是从X轴正向到点(x,y)的弧度,范围是-PI到PI。 - // Math.toDegrees 将弧度转换为度数。 this.rotationAngle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX)); this.drawStartX = startX; @@ -85,34 +72,21 @@ public class ConnectingLineView extends View { } // 保存当前画布的状态。 - // 这允许我们对画布进行平移和旋转操作,而不会影响后续或外部的绘制。 canvas.save(); - // 1. 平移画布到连接带的起始点。 - // 这样,在绘制时,连接带的逻辑起始点就变成了 (0,0)。 canvas.translate(drawStartX, drawStartY); - // 2. 旋转画布。 - // 围绕当前的画布原点(即连接带的起始点)旋转画布。 - // 之后绘制的所有内容都会以这个角度显示。 canvas.rotate(rotationAngle); - // 3. 绘制连接带的矩形。 - // RectF 定义了一个矩形。由于画布已经旋转和平移, - // 这里的 (0, -connectionBandWidthPx / 2) 是矩形的左上角, - // (lineLength, connectionBandWidthPx / 2) 是矩形的右下角。 - // 这样矩形就会以当前 Y 轴为中心,从当前 X 轴原点(0)延伸到 lineLength。 RectF rect = new RectF(0, -connectionBandWidthPx / 2, lineLength, connectionBandWidthPx / 2); canvas.drawRect(rect, connectionBandPaint); - // 4. 绘制起始方向图标。 if (startArrowDrawable != null) { int arrowSize = (int) (connectionBandWidthPx / 2); - // 设置图标的边界。这里的坐标是相对于当前已旋转和平移的画布。 - // 确保图标垂直居中于连接带。 + startArrowDrawable.setBounds( 75, - (int) (-arrowSize / 2),// 垂直居中 + (int) (-arrowSize / 2), 75 + arrowSize, (int) (arrowSize / 2) ); diff --git a/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingSettingDialogManager.java b/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingSettingDialogManager.java index ab88f27..7b95e33 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingSettingDialogManager.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingSettingDialogManager.java @@ -114,7 +114,7 @@ public class FloatingSettingDialogManager { saveCurrentSettings(); applySettingsToService(); removeFloatingTabDialog(); - showToastOnUi(context, "设置已保存!"); + showToastOnUi(context, "The Settings have been saved.!"); }); } else { Log.e(TAG, "Save button not found!"); @@ -123,7 +123,7 @@ public class FloatingSettingDialogManager { if (closeButton != null) { closeButton.setOnClickListener(v -> { removeFloatingTabDialog(); - showToastOnUi(context, "设置已关闭,未保存更改。"); + showToastOnUi(context, "The Settings have been turned off and no changes have been saved。"); }); } else { Log.e(TAG, "Close button not found!"); @@ -134,10 +134,10 @@ public class FloatingSettingDialogManager { Log.d(TAG, "浮动标签页弹窗已显示"); } catch (WindowManager.BadTokenException e) { Log.e(TAG, "无法添加浮动标签页弹窗,可能是权限问题或上下文无效", e); - showToastOnUi(context, "显示弹窗失败,请检查权限。"); + showToastOnUi(context, "The pop-up window failed to display. Please check the permissions。"); } catch (SecurityException e) { Log.e(TAG, "需要悬浮窗权限才能显示浮动弹窗", e); - showToastOnUi(context, "请授予悬浮窗权限以便显示。"); + showToastOnUi(context, "Please grant the floating window permission for display。"); } } @@ -320,7 +320,7 @@ public class FloatingSettingDialogManager { String unitText = context.getString(R.string.duration_unit); repeatSelectedUnit.setText(unitText); currentRepeatUnit = unitText; - etRepeatValue.setText(""); // 清空以便用户输入新值 + etRepeatValue.setText(""); etRepeatValue.setEnabled(true); etRepeatValue.setInputType(InputType.TYPE_CLASS_NUMBER); popupWindow.dismiss(); @@ -359,7 +359,7 @@ public class FloatingSettingDialogManager { AutoClickService service = AutoClickService.getInstance(); if (service == null) { Log.e(TAG, "AutoClickService 实例为空,无法应用设置。"); - showToastOnUi(context, "自动点击服务未运行,无法应用设置。"); + showToastOnUi(context, "The auto-click service is not running and the Settings cannot be applied。"); return; } @@ -377,7 +377,7 @@ public class FloatingSettingDialogManager { Log.d(TAG, "应用点击间隔到服务: " + intervalValue + "ms"); } catch (NumberFormatException e) { Log.e(TAG, "点击间隔值解析错误: " + currentIntervalValue, e); - showToastOnUi(context, "点击间隔值无效,请输入有效数字。"); + showToastOnUi(context, "The click interval value is invalid. Please enter a significant number。"); } } else { Log.d(TAG, "点击间隔值为空,未应用到服务。"); @@ -394,7 +394,7 @@ public class FloatingSettingDialogManager { Log.d(TAG, "应用滑动时长到服务: " + slideDurationValue + "ms"); } catch (NumberFormatException e) { Log.e(TAG, "滑动时长值解析错误: " + currentDurationValue, e); - showToastOnUi(context, "滑动时长值无效,请输入有效数字。"); + showToastOnUi(context, "The sliding duration value is invalid. Please enter a significant number。"); } } else { Log.d(TAG, "滑动时长值为空,未应用到服务。"); @@ -413,7 +413,7 @@ public class FloatingSettingDialogManager { Log.d(TAG, "应用重复时长: " + repeatDurationMillis + "ms。"); } catch (NumberFormatException e) { Log.e(TAG, "重复时长值解析错误: " + currentRepeatValue, e); - showToastOnUi(context, "重复时长值无效,请输入有效数字。"); + showToastOnUi(context, "Repeated duration values are invalid. Please enter valid numbers。"); service.setLoopTime(0); // 错误时,取消时间循环 } } else { @@ -430,7 +430,7 @@ public class FloatingSettingDialogManager { Log.d(TAG, "应用重复次数: " + repeatCount + "次。"); } catch (NumberFormatException e) { Log.e(TAG, "重复次数值解析错误: " + currentRepeatValue, e); - showToastOnUi(context, "重复次数值无效,请输入有效数字。"); + showToastOnUi(context, "Duplicate values are invalid. Please enter significant figures。"); service.setLoopCount(1); // 错误时,设置为执行一次 } } else { @@ -465,17 +465,16 @@ public class FloatingSettingDialogManager { if (!currentSwipeDurationUnit.isEmpty()) { tvSelectedUnit.setText(currentSwipeDurationUnit); } else { - tvSelectedUnit.setText(context.getString(R.string.milliseconds_unit)); // 默认单位 + tvSelectedUnit.setText(context.getString(R.string.milliseconds_unit)); currentSwipeDurationUnit = context.getString(R.string.milliseconds_unit); } // 恢复重复设置 repeatSwitch.setChecked(isRepeatSwitchChecked); - updateRepeatUI(isRepeatSwitchChecked); // 根据开关状态更新UI + updateRepeatUI(isRepeatSwitchChecked); if (isRepeatSwitchChecked) { if (currentRepeatUnit.isEmpty()) { - // 如果没有保存的单位,默认为无限次 repeatSelectedUnit.setText(context.getString(R.string.infinitely_unit)); currentRepeatUnit = context.getString(R.string.infinitely_unit); etRepeatValue.setText(""); diff --git a/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingTabDialogManager.java b/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingTabDialogManager.java index 055aca0..06b7c00 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingTabDialogManager.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingTabDialogManager.java @@ -123,7 +123,7 @@ public class FloatingTabDialogManager { Toast.makeText(context, "正在加载方案: " + solution.getSolutionName(), Toast.LENGTH_SHORT).show(); } else { Log.e(TAG, "FloatingViewManager 未设置!无法加载方案。"); - Toast.makeText(context, "加载功能不可用,请联系开发者。", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "The loading function is unavailable. Please contact the developer.", Toast.LENGTH_SHORT).show(); } removeFloatingTabDialog(); }); @@ -138,10 +138,10 @@ public class FloatingTabDialogManager { Log.d(TAG, "浮动标签页弹窗已显示"); } catch (WindowManager.BadTokenException e) { Log.e(TAG, "无法添加浮动标签页弹窗,可能是权限问题或上下文无效", e); - Toast.makeText(context, "显示弹窗失败,请检查权限。", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "The pop-up window failed to display. Please check the permissions.", Toast.LENGTH_SHORT).show(); } catch (SecurityException e) { Log.e(TAG, "需要悬浮窗权限才能显示浮动弹窗", e); - Toast.makeText(context, "请授予悬浮窗权限以便显示。", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "Please grant the floating window permission for display。", Toast.LENGTH_SHORT).show(); } } @@ -174,7 +174,7 @@ public class FloatingTabDialogManager { if (floatingViewManager == null) { Log.e(TAG, "FloatingViewManager 未设置,无法加载方案列表。"); new Handler(Looper.getMainLooper()).post(() -> - Toast.makeText(context, "加载方案列表功能不可用。", Toast.LENGTH_SHORT).show() + Toast.makeText(context, "The function of loading the list of schemes is not available。", Toast.LENGTH_SHORT).show() ); return; } @@ -184,7 +184,7 @@ public class FloatingTabDialogManager { new Handler(Looper.getMainLooper()).post(() -> { solutionsAdapter.setSolutions(solutions); if (solutions.isEmpty()) { - Toast.makeText(context, "没有可加载的方案。", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "There is no loadable scheme。", Toast.LENGTH_SHORT).show(); } }); } @@ -193,7 +193,7 @@ public class FloatingTabDialogManager { public void onError(Exception e) { new Handler(Looper.getMainLooper()).post(() -> { Log.e(TAG, "加载方案列表失败: " + e.getMessage(), e); - Toast.makeText(context, "加载方案列表失败。", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "The loading of the scheme list failed。", Toast.LENGTH_SHORT).show(); }); } }); diff --git a/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingViewManager.java b/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingViewManager.java index 58c89dc..514afb9 100644 --- a/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingViewManager.java +++ b/app/src/main/java/com/auto/clicker/autoclicker/view/FloatingViewManager.java @@ -113,7 +113,7 @@ public class FloatingViewManager { public void showFloatingViews(int mode) throws SecurityException { if (!Settings.canDrawOverlays(context)) { - throw new SecurityException("需要悬浮窗许可"); + throw new SecurityException("A floating window permit is required"); } this.mode = mode; @@ -285,7 +285,7 @@ public class FloatingViewManager { } if (runtimeEvents.isEmpty()) { - Toast.makeText(context, "请添加一个触摸点或者滑动事件", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "Please add a touch point or a sliding event", Toast.LENGTH_SHORT).show(); return; } @@ -303,7 +303,7 @@ public class FloatingViewManager { private void addPointEvent() { if (isMultipleRunning) { - Toast.makeText(context, "请停止点击", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "Please stop clicking.", Toast.LENGTH_SHORT).show(); return; } @@ -322,7 +322,7 @@ public class FloatingViewManager { private void addSlideEvent() { if (isMultipleRunning) { - Toast.makeText(context, "请先停止点击", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "Please stop clicking first", Toast.LENGTH_SHORT).show(); return; } @@ -428,12 +428,12 @@ public class FloatingViewManager { private void removeLastEvent() { if (isMultipleRunning) { - Toast.makeText(context, "请先停止点击", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "Please stop clicking first", Toast.LENGTH_SHORT).show(); return; } if (runtimeEvents.isEmpty()) { - Toast.makeText(context, "没有更多的事件需要删除", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "There are no more events to be deleted", Toast.LENGTH_SHORT).show(); return; } @@ -449,7 +449,7 @@ public class FloatingViewManager { service.stopClicking(); } else { Log.d(TAG, "自动点击服务没有初始化"); - Toast.makeText(context, "请同意无障碍服务权限", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "Please agree to the accessibility service permission", Toast.LENGTH_SHORT).show(); } removeAllFloatingViews(); @@ -467,7 +467,7 @@ public class FloatingViewManager { service.startClicking(); Log.d(TAG, "开始多点点击事件 " + runtimeEvents.size()); - Toast.makeText(context, "多点点击开始", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "Click more to start", Toast.LENGTH_SHORT).show(); updateTouchPointsBackground(R.drawable.touch_point); @@ -476,7 +476,7 @@ public class FloatingViewManager { private void stopMultiClicking(AutoClickService service) { service.stopClicking(); - Toast.makeText(context, "多点点击停止", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "Click more to stop", Toast.LENGTH_SHORT).show(); updateTouchPointsBackground(R.drawable.ring_has_bg); @@ -592,7 +592,7 @@ public class FloatingViewManager { private void handleMissingService() { Log.e(TAG, "自动点击服务没有初始化"); - Toast.makeText(context, "请在设置里同意无障碍服务", Toast.LENGTH_LONG).show(); + Toast.makeText(context, "Please agree to accessibility services in the Settings", Toast.LENGTH_LONG).show(); Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); @@ -650,14 +650,14 @@ public class FloatingViewManager { public void saveCurrentEventsAsSolution(String solutionName, EventRepository.RepositoryCallback callback) { if (solutionName == null || solutionName.trim().isEmpty()) { - Toast.makeText(context, "方案名称不能为空", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "The script name cannot be empty", Toast.LENGTH_SHORT).show(); if (callback != null) { callback.onComplete(-1L); } return; } if (runtimeEvents.isEmpty()) { - Toast.makeText(context, "当前没有事件可以保存", Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "There are no events that can be saved at present", Toast.LENGTH_SHORT).show(); if (callback != null) { callback.onComplete(-1L); } @@ -676,9 +676,9 @@ public class FloatingViewManager { @Override public void onError(Exception e) { Log.e(TAG, "保存方案失败: " + e.getMessage(), e); - Toast.makeText(context, "保存方案失败: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + Toast.makeText(context, "Failed to save the script: " + e.getMessage(), Toast.LENGTH_SHORT).show(); if (callback != null) { - callback.onError(e); // 将错误传递给调用者 + callback.onError(e); } } }); diff --git a/app/src/main/res/layout/floating_tab_dialog.xml b/app/src/main/res/layout/floating_tab_dialog.xml index ad98c26..8d4e19c 100644 --- a/app/src/main/res/layout/floating_tab_dialog.xml +++ b/app/src/main/res/layout/floating_tab_dialog.xml @@ -21,7 +21,7 @@ android:layout_height="wrap_content" android:layout_weight="1" android:background="?attr/selectableItemBackground" - android:text="选项卡一" + android:text="Save" android:textColor="@color/black" />