diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 00db0e7..78207e4 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,13 +18,6 @@
android:supportsRtl="true"
android:theme="@style/Theme.AutoClicker"
tools:targetApi="31">
-
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/data/PointEvent.java b/app/src/main/java/com/auto/clicker/autoclicker/data/PointEvent.java
index 76702b5..e180cb7 100644
--- a/app/src/main/java/com/auto/clicker/autoclicker/data/PointEvent.java
+++ b/app/src/main/java/com/auto/clicker/autoclicker/data/PointEvent.java
@@ -1,21 +1,29 @@
package com.auto.clicker.autoclicker.data;
-import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
public class PointEvent extends Event {
+ private int id;
private int x;
private int y;
- private TextView view;
- private WindowManager.LayoutParams layoutParams;
- public PointEvent(int id, int x, int y, TextView view, WindowManager.LayoutParams layoutParams) {
+ private transient TextView view;
+ private transient WindowManager.LayoutParams layoutParams;
+
+ public PointEvent(int id, int x, int y) {
super(id);
this.x = x;
this.y = y;
- this.view = view;
- this.layoutParams = layoutParams;
+ }
+
+ @Override
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
}
public int getX() {
@@ -34,7 +42,7 @@ public class PointEvent extends Event {
this.y = y;
}
- public View getView() {
+ public TextView getView() {
return view;
}
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/data/SlideEvent.java b/app/src/main/java/com/auto/clicker/autoclicker/data/SlideEvent.java
index a1adaa1..1f0cce5 100644
--- a/app/src/main/java/com/auto/clicker/autoclicker/data/SlideEvent.java
+++ b/app/src/main/java/com/auto/clicker/autoclicker/data/SlideEvent.java
@@ -4,20 +4,27 @@ import android.view.WindowManager;
import com.auto.clicker.autoclicker.view.ConnectingLineView;
-
public class SlideEvent extends Event {
+ private int id;
private PointEvent startPoint;
private PointEvent endPoint;
- private ConnectingLineView lineView;
- private WindowManager.LayoutParams lineParams;
- public SlideEvent(int id, PointEvent startPoint, PointEvent endPoint,
- ConnectingLineView lineView, WindowManager.LayoutParams lineParams) {
+ private transient ConnectingLineView lineView;
+ private transient WindowManager.LayoutParams lineParams;
+
+ public SlideEvent(int id, PointEvent startPoint, PointEvent endPoint) {
super(id);
this.startPoint = startPoint;
this.endPoint = endPoint;
- this.lineView = lineView;
- this.lineParams = lineParams;
+ }
+
+ @Override
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
}
public PointEvent getStartPoint() {
@@ -51,5 +58,4 @@ public class SlideEvent extends Event {
public void setLineParams(WindowManager.LayoutParams lineParams) {
this.lineParams = lineParams;
}
-
}
\ No newline at end of file
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/dialog/LoadScriptView.java b/app/src/main/java/com/auto/clicker/autoclicker/dialog/LoadScriptView.java
deleted file mode 100644
index 29b70f7..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/dialog/LoadScriptView.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.auto.clicker.autoclicker.dialog;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.view.LayoutInflater;
-
-import androidx.constraintlayout.widget.ConstraintLayout;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.auto.clicker.autoclicker.R;
-import com.auto.clicker.autoclicker.room.AppDatabase;
-import com.auto.clicker.autoclicker.room.ScriptEntity;
-import com.auto.clicker.autoclicker.ui.adapter.script.ScriptListAdapter;
-
-import java.util.List;
-
-public class LoadScriptView extends ConstraintLayout {
- public interface OnScriptClickListener {
- void onScriptSelected(ScriptEntity script);
- }
-
- public LoadScriptView(Context context, OnScriptClickListener listener) {
- super(context);
- LayoutInflater.from(context).inflate(R.layout.load_script_page, this, true);
-
- RecyclerView recyclerView = findViewById(R.id.script_list);
- recyclerView.setLayoutManager(new LinearLayoutManager(context));
-
- new Thread(() -> {
- List scripts = AppDatabase.getInstance(context).scriptDao().getAllScripts();
- new Handler(Looper.getMainLooper()).post(() -> {
- recyclerView.setAdapter(new ScriptListAdapter(scripts, listener));
- });
- }).start();
- }
-}
-
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/dialog/SaveScriptView.java b/app/src/main/java/com/auto/clicker/autoclicker/dialog/SaveScriptView.java
deleted file mode 100644
index c0dce6d..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/dialog/SaveScriptView.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.auto.clicker.autoclicker.dialog;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import androidx.appcompat.widget.AppCompatButton;
-import androidx.constraintlayout.widget.ConstraintLayout;
-
-import com.auto.clicker.autoclicker.R;
-
-public class SaveScriptView extends ConstraintLayout {
- public interface OnSaveListener {
- void onSave(String scriptName);
- }
-
- public SaveScriptView(Context context, OnSaveListener listener) {
- super(context);
- LayoutInflater.from(context).inflate(R.layout.save_script_page, this, true);
-
- EditText input = findViewById(R.id.script_name_input);
- AppCompatButton saveBtn = findViewById(R.id.save);
-
- saveBtn.setOnClickListener(v -> {
- String name = input.getText().toString().trim();
- if (!name.isEmpty()) {
- listener.onSave(name);
- } else {
- Toast.makeText(context, "名称不能为空", Toast.LENGTH_SHORT).show();
- }
- });
- }
-}
-
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/dialog/ScriptManagerDialog.java b/app/src/main/java/com/auto/clicker/autoclicker/dialog/ScriptManagerDialog.java
deleted file mode 100644
index b9666e4..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/dialog/ScriptManagerDialog.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.auto.clicker.autoclicker.dialog;
-
-import android.content.Context;
-import android.graphics.PixelFormat;
-import android.os.Build;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-
-import androidx.viewpager2.widget.ViewPager2;
-
-import com.auto.clicker.autoclicker.R;
-import com.auto.clicker.autoclicker.room.ScriptEntity;
-import com.auto.clicker.autoclicker.ui.adapter.dialog.ViewPagerAdapter;
-import com.google.android.material.tabs.TabLayout;
-import com.google.android.material.tabs.TabLayoutMediator;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ScriptManagerDialog {
- private final WindowManager windowManager;
- private final View rootView;
-
- public ScriptManagerDialog(Context context) {
- windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-
- rootView = LayoutInflater.from(context).inflate(R.layout.dialog_script_container, null);
- TabLayout tabLayout = rootView.findViewById(R.id.tab_layout);
- ViewPager2 viewPager = rootView.findViewById(R.id.view_pager);
-
- List pages = new ArrayList<>();
- pages.add(new SaveScriptView(context, this::onScriptSaved));
- pages.add(new LoadScriptView(context, this::onScriptSelected));
-
- viewPager.setAdapter(new ViewPagerAdapter(pages));
- new TabLayoutMediator(tabLayout, viewPager,
- (tab, position) -> tab.setText(position == 0 ? "保存脚本" : "加载脚本")).attach();
-
- // 悬浮窗参数
- WindowManager.LayoutParams params = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.WRAP_CONTENT,
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
- WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
- WindowManager.LayoutParams.TYPE_PHONE,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
- PixelFormat.TRANSLUCENT
- );
- params.gravity = Gravity.CENTER;
- windowManager.addView(rootView, params);
- }
-
- private void onScriptSaved(String name) {
- // 插入数据库逻辑
- }
-
- private void onScriptSelected(ScriptEntity script) {
- // 加载并恢复脚本逻辑
- }
-
- public void dismiss() {
- windowManager.removeView(rootView);
- }
-
- public void show() {
- WindowManager.LayoutParams params = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.WRAP_CONTENT,
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
- WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
- WindowManager.LayoutParams.TYPE_PHONE,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
- PixelFormat.TRANSLUCENT
- );
- params.gravity = Gravity.CENTER;
- try {
- windowManager.addView(rootView, params);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-}
-
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/AppDatabase.java b/app/src/main/java/com/auto/clicker/autoclicker/room/AppDatabase.java
index ecbe19c..a0d21c5 100644
--- a/app/src/main/java/com/auto/clicker/autoclicker/room/AppDatabase.java
+++ b/app/src/main/java/com/auto/clicker/autoclicker/room/AppDatabase.java
@@ -7,12 +7,18 @@ import androidx.room.Room;
import androidx.room.RoomDatabase;
import com.auto.clicker.autoclicker.MyApplication;
+import com.auto.clicker.autoclicker.room.dao.EventEntityDao;
+import com.auto.clicker.autoclicker.room.dao.TouchPointDao;
+import com.auto.clicker.autoclicker.room.dao.SolutionDao;
+import com.auto.clicker.autoclicker.room.entity.EventEntity;
+import com.auto.clicker.autoclicker.room.entity.TouchPoint;
+import com.auto.clicker.autoclicker.room.entity.Solution;
-@Database(entities = {ScriptEntity.class,PointEventEntity.class,SlideEventEntity.class}, version = MyApplication.DB_VERSION, exportSchema = false)
+@Database(entities = {Solution.class, TouchPoint.class, EventEntity.class}, version = MyApplication.DB_VERSION, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
- public abstract ScriptEntityDao scriptDao();
- public abstract PointEventEntityDao pointEventEntityDao();
- public abstract SlideEventEntityDao slideEventEntityDao();
+ public abstract SolutionDao solutionDao();
+ public abstract TouchPointDao pointDao();
+ public abstract EventEntityDao eventEntityDao();
private static volatile AppDatabase INSTANCE;
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/PointEventEntity.java b/app/src/main/java/com/auto/clicker/autoclicker/room/PointEventEntity.java
deleted file mode 100644
index 94ddeae..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/room/PointEventEntity.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.auto.clicker.autoclicker.room;
-
-import androidx.room.Entity;
-import androidx.room.ForeignKey;
-import androidx.room.Index;
-import androidx.room.PrimaryKey;
-
-@Entity(tableName = "point_events",
- foreignKeys = @ForeignKey(entity = ScriptEntity.class,
- parentColumns = "scriptId",
- childColumns = "scriptOwnerId",
- onDelete = ForeignKey.CASCADE),
- indices = {@Index("scriptOwnerId")})
-public class PointEventEntity {
- @PrimaryKey(autoGenerate = true)
- public long pointId;
-
- public int x;
- public int y;
- public int order;
- public long scriptOwnerId;
-}
-
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/PointEventEntityDao.java b/app/src/main/java/com/auto/clicker/autoclicker/room/PointEventEntityDao.java
deleted file mode 100644
index 574a48a..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/room/PointEventEntityDao.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.auto.clicker.autoclicker.room;
-
-import androidx.room.Dao;
-
-@Dao
-public interface PointEventEntityDao {
-}
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/ScriptEntity.java b/app/src/main/java/com/auto/clicker/autoclicker/room/ScriptEntity.java
deleted file mode 100644
index de63b05..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/room/ScriptEntity.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.auto.clicker.autoclicker.room;
-
-import androidx.room.Entity;
-import androidx.room.PrimaryKey;
-
-@Entity(tableName = "scripts")
-public class ScriptEntity {
- @PrimaryKey(autoGenerate = true)
- public long scriptId;
-
- public String name;
- public long createdTime;
-}
-
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/ScriptEntityDao.java b/app/src/main/java/com/auto/clicker/autoclicker/room/ScriptEntityDao.java
deleted file mode 100644
index 39decfd..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/room/ScriptEntityDao.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.auto.clicker.autoclicker.room;
-
-import androidx.room.Dao;
-import androidx.room.Delete;
-import androidx.room.Insert;
-import androidx.room.Query;
-import androidx.room.Transaction;
-
-import java.util.List;
-
-@Dao
-public interface ScriptEntityDao {
- @Insert
- long insertScript(ScriptEntity script);
- @Insert void insertPointEvents(List points);
- @Insert void insertSlideEvents(List slides);
-
- @Transaction
- @Query("SELECT * FROM scripts")
- List getAllScripts();
-
- @Transaction
- @Query("SELECT * FROM scripts WHERE scriptId = :scriptId")
- ScriptWithEvents getScriptById(long scriptId);
-
- @Delete
- void deleteScript(ScriptEntity script);
-}
-
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/ScriptWithEvents.java b/app/src/main/java/com/auto/clicker/autoclicker/room/ScriptWithEvents.java
deleted file mode 100644
index f6fd9e7..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/room/ScriptWithEvents.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.auto.clicker.autoclicker.room;
-
-import androidx.room.Embedded;
-import androidx.room.Relation;
-
-import java.util.List;
-
-public class ScriptWithEvents {
- @Embedded
- public ScriptEntity script;
-
- @Relation(parentColumn = "scriptId", entityColumn = "scriptOwnerId")
- public List pointEvents;
-
- @Relation(parentColumn = "scriptId", entityColumn = "scriptOwnerId")
- public List slideEvents;
-}
-
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/SlideEventEntity.java b/app/src/main/java/com/auto/clicker/autoclicker/room/SlideEventEntity.java
deleted file mode 100644
index c624a54..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/room/SlideEventEntity.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.auto.clicker.autoclicker.room;
-
-import androidx.room.Entity;
-import androidx.room.ForeignKey;
-import androidx.room.Index;
-import androidx.room.PrimaryKey;
-
-@Entity(tableName = "slide_events",
- foreignKeys = @ForeignKey(entity = ScriptEntity.class,
- parentColumns = "scriptId",
- childColumns = "scriptOwnerId",
- onDelete = ForeignKey.CASCADE),
- indices = {@Index("scriptOwnerId")})
-public class SlideEventEntity {
- @PrimaryKey(autoGenerate = true)
- public long slideId;
-
- public int startX;
- public int startY;
- public int endX;
- public int endY;
-
- public int order;
- public long scriptOwnerId;
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/SlideEventEntityDao.java b/app/src/main/java/com/auto/clicker/autoclicker/room/SlideEventEntityDao.java
deleted file mode 100644
index 2f48edf..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/room/SlideEventEntityDao.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.auto.clicker.autoclicker.room;
-
-import androidx.room.Dao;
-
-@Dao
-public interface SlideEventEntityDao {
-}
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/SolutionWithEventsAndPoints.java b/app/src/main/java/com/auto/clicker/autoclicker/room/SolutionWithEventsAndPoints.java
new file mode 100644
index 0000000..a73f03f
--- /dev/null
+++ b/app/src/main/java/com/auto/clicker/autoclicker/room/SolutionWithEventsAndPoints.java
@@ -0,0 +1,50 @@
+package com.auto.clicker.autoclicker.room;
+
+import androidx.room.Embedded;
+import androidx.room.Relation;
+
+import com.auto.clicker.autoclicker.room.entity.EventEntity;
+import com.auto.clicker.autoclicker.room.entity.TouchPoint;
+import com.auto.clicker.autoclicker.room.entity.Solution;
+
+import java.util.List;
+
+// 这个 POJO 用于表示一个方案,以及该方案下的所有事件及其关联的坐标点
+public class SolutionWithEventsAndPoints {
+ @Embedded
+ public Solution solution;
+
+ @Relation(
+ parentColumn = "solutionId",
+ entityColumn = "solution_id",
+ entity = EventEntity.class
+ )
+ public List events; // 注意这里我们用 EventWithPoints
+
+ // 内部类,用于表示一个事件以及它关联的起点和终点
+ public static class EventWithPoints {
+ @Embedded
+ public EventEntity eventEntity;
+
+ @Relation(
+ parentColumn = "click_point_id",
+ entityColumn = "pointId",
+ entity = TouchPoint.class
+ )
+ public TouchPoint clickTouchPoint; // 单击事件的点
+
+ @Relation(
+ parentColumn = "slide_start_point_id",
+ entityColumn = "pointId",
+ entity = TouchPoint.class
+ )
+ public TouchPoint slideStartTouchPoint; // 滑动事件的起点
+
+ @Relation(
+ parentColumn = "slide_end_point_id",
+ entityColumn = "pointId",
+ entity = TouchPoint.class
+ )
+ public TouchPoint slideEndTouchPoint; // 滑动事件的终点
+ }
+}
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
new file mode 100644
index 0000000..e879ffa
--- /dev/null
+++ b/app/src/main/java/com/auto/clicker/autoclicker/room/dao/EventEntityDao.java
@@ -0,0 +1,23 @@
+package com.auto.clicker.autoclicker.room.dao;
+
+import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.Query;
+
+import com.auto.clicker.autoclicker.room.entity.EventEntity;
+
+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);
+}
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
new file mode 100644
index 0000000..a898205
--- /dev/null
+++ b/app/src/main/java/com/auto/clicker/autoclicker/room/dao/SolutionDao.java
@@ -0,0 +1,44 @@
+package com.auto.clicker.autoclicker.room.dao;
+
+import androidx.room.Dao;
+import androidx.room.Insert;
+import androidx.room.Delete;
+import androidx.room.Query;
+import androidx.room.Transaction;
+import androidx.room.Update;
+
+import com.auto.clicker.autoclicker.room.SolutionWithEventsAndPoints;
+import com.auto.clicker.autoclicker.room.entity.Solution;
+
+import java.util.List;
+
+@Dao
+public interface SolutionDao {
+ @Insert
+ long insertSolution(Solution solution); // 返回新插入的 solutionId
+
+ @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); // 返回更新的行数
+
+ // 在 SolutionDao 中添加
+ @Transaction // 表示这是一个事务操作,确保数据一致性
+ @Query("SELECT * FROM solutions WHERE solutionId = :solutionId LIMIT 1")
+ SolutionWithEventsAndPoints getSolutionWithEventsAndPoints(long solutionId);
+
+ // 也可以获取所有方案及其事件
+ @Transaction
+ @Query("SELECT * FROM solutions")
+ List getAllSolutionsWithEventsAndPoints();
+}
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
new file mode 100644
index 0000000..f16fc3a
--- /dev/null
+++ b/app/src/main/java/com/auto/clicker/autoclicker/room/dao/TouchPointDao.java
@@ -0,0 +1,24 @@
+package com.auto.clicker.autoclicker.room.dao;
+
+import androidx.room.Dao;
+import androidx.room.Insert;
+import androidx.room.Query;
+import androidx.room.Update;
+import androidx.room.Delete;
+
+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);
+}
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/entity/EventEntity.java b/app/src/main/java/com/auto/clicker/autoclicker/room/entity/EventEntity.java
new file mode 100644
index 0000000..a8cc319
--- /dev/null
+++ b/app/src/main/java/com/auto/clicker/autoclicker/room/entity/EventEntity.java
@@ -0,0 +1,129 @@
+package com.auto.clicker.autoclicker.room.entity;
+
+import static androidx.room.ForeignKey.CASCADE;
+
+import androidx.room.ColumnInfo;
+import androidx.room.Entity;
+import androidx.room.ForeignKey;
+import androidx.room.PrimaryKey;
+
+@Entity(tableName = "events",
+ foreignKeys = {
+ @ForeignKey(entity = Solution.class,
+ parentColumns = "solutionId",
+ childColumns = "solution_id",
+ onDelete = CASCADE),
+ @ForeignKey(entity = TouchPoint.class,
+ parentColumns = "pointId",
+ childColumns = "click_point_id",
+ onDelete = CASCADE),
+ @ForeignKey(entity = TouchPoint.class,
+ parentColumns = "pointId",
+ childColumns = "slide_start_point_id",
+ onDelete = CASCADE),
+ @ForeignKey(entity = TouchPoint.class,
+ parentColumns = "pointId",
+ childColumns = "slide_end_point_id",
+ onDelete = CASCADE)
+ })
+public class EventEntity {
+ @PrimaryKey(autoGenerate = true)
+ public long eventId;
+
+ @ColumnInfo(name = "solution_id")
+ public long solutionId;
+
+ @ColumnInfo(name = "event_type")
+ public String eventType;
+
+ @ColumnInfo(name = "order_in_solution")
+ public int orderInSolution;
+
+ @ColumnInfo(name = "click_point_id")
+ public Long clickPointId;
+
+ @ColumnInfo(name = "slide_start_point_id")
+ public Long slideStartPointId;
+
+ @ColumnInfo(name = "slide_end_point_id")
+ public Long slideEndPointId;
+
+ @ColumnInfo(name = "duration")
+ public long duration;
+
+ public EventEntity(long solutionId, String eventType, int orderInSolution,
+ Long clickPointId, Long slideStartPointId, Long slideEndPointId, long duration) {
+ this.solutionId = solutionId;
+ this.eventType = eventType;
+ this.orderInSolution = orderInSolution;
+ this.clickPointId = clickPointId;
+ this.slideStartPointId = slideStartPointId;
+ this.slideEndPointId = slideEndPointId;
+ this.duration = duration;
+ }
+
+ public long getEventId() {
+ return eventId;
+ }
+
+ public void setEventId(long eventId) {
+ this.eventId = eventId;
+ }
+
+ public long getSolutionId() {
+ return solutionId;
+ }
+
+ public void setSolutionId(long solutionId) {
+ this.solutionId = solutionId;
+ }
+
+ public String getEventType() {
+ return eventType;
+ }
+
+ public void setEventType(String eventType) {
+ this.eventType = eventType;
+ }
+
+ public int getOrderInSolution() {
+ return orderInSolution;
+ }
+
+ public void setOrderInSolution(int orderInSolution) {
+ this.orderInSolution = orderInSolution;
+ }
+
+ public Long getClickPointId() {
+ return clickPointId;
+ }
+
+ public void setClickPointId(Long clickPointId) {
+ this.clickPointId = clickPointId;
+ }
+
+ public Long getSlideStartPointId() {
+ return slideStartPointId;
+ }
+
+ public void setSlideStartPointId(Long slideStartPointId) {
+ this.slideStartPointId = slideStartPointId;
+ }
+
+ public Long getSlideEndPointId() {
+ return slideEndPointId;
+ }
+
+ public void setSlideEndPointId(Long slideEndPointId) {
+ this.slideEndPointId = slideEndPointId;
+ }
+
+ public long getDuration() {
+ return duration;
+ }
+
+ public void setDuration(long duration) {
+ this.duration = duration;
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/entity/Solution.java b/app/src/main/java/com/auto/clicker/autoclicker/room/entity/Solution.java
new file mode 100644
index 0000000..a09fb4e
--- /dev/null
+++ b/app/src/main/java/com/auto/clicker/autoclicker/room/entity/Solution.java
@@ -0,0 +1,27 @@
+package com.auto.clicker.autoclicker.room.entity;
+
+import androidx.room.ColumnInfo;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+import androidx.room.ColumnInfo;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+@Entity(tableName = "solutions")
+public class Solution {
+ @PrimaryKey(autoGenerate = true)
+ public long solutionId;
+
+ @ColumnInfo(name = "solution_name")
+ public String solutionName;
+
+ public Solution(String solutionName) {
+ this.solutionName = solutionName;
+ }
+
+ public long getSolutionId() { return solutionId; }
+ public void setSolutionId(long solutionId) { this.solutionId = solutionId; }
+ public String getSolutionName() { return solutionName; }
+ public void setSolutionName(String solutionName) { this.solutionName = solutionName; }
+}
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/room/entity/TouchPoint.java b/app/src/main/java/com/auto/clicker/autoclicker/room/entity/TouchPoint.java
new file mode 100644
index 0000000..4d66646
--- /dev/null
+++ b/app/src/main/java/com/auto/clicker/autoclicker/room/entity/TouchPoint.java
@@ -0,0 +1,31 @@
+package com.auto.clicker.autoclicker.room.entity;
+
+import androidx.room.ColumnInfo;
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+
+
+@Entity(tableName = "touchPoints")
+public class TouchPoint {
+ @PrimaryKey(autoGenerate = true)
+ public long pointId;
+
+ @ColumnInfo(name = "x_coordinate")
+ public int x;
+
+ @ColumnInfo(name = "y_coordinate")
+ public int y;
+
+ public TouchPoint(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public long getPointId() { return pointId; }
+ public void setPointId(long pointId) { this.pointId = pointId; }
+ public int getX() { return x; }
+ public void setX(int x) { this.x = x; }
+ public int getY() { return y; }
+ public void setY(int y) { this.y = y; }
+}
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
new file mode 100644
index 0000000..316f595
--- /dev/null
+++ b/app/src/main/java/com/auto/clicker/autoclicker/room/repository/EventRepository.java
@@ -0,0 +1,169 @@
+package com.auto.clicker.autoclicker.room.repository;
+
+import android.content.Context;
+
+import com.auto.clicker.autoclicker.data.Event;
+import com.auto.clicker.autoclicker.data.EventWrapper;
+import com.auto.clicker.autoclicker.data.PointEvent;
+import com.auto.clicker.autoclicker.data.SlideEvent;
+import com.auto.clicker.autoclicker.room.AppDatabase;
+import com.auto.clicker.autoclicker.room.SolutionWithEventsAndPoints;
+import com.auto.clicker.autoclicker.room.dao.EventEntityDao;
+import com.auto.clicker.autoclicker.room.dao.TouchPointDao;
+import com.auto.clicker.autoclicker.room.dao.SolutionDao;
+import com.auto.clicker.autoclicker.room.entity.EventEntity;
+import com.auto.clicker.autoclicker.room.entity.TouchPoint;
+import com.auto.clicker.autoclicker.room.entity.Solution;
+
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import android.content.Context;
+
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import android.util.Log; // Add Log import for debugging
+
+public class EventRepository {
+ private final SolutionDao solutionDao;
+ private final TouchPointDao touchPointDao; // Renamed from PointDao
+ private final EventEntityDao eventEntityDao;
+ private final ExecutorService databaseWriteExecutor;
+
+ public EventRepository(Context context) {
+ AppDatabase db = AppDatabase.getInstance(context); // Updated to getInstance
+ this.solutionDao = db.solutionDao();
+ this.touchPointDao = db.pointDao(); // Assuming db.pointDao() returns TouchPointDao now
+ this.eventEntityDao = db.eventEntityDao();
+ this.databaseWriteExecutor = Executors.newFixedThreadPool(2);
+ }
+
+ // --- 插入操作 ---
+ public void insertSolutionWithEvents(Solution solution, List runtimeEvents, RepositoryCallback callback) {
+ databaseWriteExecutor.execute(() -> {
+ long solutionId = -1; // Initialize solutionId outside try-catch for broader scope
+ try {
+ // 1. 插入 Solution
+ solutionId = solutionDao.insertSolution(solution);
+ if (solutionId == -1) {
+ throw new RuntimeException("Failed to insert solution.");
+ }
+
+ // 2. 遍历 runtimeEvents,插入 TouchPoint 和 EventEntity
+ for (EventWrapper wrapper : runtimeEvents) {
+ Event event = wrapper.getEvent();
+ int order = wrapper.getOrder(); // Using order from EventWrapper
+
+ long eventEntityId = -1; // To store the result of event entity insertion
+
+ if (wrapper.getType() == EventWrapper.EventType.POINT && event instanceof PointEvent) {
+ PointEvent pointEvent = (PointEvent) event;
+ TouchPoint touchPoint = new TouchPoint(pointEvent.getX(), pointEvent.getY());
+ long pointId = touchPointDao.insertPoint(touchPoint);
+ if (pointId == -1)
+ throw new RuntimeException("Failed to insert touch point for PointEvent.");
+
+ // 调用 EventEntity 的唯一构造函数,将滑动相关字段设为 null 或默认值
+ EventEntity eventEntity = new EventEntity(
+ (int) solutionId, // Ensure type compatibility if solutionId is long
+ wrapper.getType().name(),
+ order,
+ pointId, // clickPointId
+ null, // slideStartPointId (null for point event)
+ null, // slideEndPointId (null for point event)
+ 0 // duration (0 for point event)
+ );
+ eventEntityId = eventEntityDao.insertEventEntity(eventEntity);
+ if (eventEntityId == -1)
+ throw new RuntimeException("Failed to insert EventEntity for PointEvent.");
+
+ } else if (wrapper.getType() == EventWrapper.EventType.SLIDE && event instanceof SlideEvent) {
+ SlideEvent slideEvent = (SlideEvent) event;
+ TouchPoint startTouchPoint = new TouchPoint(slideEvent.getStartPoint().getX(), slideEvent.getStartPoint().getY());
+ long startPointId = touchPointDao.insertPoint(startTouchPoint);
+ if (startPointId == -1)
+ throw new RuntimeException("Failed to insert start touch point for SlideEvent.");
+
+ TouchPoint endTouchPoint = new TouchPoint(slideEvent.getEndPoint().getX(), slideEvent.getEndPoint().getY());
+ long endPointId = touchPointDao.insertPoint(endTouchPoint);
+ if (endPointId == -1)
+ throw new RuntimeException("Failed to insert end touch point for SlideEvent.");
+
+ // 调用 EventEntity 的唯一构造函数,将点击相关字段设为 null
+ EventEntity eventEntity = new EventEntity(
+ (int) solutionId,
+ wrapper.getType().name(),
+ order,
+ null,
+ startPointId,
+ endPointId,
+ 0
+ );
+ eventEntityId = eventEntityDao.insertEventEntity(eventEntity);
+ if (eventEntityId == -1)
+ throw new RuntimeException("Failed to insert EventEntity for SlideEvent.");
+ }
+ }
+ if (callback != null) {
+ // Post the result back to the main thread if needed for UI updates
+ // For simplicity, directly calling callback here; in a real app, use Handler or LiveData
+ callback.onComplete(solutionId);
+ }
+ } catch (Exception e) {
+ Log.e("EventRepository", "Error inserting solution with events: " + e.getMessage(), e);
+ // Consider rolling back the transaction if any part fails
+ if (callback != null) {
+ callback.onError(e);
+ }
+ }
+ });
+ }
+
+ // --- 查询操作 ---
+ public void getAllSolutions(RepositoryCallback> callback) {
+ databaseWriteExecutor.execute(() -> {
+ try {
+ List solutions = solutionDao.getAllSolutions();
+ if (callback != null) callback.onComplete(solutions);
+ } catch (Exception e) {
+ Log.e("EventRepository", "Error getting all solutions: " + e.getMessage(), e);
+ if (callback != null) callback.onError(e);
+ }
+ });
+ }
+
+ public void getSolutionWithEventsAndPoints(long solutionId, RepositoryCallback callback) {
+ databaseWriteExecutor.execute(() -> {
+ try {
+ SolutionWithEventsAndPoints data = solutionDao.getSolutionWithEventsAndPoints(solutionId);
+ if (callback != null) callback.onComplete(data);
+ } catch (Exception e) {
+ Log.e("EventRepository", "Error getting solution with events and points: " + e.getMessage(), e);
+ if (callback != null) callback.onError(e);
+ }
+ });
+ }
+
+ // --- 删除操作 ---
+ public void deleteSolution(Solution solution, RepositoryCallback callback) {
+ databaseWriteExecutor.execute(() -> {
+ try {
+ int rowsAffected = solutionDao.deleteSolution(solution);
+ if (callback != null) callback.onComplete(rowsAffected);
+ } catch (Exception e) {
+ Log.e("EventRepository", "Error deleting solution: " + e.getMessage(), e);
+ if (callback != null) callback.onError(e);
+ }
+ });
+ }
+
+ // 假设的回调接口,可以根据需要自定义
+ public interface RepositoryCallback {
+ void onComplete(T result);
+
+ void onError(Exception e);
+ }
+}
\ No newline at end of file
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 409df0e..eb2b247 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
@@ -239,7 +239,7 @@ public class AutoClickService extends AccessibilityService {
}
private void flashTouchFeedback(int index) {
- Intent intent = new Intent("com.auto.autoclicker.FLASH_TOUCH_POINT");
+ Intent intent = new Intent("com.auto.clicker.autoclicker.FLASH_TOUCH_POINT");
intent.putExtra("index", index);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
@@ -257,7 +257,7 @@ public class AutoClickService extends AccessibilityService {
super.onDestroy();
instance = null;
stopClicking();
- Intent intent = new Intent("com.auto.autoclicker.SERVICE_DESTROYED");
+ Intent intent = new Intent("com.auto.clicker.autoclicker.SERVICE_DESTROYED");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
logDebug("无障碍服务已销毁");
}
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/ui/activity/floating/TransparentFloatingActivity.java b/app/src/main/java/com/auto/clicker/autoclicker/ui/activity/floating/TransparentFloatingActivity.java
deleted file mode 100644
index 3ea9ef9..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/ui/activity/floating/TransparentFloatingActivity.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package com.auto.clicker.autoclicker.ui.activity.floating; // 替换为你的实际包名
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.LayoutInflater; // 新增
-import android.view.View;
-import android.view.WindowManager; // 新增,用于设置 Window 属性
-import android.widget.ImageView;
-
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity; // 继续使用 AppCompatActivity
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
-import androidx.viewpager2.widget.ViewPager2; // 新增
-
-import com.auto.clicker.autoclicker.R;
-import com.auto.clicker.autoclicker.ui.adapter.floating.TabPagerAdapter;
-import com.auto.clicker.autoclicker.ui.fragment.floating.LoadScriptFragment;
-import com.auto.clicker.autoclicker.ui.fragment.floating.SaveScriptFragment;
-import com.google.android.material.tabs.TabLayout; // 新增
-import com.google.android.material.tabs.TabLayoutMediator; // 新增
-
-
-public class TransparentFloatingActivity extends AppCompatActivity {
-
- private static final String TAG = "TransparentFloatingAct";
- public static final String ACTION_CLOSE_FLOATING_TAB_DIALOG = "com.auto.autoclicker.CLOSE_FLOATING_TAB_DIALOG";
-
- // 不再需要 FloatingTabDialogManager 实例,直接在这里处理 UI
- private View dialogContentView; // 承载整个弹窗内容的 View
-
- // 接收关闭指令的广播接收器
- private BroadcastReceiver closeReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (ACTION_CLOSE_FLOATING_TAB_DIALOG.equals(intent.getAction())) {
- Log.d(TAG, "收到关闭浮动标签页弹窗的广播");
- finish(); // 关闭自身 Activity
- }
- }
- };
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // 设置 Activity 的窗口属性,使其看起来像一个对话框
- // 注意:这里的设置可能与主题中的部分重复,但可以作为额外的控制
- WindowManager.LayoutParams params = getWindow().getAttributes();
- params.gravity = android.view.Gravity.CENTER; // 确保居中
- params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; // 移除背景变暗(如果主题没有完全实现)
- params.width = WindowManager.LayoutParams.WRAP_CONTENT; // 根据内容调整宽度
- params.height = WindowManager.LayoutParams.WRAP_CONTENT; // 根据内容调整高度
- getWindow().setAttributes(params);
- getWindow().setBackgroundDrawableResource(android.R.color.transparent); // 确保背景透明
-
- // 加载你的弹窗布局
- setContentView(R.layout.floating_tab_dialog);
- dialogContentView = findViewById(android.R.id.content); // 获取根视图(如果你的布局没有特定ID)
-
- Log.d(TAG, "TransparentFloatingActivity onCreate");
-
- // 初始化 TabLayout 和 ViewPager2
- TabLayout tabLayout = findViewById(R.id.tab_layout);
- ViewPager2 viewPager = findViewById(R.id.view_pager);
-
- TabPagerAdapter pagerAdapter = new TabPagerAdapter(this); // 传入当前的 Activity 作为 FragmentActivity
- pagerAdapter.addFragment(new SaveScriptFragment(), "选项卡一");
- pagerAdapter.addFragment(new LoadScriptFragment(), "选项卡二");
- // 添加更多 Fragment...
-
- viewPager.setAdapter(pagerAdapter);
-
- new TabLayoutMediator(tabLayout, viewPager,
- (tab, position) -> tab.setText(pagerAdapter.getPageTitle(position))
- ).attach();
-
- // 假设你在 floating_tab_dialog.xml 中有一个关闭按钮,ID 为 close_dialog_button
- ImageView closeDialogButton = findViewById(R.id.close_dialog_button);
- if (closeDialogButton != null) {
- closeDialogButton.setOnClickListener(v -> {
- // 点击关闭按钮时,直接结束这个 Activity
- finish();
- });
- }
-
-
- // 注册广播接收器
- LocalBroadcastManager.getInstance(this).registerReceiver(closeReceiver,
- new IntentFilter(ACTION_CLOSE_FLOATING_TAB_DIALOG));
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- Log.d(TAG, "TransparentFloatingActivity onDestroy");
- // 注销广播接收器
- LocalBroadcastManager.getInstance(this).unregisterReceiver(closeReceiver);
- }
-
- // 移除这个方法,因为现在 Activity 自己会关闭
- // public static void sendCloseBroadcast(Context context) {
- // Intent intent = new Intent(ACTION_CLOSE_FLOATING_TAB_DIALOG);
- // LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
- // }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/dialog/ViewPagerAdapter.java b/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/dialog/ViewPagerAdapter.java
deleted file mode 100644
index 6a72e17..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/dialog/ViewPagerAdapter.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.auto.clicker.autoclicker.ui.adapter.dialog;
-
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.recyclerview.widget.RecyclerView;
-
-import java.util.List;
-
-public class ViewPagerAdapter extends RecyclerView.Adapter {
- private final List views;
-
- public ViewPagerAdapter(List views) {
- this.views = views;
- }
-
- @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return new ViewHolder(views.get(viewType));
- }
-
- @Override public void onBindViewHolder(ViewHolder holder, int position) {}
-
- @Override public int getItemCount() {
- return views.size();
- }
-
- @Override public int getItemViewType(int position) {
- return position;
- }
-
- static class ViewHolder extends RecyclerView.ViewHolder {
- public ViewHolder(View itemView) { super(itemView); }
- }
-}
-
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/floating/TabPagerAdapter.java b/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/floating/TabPagerAdapter.java
deleted file mode 100644
index ca7f354..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/floating/TabPagerAdapter.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.auto.clicker.autoclicker.ui.adapter.floating;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-import androidx.viewpager2.adapter.FragmentStateAdapter;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class TabPagerAdapter extends FragmentStateAdapter {
-
- private final List fragmentList = new ArrayList<>();
- private final List fragmentTitleList = new ArrayList<>();
-
- public TabPagerAdapter(@NonNull FragmentActivity fragmentActivity) { // 保持接收 FragmentActivity
- super(fragmentActivity);
- }
-
- public void addFragment(Fragment fragment, String title) {
- fragmentList.add(fragment);
- fragmentTitleList.add(title);
- }
-
- @NonNull
- @Override
- public Fragment createFragment(int position) {
- return fragmentList.get(position);
- }
-
- @Override
- public int getItemCount() {
- return fragmentList.size();
- }
-
- public CharSequence getPageTitle(int position) {
- return fragmentTitleList.get(position);
- }
-}
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/script/ScriptListAdapter.java b/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/script/ScriptListAdapter.java
index 2caf32c..bf92cd8 100644
--- a/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/script/ScriptListAdapter.java
+++ b/app/src/main/java/com/auto/clicker/autoclicker/ui/adapter/script/ScriptListAdapter.java
@@ -3,26 +3,20 @@ package com.auto.clicker.autoclicker.ui.adapter.script;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.auto.clicker.autoclicker.R;
-import com.auto.clicker.autoclicker.dialog.LoadScriptView;
-import com.auto.clicker.autoclicker.room.ScriptEntity;
+import com.auto.clicker.autoclicker.room.entity.Solution;
import java.util.List;
public class ScriptListAdapter extends RecyclerView.Adapter {
- private List scripts;
- private LoadScriptView.OnScriptClickListener listener;
+ private List solutionList;
-
- public ScriptListAdapter(List scripts, LoadScriptView.OnScriptClickListener listener) {
- this.scripts = scripts;
- this.listener = listener;
+ public ScriptListAdapter(List solutionList) {
+ this.solutionList = solutionList;
}
@NonNull
@@ -40,7 +34,7 @@ public class ScriptListAdapter extends RecyclerView.Adapter {
+
+ private List solutionList;
+ private OnSolutionClickListener listener;
+
+ // 定义接口用于处理点击事件
+ public interface OnSolutionClickListener {
+ void onSolutionClick(Solution solution);
+ }
+
+ public SolutionAdapter(List solutionList, OnSolutionClickListener listener) {
+ this.solutionList = solutionList;
+ this.listener = listener;
+ }
+
+ @NonNull
+ @Override
+ public SolutionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(android.R.layout.simple_list_item_1, parent, false); // 可以自定义更复杂的item布局
+ return new SolutionViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull SolutionViewHolder holder, int position) {
+ Solution solution = solutionList.get(position);
+ holder.solutionNameTextView.setText(solution.getSolutionName());
+
+ holder.itemView.setOnClickListener(v -> {
+ if (listener != null) {
+ listener.onSolutionClick(solution);
+ }
+ });
+ }
+
+ @Override
+ public int getItemCount() {
+ return solutionList.size();
+ }
+
+ public void setSolutions(List newSolutions) {
+ this.solutionList.clear();
+ if (newSolutions != null) {
+ this.solutionList.addAll(newSolutions);
+ }
+ notifyDataSetChanged();
+ }
+
+ static class SolutionViewHolder extends RecyclerView.ViewHolder {
+ TextView solutionNameTextView;
+
+ SolutionViewHolder(View itemView) {
+ super(itemView);
+ // simple_list_item_1 只有一个 TextView
+ solutionNameTextView = itemView.findViewById(android.R.id.text1);
+ }
+ }
+}
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/util/FloatingTabDialogManager.java b/app/src/main/java/com/auto/clicker/autoclicker/util/FloatingTabDialogManager.java
index e4256ad..9448247 100644
--- a/app/src/main/java/com/auto/clicker/autoclicker/util/FloatingTabDialogManager.java
+++ b/app/src/main/java/com/auto/clicker/autoclicker/util/FloatingTabDialogManager.java
@@ -3,126 +3,211 @@ package com.auto.clicker.autoclicker.util;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
+import android.widget.EditText;
import android.widget.LinearLayout;
+import android.widget.Toast;
+
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
import com.auto.clicker.autoclicker.R;
+import com.auto.clicker.autoclicker.room.entity.Solution;
+import com.auto.clicker.autoclicker.room.repository.EventRepository;
+import com.auto.clicker.autoclicker.ui.floating.SolutionAdapter;
+import com.auto.clicker.autoclicker.view.FloatingViewManager;
+
+import java.util.ArrayList;
+import java.util.List;
public class FloatingTabDialogManager {
private static final String TAG = "FloatingTabDialogMgr";
- private final Context originalContext; // 保存原始的 Service Context
+ private final Context context;
private final WindowManager windowManager;
private LinearLayout floatingDialogView;
private WindowManager.LayoutParams floatingDialogParams;
- private Button tabOneButton;
- private Button tabTwoButton;
- private FrameLayout contentFrame;
- private View pageOneView;
- private View pageTwoView;
+ private Button saveTab;
+ private Button loadTab;
+ private View savePage;
+ private View loadPage;
+
+ private FloatingViewManager floatingViewManager;
+
+ private EditText inputName;
+ private Button saveButton;
+ private Button closeButton;
+
+ private RecyclerView loadRecyclerview;
+ private SolutionAdapter solutionsAdapter;
+ private List solutionList = new ArrayList<>();
public FloatingTabDialogManager(Context context) {
- this.originalContext = context; // 保存原始 Context
+ this.context = context;
this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
+ public void setFloatingViewManager(FloatingViewManager manager) {
+ this.floatingViewManager = manager;
+ }
+
public void showFloatingTabDialog() {
if (floatingDialogView != null) {
- removeFloatingTabDialog(); // 如果已经显示,先移除
+ removeFloatingTabDialog();
}
- // --- 关键修改:使用 ContextThemeWrapper 包裹 Service Context ---
- Context themedContext = new ContextThemeWrapper(originalContext, R.style.Theme_AutoClicker);
- // 或者如果你想用 Material3 的默认主题,但你的 Theme_AutoClicker 已经继承了 Material3,那用它就行
- // Context themedContext = new ContextThemeWrapper(originalContext, R.style.Theme_Material3_DayNight_NoActionBar); // 也可以直接用这个
+ Context themedContext = new ContextThemeWrapper(context, R.style.Theme_AutoClicker);
floatingDialogView = (LinearLayout) LayoutInflater.from(themedContext).inflate(R.layout.floating_tab_dialog, null);
- // --- 关键修改结束 ---
+ floatingDialogParams = createFloatingDialogParams(); // 创建悬浮窗参数
- floatingDialogParams = createFloatingDialogParams();
+ saveTab = floatingDialogView.findViewById(R.id.tab_one_button);
+ loadTab = floatingDialogView.findViewById(R.id.tab_two_button);
+ savePage = floatingDialogView.findViewById(R.id.page_one_view);
+ loadPage = floatingDialogView.findViewById(R.id.page_two_view);
- // 获取视图组件
- tabOneButton = floatingDialogView.findViewById(R.id.tab_one_button);
- tabTwoButton = floatingDialogView.findViewById(R.id.tab_two_button);
- contentFrame = floatingDialogView.findViewById(R.id.content_frame);
- pageOneView = floatingDialogView.findViewById(R.id.page_one_view);
- pageTwoView = floatingDialogView.findViewById(R.id.page_two_view);
- ImageView closeDialogButton = floatingDialogView.findViewById(R.id.close_dialog_button);
+ saveTab.setOnClickListener(v -> showPage(0));
+ loadTab.setOnClickListener(v -> showPage(1));
- // 设置标签按钮的点击事件
- tabOneButton.setOnClickListener(v -> showPage(0));
- tabTwoButton.setOnClickListener(v -> showPage(1));
+ inputName = savePage.findViewById(R.id.script_name_input);
+ saveButton = savePage.findViewById(R.id.save);
+ closeButton = savePage.findViewById(R.id.close);
- // 设置关闭按钮的点击事件
- if (closeDialogButton != null) {
- closeDialogButton.setOnClickListener(v -> {
- removeFloatingTabDialog(); // 点击关闭按钮时,移除弹窗
- });
- }
+ saveButton.setOnClickListener(v -> {
+ String solutionName = inputName.getText().toString().trim();
- // 默认显示第一个页面
- showPage(0);
+ if (floatingViewManager != null) {
+ floatingViewManager.saveCurrentEventsAsSolution(solutionName, new EventRepository.RepositoryCallback() {
+ @Override
+ public void onComplete(Long solutionId) {
+ if (solutionId != -1) {
+ Toast.makeText(context, "方案 '" + solutionName + "' 保存成功!", Toast.LENGTH_SHORT).show();
+ removeFloatingTabDialog();
+ } else {
+ Toast.makeText(context, "保存方案失败。", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public void onError(Exception e) {
+ Log.e(TAG, "保存方案失败: " + e.getMessage(), e);
+ Toast.makeText(context, "保存方案失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
+ }
+ });
+ // ✅ 只在验证通过时才显示
+ Toast.makeText(context, "正在保存方案...", Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ closeButton.setOnClickListener(v -> removeFloatingTabDialog());
+
+ loadRecyclerview = loadPage.findViewById(R.id.script_list);
+ loadRecyclerview.setLayoutManager(new LinearLayoutManager(context));
+
+ solutionsAdapter = new SolutionAdapter(solutionList, solution -> {
+ if (floatingViewManager != null) {
+ floatingViewManager.loadSolution(solution.solutionId);
+ Toast.makeText(context, "正在加载方案: " + solution.getSolutionName(), Toast.LENGTH_SHORT).show();
+ } else {
+ Log.e(TAG, "FloatingViewManager 未设置!无法加载方案。");
+ Toast.makeText(context, "加载功能不可用,请联系开发者。", Toast.LENGTH_SHORT).show();
+ }
+ removeFloatingTabDialog();
+ });
+ loadRecyclerview.setAdapter(solutionsAdapter);
+
+ showPage(0); // 默认显示保存页面
+
+ loadSolutionsForList(); // 加载方案列表,以便切换到加载页面时可以直接显示
try {
windowManager.addView(floatingDialogView, floatingDialogParams);
Log.d(TAG, "浮动标签页弹窗已显示");
} catch (WindowManager.BadTokenException e) {
Log.e(TAG, "无法添加浮动标签页弹窗,可能是权限问题或上下文无效", e);
+ Toast.makeText(context, "显示弹窗失败,请检查权限。", Toast.LENGTH_SHORT).show();
} catch (SecurityException e) {
Log.e(TAG, "需要悬浮窗权限才能显示浮动弹窗", e);
- // 引导用户去开启权限,如果你在 FloatingViewManager 中已经处理了,这里可以省略
- // Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
- // Uri.parse("package:" + context.getPackageName()));
- // intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- // context.startActivity(intent);
+ Toast.makeText(context, "请授予悬浮窗权限以便显示。", Toast.LENGTH_SHORT).show();
}
}
private void showPage(int pageIndex) {
- // 确保所有视图都已正确加载(例如,通过 inflated 后的 findViewById)
- if (pageOneView == null || pageTwoView == null) {
+ if (savePage == null || loadPage == null) {
Log.e(TAG, "页面视图未初始化!");
return;
}
// 隐藏所有页面
- pageOneView.setVisibility(View.GONE);
- pageTwoView.setVisibility(View.GONE);
+ savePage.setVisibility(View.GONE);
+ loadPage.setVisibility(View.GONE);
- // 重置所有标签按钮的颜色/背景(如果需要视觉反馈)
- // 注意:这里使用 getContext().getResources().getColor() 是在 themedContext 的上下文中获取颜色
- // 如果你的颜色定义在 themes.xml 或 colors.xml 中,并且依赖于主题属性,那么需要确保主题是正确的
- tabOneButton.setTextColor(originalContext.getResources().getColor(android.R.color.darker_gray)); // 用 originalContext 或 themedContext
- tabTwoButton.setTextColor(originalContext.getResources().getColor(android.R.color.darker_gray)); // 最好用 themedContext
+ // 重置Tab按钮颜色
+ saveTab.setTextColor(context.getResources().getColor(android.R.color.darker_gray));
+ loadTab.setTextColor(context.getResources().getColor(android.R.color.darker_gray));
- // 显示选定页面并更新标签样式
switch (pageIndex) {
- case 0:
- pageOneView.setVisibility(View.VISIBLE);
- tabOneButton.setTextColor(originalContext.getResources().getColor(android.R.color.black)); // 选中颜色
+ case 0: // 保存页面
+ savePage.setVisibility(View.VISIBLE);
+ saveTab.setTextColor(context.getResources().getColor(android.R.color.black));
+ // 在显示保存页面时尝试显示键盘
+ showKeyboard();
break;
- case 1:
- pageTwoView.setVisibility(View.VISIBLE);
- tabTwoButton.setTextColor(originalContext.getResources().getColor(android.R.color.black)); // 选中颜色
+ case 1: // 加载页面
+ loadPage.setVisibility(View.VISIBLE);
+ loadTab.setTextColor(context.getResources().getColor(android.R.color.black));
+ loadSolutionsForList();
break;
- // 添加更多页面
}
}
+ private void loadSolutionsForList() {
+ if (floatingViewManager == null) {
+ Log.e(TAG, "FloatingViewManager 未设置,无法加载方案列表。");
+ // 确保UI操作在主线程
+ new Handler(Looper.getMainLooper()).post(() ->
+ Toast.makeText(context, "加载方案列表功能不可用。", Toast.LENGTH_SHORT).show()
+ );
+ return;
+ }
+ floatingViewManager.getAllSolutions(new EventRepository.RepositoryCallback>() {
+ @Override
+ public void onComplete(List solutions) {
+ // 将 UI 更新操作(包括更新适配器和显示Toast)切换到主线程
+ new Handler(Looper.getMainLooper()).post(() -> {
+ solutionsAdapter.setSolutions(solutions);
+ if (solutions.isEmpty()) {
+ Toast.makeText(context, "没有可加载的方案。", Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ @Override
+ public void onError(Exception e) {
+ // 将 UI 更新操作(显示Toast)切换到主线程
+ new Handler(Looper.getMainLooper()).post(() -> {
+ Log.e(TAG, "加载方案列表失败: " + e.getMessage(), e);
+ Toast.makeText(context, "加载方案列表失败。", Toast.LENGTH_SHORT).show();
+ });
+ }
+ });
+ }
+
public void removeFloatingTabDialog() {
if (floatingDialogView != null) {
try {
windowManager.removeView(floatingDialogView);
- floatingDialogView = null;
+ floatingDialogView = null; // 置空,防止重复移除或空指针异常
Log.d(TAG, "浮动标签页弹窗已移除");
} catch (IllegalArgumentException e) {
Log.w(TAG, "尝试移除不存在的视图", e);
@@ -131,20 +216,30 @@ public class FloatingTabDialogManager {
}
private WindowManager.LayoutParams createFloatingDialogParams() {
- // 创建浮动弹窗的参数
int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
WindowManager.LayoutParams.TYPE_PHONE;
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.WRAP_CONTENT, // 宽度自适应内容
- WindowManager.LayoutParams.WRAP_CONTENT, // 高度自适应内容
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.WRAP_CONTENT,
overlayType,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | // 如果希望点击弹窗外部能穿透,则保持
- WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // 确保它能接收触摸事件
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT
);
- params.gravity = Gravity.CENTER; // 居中显示
+ params.gravity = Gravity.CENTER;
return params;
}
+
+ private void showKeyboard() {
+ if (inputName != null) {
+ inputName.requestFocus(); // 确保输入框获取焦点
+ InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (imm != null) {
+ // 尝试强制显示键盘
+ imm.showSoftInput(inputName, InputMethodManager.SHOW_IMPLICIT);
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/util/ScriptConverter.java b/app/src/main/java/com/auto/clicker/autoclicker/util/ScriptConverter.java
deleted file mode 100644
index 67c6c4f..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/util/ScriptConverter.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.auto.clicker.autoclicker.util;
-
-import com.auto.clicker.autoclicker.data.EventWrapper;
-import com.auto.clicker.autoclicker.data.PointEvent;
-import com.auto.clicker.autoclicker.data.SlideEvent;
-import com.auto.clicker.autoclicker.room.PointEventEntity;
-import com.auto.clicker.autoclicker.room.SlideEventEntity;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ScriptConverter {
-
- public static List toPointEventEntities(List runtimeEvents, long scriptId) {
- List result = new ArrayList<>();
- for (EventWrapper wrapper : runtimeEvents) {
- if (wrapper.getType() == EventWrapper.EventType.POINT) {
- PointEvent point = (PointEvent) wrapper.getEvent();
- PointEventEntity entity = new PointEventEntity();
- entity.x = point.getX();
- entity.y = point.getY();
- entity.order = wrapper.getOrder();
- entity.scriptOwnerId = scriptId;
- result.add(entity);
- }
- }
- return result;
- }
-
- public static List toSlideEventEntities(List runtimeEvents, long scriptId) {
- List result = new ArrayList<>();
- for (EventWrapper wrapper : runtimeEvents) {
- if (wrapper.getType() == EventWrapper.EventType.SLIDE) {
- SlideEvent slide = (SlideEvent) wrapper.getEvent();
- SlideEventEntity entity = new SlideEventEntity();
- entity.startX = slide.getStartPoint().getX();
- entity.startY = slide.getStartPoint().getY();
- entity.endX = slide.getEndPoint().getX();
- entity.endY = slide.getEndPoint().getY();
- entity.order = wrapper.getOrder();
- entity.scriptOwnerId = scriptId;
- result.add(entity);
- }
- }
- return result;
- }
-}
-
diff --git a/app/src/main/java/com/auto/clicker/autoclicker/util/ScriptRestorer.java b/app/src/main/java/com/auto/clicker/autoclicker/util/ScriptRestorer.java
deleted file mode 100644
index 2d704f9..0000000
--- a/app/src/main/java/com/auto/clicker/autoclicker/util/ScriptRestorer.java
+++ /dev/null
@@ -1,131 +0,0 @@
-package com.auto.clicker.autoclicker.util;
-
-import static com.auto.clicker.autoclicker.view.FloatingViewManager.TOUCH_POINT_SIZE;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
-import android.os.Build;
-import android.view.Gravity;
-import android.view.WindowManager;
-import android.widget.TextView;
-
-import com.auto.clicker.autoclicker.R;
-import com.auto.clicker.autoclicker.data.EventWrapper;
-import com.auto.clicker.autoclicker.data.PointEvent;
-import com.auto.clicker.autoclicker.data.SlideEvent;
-import com.auto.clicker.autoclicker.room.PointEventEntity;
-import com.auto.clicker.autoclicker.room.ScriptWithEvents;
-import com.auto.clicker.autoclicker.room.SlideEventEntity;
-import com.auto.clicker.autoclicker.view.ConnectingLineView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ScriptRestorer {
-
- private final Context context;
- private final int screenWidth;
- private final int screenHeight;
-
- public ScriptRestorer(Context context, int screenWidth, int screenHeight) {
- this.context = context;
- this.screenWidth = screenWidth;
- this.screenHeight = screenHeight;
- }
-
- public List restoreRuntimeEvents(ScriptWithEvents script) {
- List events = new ArrayList<>();
- int counter = 0;
-
- // 还原点事件
- for (PointEventEntity entity : script.pointEvents) {
- TextView view = createTouchPointView(String.valueOf(entity.order));
- WindowManager.LayoutParams params = createTouchPointParams();
- params.x = entity.x;
- params.y = entity.y;
-
- PointEvent pointEvent = new PointEvent(entity.order, entity.x, entity.y, view, params);
- events.add(new EventWrapper(EventWrapper.EventType.POINT, pointEvent, entity.order));
- }
-
- // 还原滑动事件
- for (SlideEventEntity entity : script.slideEvents) {
- // 创建起点和终点
- TextView startView = createTouchPointView(String.valueOf(entity.order));
- TextView endView = createTouchPointView(String.valueOf(entity.order));
-
- WindowManager.LayoutParams startParams = createTouchPointParams();
- WindowManager.LayoutParams endParams = createTouchPointParams();
-
- startParams.x = entity.startX;
- startParams.y = entity.startY;
-
- endParams.x = entity.endX;
- endParams.y = entity.endY;
-
- PointEvent startEvent = new PointEvent(entity.order, entity.startX, entity.startY, startView, startParams);
- PointEvent endEvent = new PointEvent(entity.order, entity.endX, entity.endY, endView, endParams);
-
- // 创建连接线
- ConnectingLineView lineView = new ConnectingLineView(context);
- WindowManager.LayoutParams lineParams = createLineViewParams();
-
- SlideEvent slideEvent = new SlideEvent(entity.order, startEvent, endEvent, lineView, lineParams);
- events.add(new EventWrapper(EventWrapper.EventType.SLIDE, slideEvent, entity.order));
- }
-
- return events;
- }
-
- // 复制你的原始方法
- private TextView createTouchPointView(String label) {
- // 创建一个圆形点击点视图
- TextView touchPointView = new TextView(context);
- touchPointView.setBackgroundResource(R.drawable.ring_has_bg);
- touchPointView.setGravity(Gravity.CENTER);
- touchPointView.setText(label);
- touchPointView.setTextColor(Color.WHITE);
- touchPointView.setTextSize(19);
- return touchPointView;
- }
-
- private WindowManager.LayoutParams createTouchPointParams() {
- // 创建点击点的布局参数
- int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
- WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
- WindowManager.LayoutParams.TYPE_PHONE;
-
- WindowManager.LayoutParams params = new WindowManager.LayoutParams(
- TOUCH_POINT_SIZE, TOUCH_POINT_SIZE,
- overlayType,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
- WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
- PixelFormat.TRANSLUCENT
- );
- params.gravity = Gravity.TOP | Gravity.START;
- return params;
- }
-
- private WindowManager.LayoutParams createLineViewParams() {
- // 创建连接线(滑动路径)的参数,全屏不可点击
- int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
- WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
- WindowManager.LayoutParams.TYPE_PHONE;
-
- WindowManager.LayoutParams params = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.MATCH_PARENT,
- overlayType,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
- WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
- PixelFormat.TRANSLUCENT
- );
- params.gravity = Gravity.TOP | Gravity.START;
- params.x = 0;
- params.y = 0;
- return params;
- }
-}
-
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 08b0e18..5f4a4d4 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
@@ -36,10 +36,13 @@ import com.auto.clicker.autoclicker.data.EventWrapper;
import com.auto.clicker.autoclicker.data.PointEvent;
import com.auto.clicker.autoclicker.data.PositionUpdater;
import com.auto.clicker.autoclicker.data.SlideEvent;
-import com.auto.clicker.autoclicker.dialog.ScriptManagerDialog;
+import com.auto.clicker.autoclicker.room.SolutionWithEventsAndPoints;
+import com.auto.clicker.autoclicker.room.entity.EventEntity;
+import com.auto.clicker.autoclicker.room.entity.Solution;
+import com.auto.clicker.autoclicker.room.entity.TouchPoint;
+import com.auto.clicker.autoclicker.room.repository.EventRepository;
import com.auto.clicker.autoclicker.service.AutoClickService;
import com.auto.clicker.autoclicker.service.ForegroundService;
-import com.auto.clicker.autoclicker.ui.activity.floating.TransparentFloatingActivity;
import com.auto.clicker.autoclicker.util.FloatingTabDialogManager;
import com.auto.clicker.autoclicker.util.PrefUtils;
import com.auto.clicker.autoclicker.util.ScreenUtils;
@@ -71,6 +74,8 @@ public class FloatingViewManager {
private FloatingTabDialogManager floatingTabDialogManager;
+ private EventRepository eventRepository;
+
public FloatingViewManager(Context context) {
this.context = context;
this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
@@ -78,6 +83,8 @@ public class FloatingViewManager {
this.screenWidth = screenSize.x;
this.screenHeight = screenSize.y;
this.floatingTabDialogManager = new FloatingTabDialogManager(context);
+ this.floatingTabDialogManager.setFloatingViewManager(this);
+ this.eventRepository = new EventRepository(context.getApplicationContext());
registerBroadcastReceiver();
}
@@ -266,7 +273,7 @@ public class FloatingViewManager {
}
// 创建点击点视图
- TextView point = createTouchPointView(String.valueOf(eventOrderCounter));
+ TextView pointView = createTouchPointView(String.valueOf(eventOrderCounter));
// 设置位置居中
WindowManager.LayoutParams params = createTouchPointParams();
@@ -274,15 +281,18 @@ public class FloatingViewManager {
params.y = screenHeight / 2 - TOUCH_POINT_SIZE / 2;
// 包装为事件对象
- PointEvent pointEvent = new PointEvent(eventOrderCounter, params.x, params.y, point, params);
+ PointEvent pointEvent = new PointEvent(eventOrderCounter, params.x, params.y);
+ pointEvent.setView(pointView);
+ pointEvent.setLayoutParams(params);
+
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.POINT, pointEvent, eventOrderCounter));
eventOrderCounter++;
Log.d(TAG, "addPoint runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
// 设置拖动功能并添加到窗口
- setupDraggablePoint(point, params, pointEvent);
- windowManager.addView(point, params);
+ setupDraggablePoint(pointView, params, pointEvent);
+ windowManager.addView(pointView, params);
updateServicePositions();
}
@@ -294,37 +304,44 @@ public class FloatingViewManager {
}
// 创建起点
- TextView startPoint = createTouchPointView(String.valueOf(eventOrderCounter));
+ TextView startPointView = createTouchPointView(String.valueOf(eventOrderCounter));
WindowManager.LayoutParams startParams = createTouchPointParams();
startParams.x = screenWidth / 2 - 100;
startParams.y = screenHeight / 2 - 50;
- PointEvent startPointEvent = new PointEvent(eventOrderCounter, startParams.x, startParams.y, startPoint, startParams);
+ PointEvent startPointEvent = new PointEvent(eventOrderCounter, startParams.x, startParams.y);
+ startPointEvent.setView(startPointView);
+ startPointEvent.setLayoutParams(startParams);
// 创建终点
- TextView endPoint = createTouchPointView(String.valueOf(eventOrderCounter));
+ TextView endPointView = createTouchPointView(String.valueOf(eventOrderCounter));
WindowManager.LayoutParams endParams = createTouchPointParams();
endParams.x = screenWidth / 2 + 100;
endParams.y = screenHeight / 2 - 50;
- PointEvent endPointEvent = new PointEvent(eventOrderCounter, endParams.x, endParams.y, endPoint, endParams);
+ PointEvent endPointEvent = new PointEvent(eventOrderCounter, endParams.x, endParams.y);
+ startPointEvent.setView(endPointView);
+ startPointEvent.setLayoutParams(endParams);
// 创建滑动连线
ConnectingLineView lineView = new ConnectingLineView(context);
WindowManager.LayoutParams lineParams = createLineViewParams();
- SlideEvent slideEvent = new SlideEvent(eventOrderCounter, startPointEvent, endPointEvent, lineView, lineParams);
+ SlideEvent slideEvent = new SlideEvent(eventOrderCounter, startPointEvent, endPointEvent);
+ slideEvent.setLineView(lineView);
+ slideEvent.setLineParams(lineParams);
+
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.SLIDE, slideEvent, eventOrderCounter));
eventOrderCounter++;
Log.d(TAG, "addSlide runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
// 设置滑动点可拖动
- setupDraggableSlidePoint(startPoint, startParams, startPointEvent, slideEvent);
- setupDraggableSlidePoint(endPoint, endParams, endPointEvent, slideEvent);
+ setupDraggableSlidePoint(startPointView, startParams, startPointEvent, slideEvent);
+ setupDraggableSlidePoint(endPointView, endParams, endPointEvent, slideEvent);
// 添加视图到窗口
windowManager.addView(lineView, lineParams);
- windowManager.addView(startPoint, startParams);
- windowManager.addView(endPoint, endParams);
+ windowManager.addView(startPointView, startParams);
+ windowManager.addView(endPointView, endParams);
updateLinePosition(slideEvent); // 更新线的位置
updateServicePositions();
@@ -335,9 +352,9 @@ public class FloatingViewManager {
// 获取事件的视图
View viewToToggle = null;
if (wrapper.getType() == EventWrapper.EventType.POINT) {
- viewToToggle = ((PointEvent) wrapper.getEvent()).getView();
+ viewToToggle = createTouchPointView(String.valueOf(wrapper.getEvent().getId()));
} else if (wrapper.getType() == EventWrapper.EventType.SLIDE) {
- View startPointView = getView(show, wrapper);
+ View startPointView = getView(show, wrapper,context);
WindowManager.LayoutParams startParams = (WindowManager.LayoutParams) startPointView.getLayoutParams();
if (show) {
@@ -367,12 +384,12 @@ public class FloatingViewManager {
}
@NonNull
- private static View getView(boolean show, EventWrapper wrapper) {
+ private View getView(boolean show, EventWrapper wrapper,Context context) {
SlideEvent slideEvent = (SlideEvent) wrapper.getEvent();
// 假设你只隐藏/显示点,线也需要同步
- View startPointView = slideEvent.getStartPoint().getView();
- View endPointView = slideEvent.getEndPoint().getView();
- View lineView = slideEvent.getLineView();
+ View startPointView = createTouchPointView(String.valueOf(slideEvent.getStartPoint().getId()));
+ View endPointView = createTouchPointView(String.valueOf(slideEvent.getEndPoint().getId()));
+ View lineView = new ConnectingLineView(context);
if (show) {
// 如果是显示,可能需要重新添加或设置可见性
@@ -423,7 +440,7 @@ public class FloatingViewManager {
PrefUtils.setFloatingShown(context, 0);
// 发送浮窗关闭广播
- Intent intent = new Intent("com.auto.autoclicker.FLOATING_WINDOW_STATE_CHANGED");
+ Intent intent = new Intent("com.auto.clicker.autoclicker.FLOATING_WINDOW_STATE_CHANGED");
intent.putExtra("isShown", false);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
@@ -788,13 +805,145 @@ public class FloatingViewManager {
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if ("com.auto.autoclicker.FLASH_TOUCH_POINT".equals(intent.getAction())) {
+ if ("com.auto.clicker.autoclicker.FLASH_TOUCH_POINT".equals(intent.getAction())) {
int index = intent.getIntExtra("index", -1);
flashTouchPoint(index);
}
}
},
- new IntentFilter("com.auto.autoclicker.FLASH_TOUCH_POINT")
+ new IntentFilter("com.auto.clicker.autoclicker.FLASH_TOUCH_POINT")
);
}
+
+ public void saveCurrentEventsAsSolution(String solutionName, EventRepository.RepositoryCallback callback) {
+ if (solutionName == null || solutionName.trim().isEmpty()) {
+ Toast.makeText(context, "方案名称不能为空", Toast.LENGTH_SHORT).show();
+ // 在这里调用回调的 onError,或者 onComplete 返回一个表示失败的值
+ // 确保 FloatingTabDialogManager 收到反馈
+ if (callback != null) {
+ callback.onComplete(-1L); // 返回一个表示失败的值
+ }
+ return;
+ }
+ if (runtimeEvents.isEmpty()) {
+ Toast.makeText(context, "当前没有事件可以保存", Toast.LENGTH_SHORT).show();
+ if (callback != null) {
+ callback.onComplete(-1L); // 返回一个表示失败的值
+ }
+ return;
+ }
+
+ Solution newSolution = new Solution(solutionName);
+ eventRepository.insertSolutionWithEvents(newSolution, runtimeEvents, new EventRepository.RepositoryCallback() {
+ @Override
+ public void onComplete(Long solutionId) {
+ // 成功保存,Toast 可以在这里显示,也可以在 FloatingTabDialogManager 中显示
+ // 为了职责分离,建议在这里显示一个简单的"保存成功" Toast,然后让 FloatingTabDialogManager 决定是否关闭
+ // Toast.makeText(context, "方案 '" + solutionName + "' 保存成功!", Toast.LENGTH_SHORT).show();
+ // 保存失败,Toast 可以在这里显示
+ // Toast.makeText(context, "保存方案失败。", Toast.LENGTH_SHORT).show();
+ if (callback != null) {
+ callback.onComplete(solutionId); // 将结果传递给调用者
+ }
+ }
+
+ @Override
+ public void onError(Exception e) {
+ Log.e(TAG, "保存方案失败: " + e.getMessage(), e);
+ Toast.makeText(context, "保存方案失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
+ if (callback != null) {
+ callback.onError(e); // 将错误传递给调用者
+ }
+ }
+ });
+ }
+
+ public void loadSolution(long solutionId) {
+ eventRepository.getSolutionWithEventsAndPoints(solutionId, new EventRepository.RepositoryCallback() {
+ @Override
+ public void onComplete(SolutionWithEventsAndPoints solutionData) {
+ if (solutionData != null && solutionData.events != null) {
+ removeFloatingViews();
+ runtimeEvents.clear();
+ eventOrderCounter = 1;
+
+ for (SolutionWithEventsAndPoints.EventWithPoints eventWithPoints : solutionData.events) {
+ EventEntity eventEntity = eventWithPoints.eventEntity;
+ EventWrapper.EventType type = EventWrapper.EventType.valueOf(eventEntity.eventType);
+
+ if (type == EventWrapper.EventType.POINT) {
+ TouchPoint clickPoint = eventWithPoints.clickTouchPoint;
+ if (clickPoint != null) {
+ PointEvent pointEvent = new PointEvent(eventEntity.orderInSolution, clickPoint.x, clickPoint.y);
+ TextView pointView = createTouchPointView(String.valueOf(pointEvent.getId()));
+ WindowManager.LayoutParams params = createTouchPointParams();
+ params.x = pointEvent.getX();
+ params.y = pointEvent.getY();
+ pointView.setLayoutParams(params);
+ pointEvent.setView(pointView);
+ setupDraggablePoint(pointView, params, pointEvent);
+ windowManager.addView(pointView, params);
+ runtimeEvents.add(new EventWrapper(type, pointEvent, pointEvent.getId()));
+ }
+ } else if (type == EventWrapper.EventType.SLIDE) {
+ TouchPoint startPointData = eventWithPoints.slideStartTouchPoint;
+ TouchPoint endPointData = eventWithPoints.slideEndTouchPoint;
+ if (startPointData != null && endPointData != null) {
+ PointEvent startPointEvent = new PointEvent(eventEntity.orderInSolution, startPointData.x, startPointData.y);
+ PointEvent endPointEvent = new PointEvent(eventEntity.orderInSolution, endPointData.x, endPointData.y);
+
+ TextView startPointView = createTouchPointView(String.valueOf(startPointEvent.getId()));
+ WindowManager.LayoutParams startParams = createTouchPointParams();
+ startParams.x = startPointEvent.getX();
+ startParams.y = startPointEvent.getY();
+ startPointView.setLayoutParams(startParams);
+
+ TextView endPointView = createTouchPointView(String.valueOf(endPointEvent.getId()));
+ WindowManager.LayoutParams endParams = createTouchPointParams();
+ endParams.x = endPointEvent.getX();
+ endParams.y = endPointEvent.getY();
+ endPointView.setLayoutParams(endParams);
+
+ ConnectingLineView lineView = new ConnectingLineView(context);
+ WindowManager.LayoutParams lineParams = createLineViewParams();
+
+ SlideEvent slideEvent = new SlideEvent(eventEntity.orderInSolution, startPointEvent, endPointEvent);
+
+ setupDraggableSlidePoint(startPointView, startParams, startPointEvent, slideEvent);
+ setupDraggableSlidePoint(endPointView, endParams, endPointEvent, slideEvent);
+
+ windowManager.addView(lineView, lineParams);
+ windowManager.addView(startPointView, startParams);
+ windowManager.addView(endPointView, endParams);
+
+ updateLinePosition(slideEvent);
+ runtimeEvents.add(new EventWrapper(type, slideEvent, slideEvent.getId()));
+ }
+ }
+ if (eventEntity.orderInSolution >= eventOrderCounter) {
+ eventOrderCounter = eventEntity.orderInSolution + 1;
+ }
+ }
+ updateServicePositions();
+ Toast.makeText(context, "方案 '" + solutionData.solution.solutionName + "' 加载成功!", Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(context, "加载方案失败或方案不存在。", Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public void onError(Exception e) {
+ Log.e(TAG, "加载方案失败: " + e.getMessage(), e);
+ Toast.makeText(context, "加载方案失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ public void getAllSolutions(EventRepository.RepositoryCallback> callback) {
+ if (eventRepository != null) {
+ eventRepository.getAllSolutions(callback);
+ } else {
+ callback.onError(new IllegalStateException("EventRepository not initialized."));
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_scripts.xml b/app/src/main/res/layout/activity_scripts.xml
index 828f499..0cbfcd9 100644
--- a/app/src/main/res/layout/activity_scripts.xml
+++ b/app/src/main/res/layout/activity_scripts.xml
@@ -22,7 +22,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
- android:text="@string/scripts"
+ android:text="@string/solutionList"
android:textColor="@color/white"
android:textSize="32sp"
android:textStyle="bold"
diff --git a/app/src/main/res/layout/activity_transparent_floating.xml b/app/src/main/res/layout/activity_transparent_floating.xml
deleted file mode 100644
index 1ba554e..0000000
--- a/app/src/main/res/layout/activity_transparent_floating.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/floating_tab_dialog.xml b/app/src/main/res/layout/floating_tab_dialog.xml
index 89045e9..ad98c26 100644
--- a/app/src/main/res/layout/floating_tab_dialog.xml
+++ b/app/src/main/res/layout/floating_tab_dialog.xml
@@ -1,40 +1,38 @@
+ android:orientation="horizontal"
+ android:weightSum="2">
+
+
+
+
+
-
-
+
+
+
diff --git a/app/src/main/res/layout/fragment_how_multi.xml b/app/src/main/res/layout/fragment_how_multi.xml
index d9f524c..0e1d322 100644
--- a/app/src/main/res/layout/fragment_how_multi.xml
+++ b/app/src/main/res/layout/fragment_how_multi.xml
@@ -117,7 +117,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
- android:text="Save/Load scripts"
+ android:text="Save/Load solutionList"
android:textColor="#FFFFFF"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="@+id/text_play_stop"
@@ -285,7 +285,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="72dp"
- android:text="Drag the action point to move it
+ android:text="Drag the action touchPoint to move it
\nanywhere, click to edit the interval"
android:textColor="@color/white"
android:textSize="14sp"
@@ -396,7 +396,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
- android:text="Drag the start/end point of swipe route to move
+ android:text="Drag the start/end touchPoint of swipe route to move
\nit anywhere, click on either of the two to edit the
\ninterval or duration"
android:textColor="@color/white"
diff --git a/app/src/main/res/layout/fragment_how_single.xml b/app/src/main/res/layout/fragment_how_single.xml
index aeb2a2c..b25db39 100644
--- a/app/src/main/res/layout/fragment_how_single.xml
+++ b/app/src/main/res/layout/fragment_how_single.xml
@@ -43,7 +43,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="11dp"
- android:text="Save/Load scripts"
+ android:text="Save/Load solutionList"
android:textColor="#FFFFFF"
android:textSize="14sp"
app:layout_constraintStart_toStartOf="@+id/text_play_stop"
@@ -211,7 +211,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="87dp"
- android:text="Drag the action point to move
+ android:text="Drag the action touchPoint to move
\nit anywhere, click to edit the"
android:textColor="@color/white"
android:textSize="14sp"
diff --git a/app/src/main/res/layout/save_script_page.xml b/app/src/main/res/layout/save_script_page.xml
index 1ae0ac2..7f212dd 100644
--- a/app/src/main/res/layout/save_script_page.xml
+++ b/app/src/main/res/layout/save_script_page.xml
@@ -9,7 +9,6 @@
android:id="@+id/tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="19dp"
android:text="Enter the Script name and hit
\nsave button"
android:textColor="@color/text_gray"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 9e0e1bb..6279f75 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -16,8 +16,8 @@
Other
Title
Subtitle
- Scripts
- Your saved scripts \nwill be shown here
+ Scripts
+ Your saved solutionList \nwill be shown here
Create Now
Import
Accessibility
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index ff47f4e..5039878 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -6,19 +6,5 @@
- @drawable/activity_background
-
-
-
\ No newline at end of file