功能添加优化
This commit is contained in:
parent
6aa0ee4cb0
commit
add6f3d1e0
@ -18,13 +18,6 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.AutoClicker"
|
android:theme="@style/Theme.AutoClicker"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
<activity
|
|
||||||
android:name=".ui.activity.floating.TransparentFloatingActivity"
|
|
||||||
android:theme="@style/Theme.TransparentOverlay"
|
|
||||||
android:launchMode="singleTop"
|
|
||||||
android:excludeFromRecents="true"
|
|
||||||
android:taskAffinity=""
|
|
||||||
android:exported="false" />
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.activity.main.QuestionActivity"
|
android:name=".ui.activity.main.QuestionActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|||||||
@ -1,21 +1,29 @@
|
|||||||
package com.auto.clicker.autoclicker.data;
|
package com.auto.clicker.autoclicker.data;
|
||||||
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
public class PointEvent extends Event {
|
public class PointEvent extends Event {
|
||||||
|
private int id;
|
||||||
private int x;
|
private int x;
|
||||||
private int y;
|
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);
|
super(id);
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
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() {
|
public int getX() {
|
||||||
@ -34,7 +42,7 @@ public class PointEvent extends Event {
|
|||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public View getView() {
|
public TextView getView() {
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,20 +4,27 @@ import android.view.WindowManager;
|
|||||||
|
|
||||||
import com.auto.clicker.autoclicker.view.ConnectingLineView;
|
import com.auto.clicker.autoclicker.view.ConnectingLineView;
|
||||||
|
|
||||||
|
|
||||||
public class SlideEvent extends Event {
|
public class SlideEvent extends Event {
|
||||||
|
private int id;
|
||||||
private PointEvent startPoint;
|
private PointEvent startPoint;
|
||||||
private PointEvent endPoint;
|
private PointEvent endPoint;
|
||||||
private ConnectingLineView lineView;
|
|
||||||
private WindowManager.LayoutParams lineParams;
|
|
||||||
|
|
||||||
public SlideEvent(int id, PointEvent startPoint, PointEvent endPoint,
|
private transient ConnectingLineView lineView;
|
||||||
ConnectingLineView lineView, WindowManager.LayoutParams lineParams) {
|
private transient WindowManager.LayoutParams lineParams;
|
||||||
|
|
||||||
|
public SlideEvent(int id, PointEvent startPoint, PointEvent endPoint) {
|
||||||
super(id);
|
super(id);
|
||||||
this.startPoint = startPoint;
|
this.startPoint = startPoint;
|
||||||
this.endPoint = endPoint;
|
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() {
|
public PointEvent getStartPoint() {
|
||||||
@ -51,5 +58,4 @@ public class SlideEvent extends Event {
|
|||||||
public void setLineParams(WindowManager.LayoutParams lineParams) {
|
public void setLineParams(WindowManager.LayoutParams lineParams) {
|
||||||
this.lineParams = lineParams;
|
this.lineParams = lineParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -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<ScriptEntity> scripts = AppDatabase.getInstance(context).scriptDao().getAllScripts();
|
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
|
||||||
recyclerView.setAdapter(new ScriptListAdapter(scripts, listener));
|
|
||||||
});
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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<View> 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -7,12 +7,18 @@ import androidx.room.Room;
|
|||||||
import androidx.room.RoomDatabase;
|
import androidx.room.RoomDatabase;
|
||||||
|
|
||||||
import com.auto.clicker.autoclicker.MyApplication;
|
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 class AppDatabase extends RoomDatabase {
|
||||||
public abstract ScriptEntityDao scriptDao();
|
public abstract SolutionDao solutionDao();
|
||||||
public abstract PointEventEntityDao pointEventEntityDao();
|
public abstract TouchPointDao pointDao();
|
||||||
public abstract SlideEventEntityDao slideEventEntityDao();
|
public abstract EventEntityDao eventEntityDao();
|
||||||
|
|
||||||
private static volatile AppDatabase INSTANCE;
|
private static volatile AppDatabase INSTANCE;
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
package com.auto.clicker.autoclicker.room;
|
|
||||||
|
|
||||||
import androidx.room.Dao;
|
|
||||||
|
|
||||||
@Dao
|
|
||||||
public interface PointEventEntityDao {
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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<PointEventEntity> points);
|
|
||||||
@Insert void insertSlideEvents(List<SlideEventEntity> slides);
|
|
||||||
|
|
||||||
@Transaction
|
|
||||||
@Query("SELECT * FROM scripts")
|
|
||||||
List<ScriptEntity> getAllScripts();
|
|
||||||
|
|
||||||
@Transaction
|
|
||||||
@Query("SELECT * FROM scripts WHERE scriptId = :scriptId")
|
|
||||||
ScriptWithEvents getScriptById(long scriptId);
|
|
||||||
|
|
||||||
@Delete
|
|
||||||
void deleteScript(ScriptEntity script);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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<PointEventEntity> pointEvents;
|
|
||||||
|
|
||||||
@Relation(parentColumn = "scriptId", entityColumn = "scriptOwnerId")
|
|
||||||
public List<SlideEventEntity> slideEvents;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
package com.auto.clicker.autoclicker.room;
|
|
||||||
|
|
||||||
import androidx.room.Dao;
|
|
||||||
|
|
||||||
@Dao
|
|
||||||
public interface SlideEventEntityDao {
|
|
||||||
}
|
|
||||||
@ -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<EventWithPoints> 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; // 滑动事件的终点
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<EventEntity> getEventsForSolution(long solutionId);
|
||||||
|
}
|
||||||
@ -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<Solution> 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<SolutionWithEventsAndPoints> getAllSolutionsWithEventsAndPoints();
|
||||||
|
}
|
||||||
@ -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);
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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; }
|
||||||
|
}
|
||||||
@ -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; }
|
||||||
|
}
|
||||||
@ -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<EventWrapper> runtimeEvents, RepositoryCallback<Long> 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<List<Solution>> callback) {
|
||||||
|
databaseWriteExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
List<Solution> 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<SolutionWithEventsAndPoints> 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<Integer> 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<T> {
|
||||||
|
void onComplete(T result);
|
||||||
|
|
||||||
|
void onError(Exception e);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -239,7 +239,7 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void flashTouchFeedback(int index) {
|
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);
|
intent.putExtra("index", index);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
||||||
}
|
}
|
||||||
@ -257,7 +257,7 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
instance = null;
|
instance = null;
|
||||||
stopClicking();
|
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);
|
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
||||||
logDebug("无障碍服务已销毁");
|
logDebug("无障碍服务已销毁");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
@ -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<ViewPagerAdapter.ViewHolder> {
|
|
||||||
private final List<View> views;
|
|
||||||
|
|
||||||
public ViewPagerAdapter(List<View> 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); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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<Fragment> fragmentList = new ArrayList<>();
|
|
||||||
private final List<String> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -3,26 +3,20 @@ package com.auto.clicker.autoclicker.ui.adapter.script;
|
|||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.auto.clicker.autoclicker.R;
|
import com.auto.clicker.autoclicker.R;
|
||||||
import com.auto.clicker.autoclicker.dialog.LoadScriptView;
|
import com.auto.clicker.autoclicker.room.entity.Solution;
|
||||||
import com.auto.clicker.autoclicker.room.ScriptEntity;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ScriptListAdapter extends RecyclerView.Adapter<ScriptListAdapter.ViewHolder> {
|
public class ScriptListAdapter extends RecyclerView.Adapter<ScriptListAdapter.ViewHolder> {
|
||||||
private List<ScriptEntity> scripts;
|
private List<Solution> solutionList;
|
||||||
private LoadScriptView.OnScriptClickListener listener;
|
|
||||||
|
|
||||||
|
public ScriptListAdapter(List<Solution> solutionList) {
|
||||||
public ScriptListAdapter(List<ScriptEntity> scripts, LoadScriptView.OnScriptClickListener listener) {
|
this.solutionList = solutionList;
|
||||||
this.scripts = scripts;
|
|
||||||
this.listener = listener;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -40,7 +34,7 @@ public class ScriptListAdapter extends RecyclerView.Adapter<ScriptListAdapter.Vi
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
return scripts.size();
|
return solutionList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|||||||
@ -0,0 +1,71 @@
|
|||||||
|
package com.auto.clicker.autoclicker.ui.floating;
|
||||||
|
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.auto.clicker.autoclicker.room.entity.Solution;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SolutionAdapter extends RecyclerView.Adapter<SolutionAdapter.SolutionViewHolder> {
|
||||||
|
|
||||||
|
private List<Solution> solutionList;
|
||||||
|
private OnSolutionClickListener listener;
|
||||||
|
|
||||||
|
// 定义接口用于处理点击事件
|
||||||
|
public interface OnSolutionClickListener {
|
||||||
|
void onSolutionClick(Solution solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SolutionAdapter(List<Solution> 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<Solution> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,126 +3,211 @@ package com.auto.clicker.autoclicker.util;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.PixelFormat;
|
import android.graphics.PixelFormat;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.ContextThemeWrapper;
|
import android.view.ContextThemeWrapper;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.EditText;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.LinearLayout;
|
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.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 {
|
public class FloatingTabDialogManager {
|
||||||
|
|
||||||
private static final String TAG = "FloatingTabDialogMgr";
|
private static final String TAG = "FloatingTabDialogMgr";
|
||||||
private final Context originalContext; // 保存原始的 Service Context
|
private final Context context;
|
||||||
private final WindowManager windowManager;
|
private final WindowManager windowManager;
|
||||||
private LinearLayout floatingDialogView;
|
private LinearLayout floatingDialogView;
|
||||||
private WindowManager.LayoutParams floatingDialogParams;
|
private WindowManager.LayoutParams floatingDialogParams;
|
||||||
|
|
||||||
private Button tabOneButton;
|
private Button saveTab;
|
||||||
private Button tabTwoButton;
|
private Button loadTab;
|
||||||
private FrameLayout contentFrame;
|
private View savePage;
|
||||||
private View pageOneView;
|
private View loadPage;
|
||||||
private View pageTwoView;
|
|
||||||
|
private FloatingViewManager floatingViewManager;
|
||||||
|
|
||||||
|
private EditText inputName;
|
||||||
|
private Button saveButton;
|
||||||
|
private Button closeButton;
|
||||||
|
|
||||||
|
private RecyclerView loadRecyclerview;
|
||||||
|
private SolutionAdapter solutionsAdapter;
|
||||||
|
private List<Solution> solutionList = new ArrayList<>();
|
||||||
|
|
||||||
public FloatingTabDialogManager(Context context) {
|
public FloatingTabDialogManager(Context context) {
|
||||||
this.originalContext = context; // 保存原始 Context
|
this.context = context;
|
||||||
this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFloatingViewManager(FloatingViewManager manager) {
|
||||||
|
this.floatingViewManager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
public void showFloatingTabDialog() {
|
public void showFloatingTabDialog() {
|
||||||
if (floatingDialogView != null) {
|
if (floatingDialogView != null) {
|
||||||
removeFloatingTabDialog(); // 如果已经显示,先移除
|
removeFloatingTabDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 关键修改:使用 ContextThemeWrapper 包裹 Service Context ---
|
Context themedContext = new ContextThemeWrapper(context, R.style.Theme_AutoClicker);
|
||||||
Context themedContext = new ContextThemeWrapper(originalContext, R.style.Theme_AutoClicker);
|
|
||||||
// 或者如果你想用 Material3 的默认主题,但你的 Theme_AutoClicker 已经继承了 Material3,那用它就行
|
|
||||||
// Context themedContext = new ContextThemeWrapper(originalContext, R.style.Theme_Material3_DayNight_NoActionBar); // 也可以直接用这个
|
|
||||||
|
|
||||||
floatingDialogView = (LinearLayout) LayoutInflater.from(themedContext).inflate(R.layout.floating_tab_dialog, null);
|
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);
|
||||||
|
|
||||||
// 获取视图组件
|
saveTab.setOnClickListener(v -> showPage(0));
|
||||||
tabOneButton = floatingDialogView.findViewById(R.id.tab_one_button);
|
loadTab.setOnClickListener(v -> showPage(1));
|
||||||
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);
|
|
||||||
|
|
||||||
// 设置标签按钮的点击事件
|
inputName = savePage.findViewById(R.id.script_name_input);
|
||||||
tabOneButton.setOnClickListener(v -> showPage(0));
|
saveButton = savePage.findViewById(R.id.save);
|
||||||
tabTwoButton.setOnClickListener(v -> showPage(1));
|
closeButton = savePage.findViewById(R.id.close);
|
||||||
|
|
||||||
// 设置关闭按钮的点击事件
|
saveButton.setOnClickListener(v -> {
|
||||||
if (closeDialogButton != null) {
|
String solutionName = inputName.getText().toString().trim();
|
||||||
closeDialogButton.setOnClickListener(v -> {
|
|
||||||
removeFloatingTabDialog(); // 点击关闭按钮时,移除弹窗
|
if (floatingViewManager != null) {
|
||||||
});
|
floatingViewManager.saveCurrentEventsAsSolution(solutionName, new EventRepository.RepositoryCallback<Long>() {
|
||||||
|
@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
|
||||||
showPage(0);
|
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 {
|
try {
|
||||||
windowManager.addView(floatingDialogView, floatingDialogParams);
|
windowManager.addView(floatingDialogView, floatingDialogParams);
|
||||||
Log.d(TAG, "浮动标签页弹窗已显示");
|
Log.d(TAG, "浮动标签页弹窗已显示");
|
||||||
} catch (WindowManager.BadTokenException e) {
|
} catch (WindowManager.BadTokenException e) {
|
||||||
Log.e(TAG, "无法添加浮动标签页弹窗,可能是权限问题或上下文无效", e);
|
Log.e(TAG, "无法添加浮动标签页弹窗,可能是权限问题或上下文无效", e);
|
||||||
|
Toast.makeText(context, "显示弹窗失败,请检查权限。", Toast.LENGTH_SHORT).show();
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
Log.e(TAG, "需要悬浮窗权限才能显示浮动弹窗", e);
|
Log.e(TAG, "需要悬浮窗权限才能显示浮动弹窗", e);
|
||||||
// 引导用户去开启权限,如果你在 FloatingViewManager 中已经处理了,这里可以省略
|
Toast.makeText(context, "请授予悬浮窗权限以便显示。", Toast.LENGTH_SHORT).show();
|
||||||
// Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
|
||||||
// Uri.parse("package:" + context.getPackageName()));
|
|
||||||
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
// context.startActivity(intent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showPage(int pageIndex) {
|
private void showPage(int pageIndex) {
|
||||||
// 确保所有视图都已正确加载(例如,通过 inflated 后的 findViewById)
|
if (savePage == null || loadPage == null) {
|
||||||
if (pageOneView == null || pageTwoView == null) {
|
|
||||||
Log.e(TAG, "页面视图未初始化!");
|
Log.e(TAG, "页面视图未初始化!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 隐藏所有页面
|
// 隐藏所有页面
|
||||||
pageOneView.setVisibility(View.GONE);
|
savePage.setVisibility(View.GONE);
|
||||||
pageTwoView.setVisibility(View.GONE);
|
loadPage.setVisibility(View.GONE);
|
||||||
|
|
||||||
// 重置所有标签按钮的颜色/背景(如果需要视觉反馈)
|
// 重置Tab按钮颜色
|
||||||
// 注意:这里使用 getContext().getResources().getColor() 是在 themedContext 的上下文中获取颜色
|
saveTab.setTextColor(context.getResources().getColor(android.R.color.darker_gray));
|
||||||
// 如果你的颜色定义在 themes.xml 或 colors.xml 中,并且依赖于主题属性,那么需要确保主题是正确的
|
loadTab.setTextColor(context.getResources().getColor(android.R.color.darker_gray));
|
||||||
tabOneButton.setTextColor(originalContext.getResources().getColor(android.R.color.darker_gray)); // 用 originalContext 或 themedContext
|
|
||||||
tabTwoButton.setTextColor(originalContext.getResources().getColor(android.R.color.darker_gray)); // 最好用 themedContext
|
|
||||||
|
|
||||||
// 显示选定页面并更新标签样式
|
|
||||||
switch (pageIndex) {
|
switch (pageIndex) {
|
||||||
case 0:
|
case 0: // 保存页面
|
||||||
pageOneView.setVisibility(View.VISIBLE);
|
savePage.setVisibility(View.VISIBLE);
|
||||||
tabOneButton.setTextColor(originalContext.getResources().getColor(android.R.color.black)); // 选中颜色
|
saveTab.setTextColor(context.getResources().getColor(android.R.color.black));
|
||||||
|
// 在显示保存页面时尝试显示键盘
|
||||||
|
showKeyboard();
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1: // 加载页面
|
||||||
pageTwoView.setVisibility(View.VISIBLE);
|
loadPage.setVisibility(View.VISIBLE);
|
||||||
tabTwoButton.setTextColor(originalContext.getResources().getColor(android.R.color.black)); // 选中颜色
|
loadTab.setTextColor(context.getResources().getColor(android.R.color.black));
|
||||||
|
loadSolutionsForList();
|
||||||
break;
|
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<List<Solution>>() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(List<Solution> 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() {
|
public void removeFloatingTabDialog() {
|
||||||
if (floatingDialogView != null) {
|
if (floatingDialogView != null) {
|
||||||
try {
|
try {
|
||||||
windowManager.removeView(floatingDialogView);
|
windowManager.removeView(floatingDialogView);
|
||||||
floatingDialogView = null;
|
floatingDialogView = null; // 置空,防止重复移除或空指针异常
|
||||||
Log.d(TAG, "浮动标签页弹窗已移除");
|
Log.d(TAG, "浮动标签页弹窗已移除");
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
Log.w(TAG, "尝试移除不存在的视图", e);
|
Log.w(TAG, "尝试移除不存在的视图", e);
|
||||||
@ -131,20 +216,30 @@ public class FloatingTabDialogManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private WindowManager.LayoutParams createFloatingDialogParams() {
|
private WindowManager.LayoutParams createFloatingDialogParams() {
|
||||||
// 创建浮动弹窗的参数
|
|
||||||
int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
|
int overlayType = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?
|
||||||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
|
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY :
|
||||||
WindowManager.LayoutParams.TYPE_PHONE;
|
WindowManager.LayoutParams.TYPE_PHONE;
|
||||||
|
|
||||||
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
||||||
WindowManager.LayoutParams.WRAP_CONTENT, // 宽度自适应内容
|
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||||
WindowManager.LayoutParams.WRAP_CONTENT, // 高度自适应内容
|
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||||
overlayType,
|
overlayType,
|
||||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | // 如果希望点击弹窗外部能穿透,则保持
|
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
|
||||||
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // 确保它能接收触摸事件
|
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
|
||||||
PixelFormat.TRANSLUCENT
|
PixelFormat.TRANSLUCENT
|
||||||
);
|
);
|
||||||
params.gravity = Gravity.CENTER; // 居中显示
|
params.gravity = Gravity.CENTER;
|
||||||
return params;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -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<PointEventEntity> toPointEventEntities(List<EventWrapper> runtimeEvents, long scriptId) {
|
|
||||||
List<PointEventEntity> 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<SlideEventEntity> toSlideEventEntities(List<EventWrapper> runtimeEvents, long scriptId) {
|
|
||||||
List<SlideEventEntity> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -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<EventWrapper> restoreRuntimeEvents(ScriptWithEvents script) {
|
|
||||||
List<EventWrapper> 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -36,10 +36,13 @@ import com.auto.clicker.autoclicker.data.EventWrapper;
|
|||||||
import com.auto.clicker.autoclicker.data.PointEvent;
|
import com.auto.clicker.autoclicker.data.PointEvent;
|
||||||
import com.auto.clicker.autoclicker.data.PositionUpdater;
|
import com.auto.clicker.autoclicker.data.PositionUpdater;
|
||||||
import com.auto.clicker.autoclicker.data.SlideEvent;
|
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.AutoClickService;
|
||||||
import com.auto.clicker.autoclicker.service.ForegroundService;
|
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.FloatingTabDialogManager;
|
||||||
import com.auto.clicker.autoclicker.util.PrefUtils;
|
import com.auto.clicker.autoclicker.util.PrefUtils;
|
||||||
import com.auto.clicker.autoclicker.util.ScreenUtils;
|
import com.auto.clicker.autoclicker.util.ScreenUtils;
|
||||||
@ -71,6 +74,8 @@ public class FloatingViewManager {
|
|||||||
|
|
||||||
private FloatingTabDialogManager floatingTabDialogManager;
|
private FloatingTabDialogManager floatingTabDialogManager;
|
||||||
|
|
||||||
|
private EventRepository eventRepository;
|
||||||
|
|
||||||
public FloatingViewManager(Context context) {
|
public FloatingViewManager(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
this.windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||||
@ -78,6 +83,8 @@ public class FloatingViewManager {
|
|||||||
this.screenWidth = screenSize.x;
|
this.screenWidth = screenSize.x;
|
||||||
this.screenHeight = screenSize.y;
|
this.screenHeight = screenSize.y;
|
||||||
this.floatingTabDialogManager = new FloatingTabDialogManager(context);
|
this.floatingTabDialogManager = new FloatingTabDialogManager(context);
|
||||||
|
this.floatingTabDialogManager.setFloatingViewManager(this);
|
||||||
|
this.eventRepository = new EventRepository(context.getApplicationContext());
|
||||||
registerBroadcastReceiver();
|
registerBroadcastReceiver();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +273,7 @@ public class FloatingViewManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建点击点视图
|
// 创建点击点视图
|
||||||
TextView point = createTouchPointView(String.valueOf(eventOrderCounter));
|
TextView pointView = createTouchPointView(String.valueOf(eventOrderCounter));
|
||||||
|
|
||||||
// 设置位置居中
|
// 设置位置居中
|
||||||
WindowManager.LayoutParams params = createTouchPointParams();
|
WindowManager.LayoutParams params = createTouchPointParams();
|
||||||
@ -274,15 +281,18 @@ public class FloatingViewManager {
|
|||||||
params.y = screenHeight / 2 - TOUCH_POINT_SIZE / 2;
|
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));
|
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.POINT, pointEvent, eventOrderCounter));
|
||||||
eventOrderCounter++;
|
eventOrderCounter++;
|
||||||
|
|
||||||
Log.d(TAG, "addPoint runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
|
Log.d(TAG, "addPoint runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
|
||||||
|
|
||||||
// 设置拖动功能并添加到窗口
|
// 设置拖动功能并添加到窗口
|
||||||
setupDraggablePoint(point, params, pointEvent);
|
setupDraggablePoint(pointView, params, pointEvent);
|
||||||
windowManager.addView(point, params);
|
windowManager.addView(pointView, params);
|
||||||
updateServicePositions();
|
updateServicePositions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,37 +304,44 @@ public class FloatingViewManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 创建起点
|
// 创建起点
|
||||||
TextView startPoint = createTouchPointView(String.valueOf(eventOrderCounter));
|
TextView startPointView = createTouchPointView(String.valueOf(eventOrderCounter));
|
||||||
WindowManager.LayoutParams startParams = createTouchPointParams();
|
WindowManager.LayoutParams startParams = createTouchPointParams();
|
||||||
startParams.x = screenWidth / 2 - 100;
|
startParams.x = screenWidth / 2 - 100;
|
||||||
startParams.y = screenHeight / 2 - 50;
|
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();
|
WindowManager.LayoutParams endParams = createTouchPointParams();
|
||||||
endParams.x = screenWidth / 2 + 100;
|
endParams.x = screenWidth / 2 + 100;
|
||||||
endParams.y = screenHeight / 2 - 50;
|
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);
|
ConnectingLineView lineView = new ConnectingLineView(context);
|
||||||
WindowManager.LayoutParams lineParams = createLineViewParams();
|
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));
|
runtimeEvents.add(new EventWrapper(EventWrapper.EventType.SLIDE, slideEvent, eventOrderCounter));
|
||||||
eventOrderCounter++;
|
eventOrderCounter++;
|
||||||
|
|
||||||
Log.d(TAG, "addSlide runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
|
Log.d(TAG, "addSlide runtimeEvents: " + runtimeEvents.size() + " eventOrderCounter :" + eventOrderCounter);
|
||||||
|
|
||||||
// 设置滑动点可拖动
|
// 设置滑动点可拖动
|
||||||
setupDraggableSlidePoint(startPoint, startParams, startPointEvent, slideEvent);
|
setupDraggableSlidePoint(startPointView, startParams, startPointEvent, slideEvent);
|
||||||
setupDraggableSlidePoint(endPoint, endParams, endPointEvent, slideEvent);
|
setupDraggableSlidePoint(endPointView, endParams, endPointEvent, slideEvent);
|
||||||
|
|
||||||
// 添加视图到窗口
|
// 添加视图到窗口
|
||||||
windowManager.addView(lineView, lineParams);
|
windowManager.addView(lineView, lineParams);
|
||||||
windowManager.addView(startPoint, startParams);
|
windowManager.addView(startPointView, startParams);
|
||||||
windowManager.addView(endPoint, endParams);
|
windowManager.addView(endPointView, endParams);
|
||||||
|
|
||||||
updateLinePosition(slideEvent); // 更新线的位置
|
updateLinePosition(slideEvent); // 更新线的位置
|
||||||
updateServicePositions();
|
updateServicePositions();
|
||||||
@ -335,9 +352,9 @@ public class FloatingViewManager {
|
|||||||
// 获取事件的视图
|
// 获取事件的视图
|
||||||
View viewToToggle = null;
|
View viewToToggle = null;
|
||||||
if (wrapper.getType() == EventWrapper.EventType.POINT) {
|
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) {
|
} 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();
|
WindowManager.LayoutParams startParams = (WindowManager.LayoutParams) startPointView.getLayoutParams();
|
||||||
if (show) {
|
if (show) {
|
||||||
@ -367,12 +384,12 @@ public class FloatingViewManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static View getView(boolean show, EventWrapper wrapper) {
|
private View getView(boolean show, EventWrapper wrapper,Context context) {
|
||||||
SlideEvent slideEvent = (SlideEvent) wrapper.getEvent();
|
SlideEvent slideEvent = (SlideEvent) wrapper.getEvent();
|
||||||
// 假设你只隐藏/显示点,线也需要同步
|
// 假设你只隐藏/显示点,线也需要同步
|
||||||
View startPointView = slideEvent.getStartPoint().getView();
|
View startPointView = createTouchPointView(String.valueOf(slideEvent.getStartPoint().getId()));
|
||||||
View endPointView = slideEvent.getEndPoint().getView();
|
View endPointView = createTouchPointView(String.valueOf(slideEvent.getEndPoint().getId()));
|
||||||
View lineView = slideEvent.getLineView();
|
View lineView = new ConnectingLineView(context);
|
||||||
|
|
||||||
if (show) {
|
if (show) {
|
||||||
// 如果是显示,可能需要重新添加或设置可见性
|
// 如果是显示,可能需要重新添加或设置可见性
|
||||||
@ -423,7 +440,7 @@ public class FloatingViewManager {
|
|||||||
PrefUtils.setFloatingShown(context, 0);
|
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);
|
intent.putExtra("isShown", false);
|
||||||
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
|
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
|
||||||
}
|
}
|
||||||
@ -788,13 +805,145 @@ public class FloatingViewManager {
|
|||||||
new BroadcastReceiver() {
|
new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
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);
|
int index = intent.getIntExtra("index", -1);
|
||||||
flashTouchPoint(index);
|
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<Long> 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<Long>() {
|
||||||
|
@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<SolutionWithEventsAndPoints>() {
|
||||||
|
@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<List<Solution>> callback) {
|
||||||
|
if (eventRepository != null) {
|
||||||
|
eventRepository.getAllSolutions(callback);
|
||||||
|
} else {
|
||||||
|
callback.onError(new IllegalStateException("EventRepository not initialized."));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -22,7 +22,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:text="@string/scripts"
|
android:text="@string/solutionList"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="32sp"
|
android:textSize="32sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:id="@+id/main"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".ui.activity.floating.TransparentFloatingActivity">
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@ -1,40 +1,38 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="321dp"
|
android:layout_width="321dp"
|
||||||
android:layout_height="386dp"
|
android:layout_height="386dp"
|
||||||
android:background="@drawable/rounded_edittext_dotted_background"
|
android:background="@drawable/rounded_edittext_background"
|
||||||
|
android:backgroundTint="@color/bg_blue"
|
||||||
|
android:orientation="vertical"
|
||||||
android:padding="8dp">
|
android:padding="8dp">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/tab_buttons_container"
|
android:id="@+id/tab_buttons_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:weightSum="2"> <Button
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="2">
|
||||||
|
|
||||||
|
<Button
|
||||||
android:id="@+id/tab_one_button"
|
android:id="@+id/tab_one_button"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="选项卡一"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:textColor="@color/black" /> <Button
|
android:text="选项卡一"
|
||||||
|
android:textColor="@color/black" />
|
||||||
|
|
||||||
|
<Button
|
||||||
android:id="@+id/tab_two_button"
|
android:id="@+id/tab_two_button"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:text="选项卡二"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:textColor="@color/gray" /> <ImageView
|
android:text="选项卡二"
|
||||||
android:id="@+id/close_dialog_button"
|
android:textColor="@color/gray" />
|
||||||
android:layout_width="30dp"
|
</LinearLayout>
|
||||||
android:layout_height="30dp"
|
|
||||||
android:src="@android:drawable/ic_menu_close_clear_cancel"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:contentDescription="关闭弹窗"
|
|
||||||
android:layout_marginStart="8dp" /> </LinearLayout>
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/content_frame"
|
android:id="@+id/content_frame"
|
||||||
@ -42,8 +40,14 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginTop="8dp">
|
android:layout_marginTop="8dp">
|
||||||
|
|
||||||
<include layout="@layout/save_script_page" android:id="@+id/page_one_view"/>
|
<include
|
||||||
<include layout="@layout/load_script_page" android:id="@+id/page_two_view" android:visibility="gone"/>
|
android:id="@+id/page_one_view"
|
||||||
|
layout="@layout/save_script_page" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/page_two_view"
|
||||||
|
layout="@layout/load_script_page"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
|||||||
@ -117,7 +117,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="12dp"
|
||||||
android:text="Save/Load scripts"
|
android:text="Save/Load solutionList"
|
||||||
android:textColor="#FFFFFF"
|
android:textColor="#FFFFFF"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
app:layout_constraintStart_toStartOf="@+id/text_play_stop"
|
app:layout_constraintStart_toStartOf="@+id/text_play_stop"
|
||||||
@ -285,7 +285,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="72dp"
|
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"
|
\nanywhere, click to edit the interval"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
@ -396,7 +396,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="25dp"
|
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
|
\nit anywhere, click on either of the two to edit the
|
||||||
\ninterval or duration"
|
\ninterval or duration"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
|
|||||||
@ -43,7 +43,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="11dp"
|
android:layout_marginTop="11dp"
|
||||||
android:text="Save/Load scripts"
|
android:text="Save/Load solutionList"
|
||||||
android:textColor="#FFFFFF"
|
android:textColor="#FFFFFF"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
app:layout_constraintStart_toStartOf="@+id/text_play_stop"
|
app:layout_constraintStart_toStartOf="@+id/text_play_stop"
|
||||||
@ -211,7 +211,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="87dp"
|
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"
|
\nit anywhere, click to edit the"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
|
|||||||
@ -9,7 +9,6 @@
|
|||||||
android:id="@+id/tip"
|
android:id="@+id/tip"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="19dp"
|
|
||||||
android:text="Enter the Script name and hit
|
android:text="Enter the Script name and hit
|
||||||
\nsave button"
|
\nsave button"
|
||||||
android:textColor="@color/text_gray"
|
android:textColor="@color/text_gray"
|
||||||
|
|||||||
@ -16,8 +16,8 @@
|
|||||||
<string name="other">Other</string>
|
<string name="other">Other</string>
|
||||||
<string name="title">Title</string>
|
<string name="title">Title</string>
|
||||||
<string name="subtitle">Subtitle</string>
|
<string name="subtitle">Subtitle</string>
|
||||||
<string name="scripts">Scripts</string>
|
<string name="solutionList">Scripts</string>
|
||||||
<string name="no_scripts_text">Your saved scripts \nwill be shown here</string>
|
<string name="no_scripts_text">Your saved solutionList \nwill be shown here</string>
|
||||||
<string name="create_now">Create Now</string>
|
<string name="create_now">Create Now</string>
|
||||||
<string name="import_scripts">Import</string>
|
<string name="import_scripts">Import</string>
|
||||||
<string name="accessibility">Accessibility</string>
|
<string name="accessibility">Accessibility</string>
|
||||||
|
|||||||
@ -6,19 +6,5 @@
|
|||||||
<item name="android:windowBackground">@drawable/activity_background</item>
|
<item name="android:windowBackground">@drawable/activity_background</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.TransparentOverlay" parent="Theme.Material3.DayNight.Dialog">
|
|
||||||
<item name="android:windowIsTranslucent">true</item>
|
|
||||||
<item name="android:windowBackground">@android:color/transparent</item>
|
|
||||||
<item name="android:windowContentOverlay">@null</item>
|
|
||||||
<item name="android:windowNoTitle">true</item>
|
|
||||||
<item name="android:windowIsFloating">true</item>
|
|
||||||
<item name="android:backgroundDimEnabled">false</item>
|
|
||||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
|
||||||
<item name="android:windowFullscreen">false</item>
|
|
||||||
<item name="android:gravity">center</item>
|
|
||||||
<item name="android:windowAnimationStyle">@android:style/Animation</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
<style name="Theme.AutoClicker" parent="Base.Theme.AutoClicker" />
|
<style name="Theme.AutoClicker" parent="Base.Theme.AutoClicker" />
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
Reference in New Issue
Block a user