功能添加
This commit is contained in:
parent
452f1d6377
commit
27727eaff0
@ -50,4 +50,6 @@ dependencies {
|
|||||||
|
|
||||||
implementation ("androidx.room:room-runtime:2.7.1")
|
implementation ("androidx.room:room-runtime:2.7.1")
|
||||||
annotationProcessor ("androidx.room:room-compiler:2.7.1")
|
annotationProcessor ("androidx.room:room-compiler:2.7.1")
|
||||||
|
|
||||||
|
implementation("com.google.code.gson:gson:2.12.1")
|
||||||
}
|
}
|
||||||
@ -13,6 +13,7 @@ public class MyApplication extends Application {
|
|||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
application = this;
|
application = this;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Context getContext() {
|
public static Context getContext() {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package com.auto.clicker.autoclicker.room.repository;
|
package com.auto.clicker.autoclicker.room.repository;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.auto.clicker.autoclicker.data.Event;
|
import com.auto.clicker.autoclicker.data.Event;
|
||||||
import com.auto.clicker.autoclicker.data.EventWrapper;
|
import com.auto.clicker.autoclicker.data.EventWrapper;
|
||||||
@ -9,34 +10,26 @@ import com.auto.clicker.autoclicker.data.SlideEvent;
|
|||||||
import com.auto.clicker.autoclicker.room.AppDatabase;
|
import com.auto.clicker.autoclicker.room.AppDatabase;
|
||||||
import com.auto.clicker.autoclicker.room.SolutionWithEventsAndPoints;
|
import com.auto.clicker.autoclicker.room.SolutionWithEventsAndPoints;
|
||||||
import com.auto.clicker.autoclicker.room.dao.EventEntityDao;
|
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.dao.SolutionDao;
|
||||||
|
import com.auto.clicker.autoclicker.room.dao.TouchPointDao;
|
||||||
import com.auto.clicker.autoclicker.room.entity.EventEntity;
|
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 com.auto.clicker.autoclicker.room.entity.Solution;
|
||||||
|
import com.auto.clicker.autoclicker.room.entity.TouchPoint;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
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 {
|
public class EventRepository {
|
||||||
private final SolutionDao solutionDao;
|
private final SolutionDao solutionDao;
|
||||||
private final TouchPointDao touchPointDao; // Renamed from PointDao
|
private final TouchPointDao touchPointDao;
|
||||||
private final EventEntityDao eventEntityDao;
|
private final EventEntityDao eventEntityDao;
|
||||||
private final ExecutorService databaseWriteExecutor;
|
private final ExecutorService databaseWriteExecutor;
|
||||||
|
|
||||||
public EventRepository(Context context) {
|
public EventRepository(Context context) {
|
||||||
AppDatabase db = AppDatabase.getInstance(context); // Updated to getInstance
|
AppDatabase db = AppDatabase.getInstance(context); // Updated to getInstance
|
||||||
this.solutionDao = db.solutionDao();
|
this.solutionDao = db.solutionDao();
|
||||||
this.touchPointDao = db.pointDao(); // Assuming db.pointDao() returns TouchPointDao now
|
this.touchPointDao = db.pointDao();
|
||||||
this.eventEntityDao = db.eventEntityDao();
|
this.eventEntityDao = db.eventEntityDao();
|
||||||
this.databaseWriteExecutor = Executors.newFixedThreadPool(2);
|
this.databaseWriteExecutor = Executors.newFixedThreadPool(2);
|
||||||
}
|
}
|
||||||
@ -147,20 +140,36 @@ public class EventRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 删除操作 ---
|
// public void deleteSolution(Solution solution, RepositoryCallback<Integer> callback) {
|
||||||
public void deleteSolution(Solution solution, RepositoryCallback<Integer> callback) {
|
// databaseWriteExecutor.execute(() -> {
|
||||||
databaseWriteExecutor.execute(() -> {
|
// try {
|
||||||
try {
|
// int rowsAffected = solutionDao.deleteSolution(solution);
|
||||||
int rowsAffected = solutionDao.deleteSolution(solution);
|
// if (callback != null) callback.onComplete(rowsAffected);
|
||||||
if (callback != null) callback.onComplete(rowsAffected);
|
// } catch (Exception e) {
|
||||||
} catch (Exception e) {
|
// Log.e("EventRepository", "Error deleting solution: " + e.getMessage(), e);
|
||||||
Log.e("EventRepository", "Error deleting solution: " + e.getMessage(), e);
|
// if (callback != null) callback.onError(e);
|
||||||
if (callback != null) callback.onError(e);
|
// }
|
||||||
}
|
// });
|
||||||
});
|
// }
|
||||||
|
|
||||||
|
public void updateSolutionName(long solutionId, String newName, RepositoryCallback<Void> callback) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteSolution(long solutionId, RepositoryCallback<Void> callback) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用于复制方案,需要保存一个新的方案以及其关联的事件和点
|
||||||
|
public void saveSolutionWithEventsAndPoints(Solution solution, List<SolutionWithEventsAndPoints.EventWithPoints> eventsWithPoints, RepositoryCallback<Void> callback) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取某个方案及其所有事件和点的数据
|
||||||
|
public void getSolutionWithEventsAndPoints(String solutionId, RepositoryCallback<SolutionWithEventsAndPoints> callback) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 假设的回调接口,可以根据需要自定义
|
|
||||||
public interface RepositoryCallback<T> {
|
public interface RepositoryCallback<T> {
|
||||||
void onComplete(T result);
|
void onComplete(T result);
|
||||||
|
|
||||||
|
|||||||
@ -48,6 +48,11 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
private int slideDuration = 500;
|
private int slideDuration = 500;
|
||||||
private int currentEventIndex = 0;
|
private int currentEventIndex = 0;
|
||||||
|
|
||||||
|
private int loopCount = 1;
|
||||||
|
private long loopTimeMillis = 0;
|
||||||
|
private long startTimeMillis;
|
||||||
|
private int currentLoop = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
@ -122,6 +127,46 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
logDebug("设置滑动时长: " + duration + "ms");
|
logDebug("设置滑动时长: " + duration + "ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置事件队列的循环次数。
|
||||||
|
*
|
||||||
|
* @param count 循环次数。设置为0表示无限循环,设置为1表示不循环(执行一次)。
|
||||||
|
*/
|
||||||
|
public void setLoopCount(int count) {
|
||||||
|
if (count < 0) {
|
||||||
|
Log.w(TAG, "循环次数不能为负数,已设置为默认值 1");
|
||||||
|
this.loopCount = 1;
|
||||||
|
} else {
|
||||||
|
this.loopCount = count;
|
||||||
|
}
|
||||||
|
logDebug("设置循环次数: " + loopCount + " 次");
|
||||||
|
// 如果设置了循环次数,则重置循环时间为0,确保两种模式不冲突
|
||||||
|
if (this.loopCount > 0) {
|
||||||
|
this.loopTimeMillis = 0;
|
||||||
|
logDebug("已重置循环时间为 0ms");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置事件队列的循环总时间。
|
||||||
|
*
|
||||||
|
* @param timeMillis 循环总时间,单位毫秒。设置为0表示不按时间循环。
|
||||||
|
*/
|
||||||
|
public void setLoopTime(long timeMillis) {
|
||||||
|
if (timeMillis < 0) {
|
||||||
|
Log.w(TAG, "循环时间不能为负数,已设置为默认值 0ms");
|
||||||
|
this.loopTimeMillis = 0;
|
||||||
|
} else {
|
||||||
|
this.loopTimeMillis = timeMillis;
|
||||||
|
}
|
||||||
|
logDebug("设置循环时间: " + loopTimeMillis + "ms");
|
||||||
|
// 如果设置了循环时间,则重置循环次数为0,确保两种模式不冲突
|
||||||
|
if (this.loopTimeMillis > 0) {
|
||||||
|
this.loopCount = 0;
|
||||||
|
logDebug("已重置循环次数为 0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void startClicking() {
|
public void startClicking() {
|
||||||
if (!isRunning) {
|
if (!isRunning) {
|
||||||
if (runtimeEvents.isEmpty()) {
|
if (runtimeEvents.isEmpty()) {
|
||||||
@ -131,10 +176,22 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
|
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
currentEventIndex = 0;
|
currentEventIndex = 0;
|
||||||
|
currentLoop = 0; // 重置循环计数
|
||||||
|
startTimeMillis = System.currentTimeMillis(); // 记录开始时间
|
||||||
|
|
||||||
EventViewBinder.setAllTouchPointsDraggable(false);
|
EventViewBinder.setAllTouchPointsDraggable(false);
|
||||||
|
|
||||||
logDebug("开始执行事件队列 - 共 " + runtimeEvents.size() + " 个事件");
|
// 根据循环设置调整日志输出
|
||||||
|
String loopInfo;
|
||||||
|
if (loopCount > 0) {
|
||||||
|
loopInfo = "循环 " + (loopCount == 1 ? "1 次" : loopCount + " 次");
|
||||||
|
} else if (loopTimeMillis > 0) {
|
||||||
|
loopInfo = "循环 " + (loopTimeMillis / 1000) + " 秒";
|
||||||
|
} else {
|
||||||
|
loopInfo = "无限循环"; // 如果两者都为0
|
||||||
|
}
|
||||||
|
logDebug("开始执行事件队列 - 共 " + runtimeEvents.size() + " 个事件. " + loopInfo);
|
||||||
|
|
||||||
executeEventsByType();
|
executeEventsByType();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,6 +203,11 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
|
|
||||||
EventViewBinder.setAllTouchPointsDraggable(true);
|
EventViewBinder.setAllTouchPointsDraggable(true);
|
||||||
|
|
||||||
|
// 重置循环状态
|
||||||
|
currentEventIndex = 0; // 停止时重置事件索引
|
||||||
|
currentLoop = 0; // 停止时重置循环计数
|
||||||
|
startTimeMillis = 0; // 停止时重置开始时间
|
||||||
|
|
||||||
logDebug("停止执行事件");
|
logDebug("停止执行事件");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,15 +217,52 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void executeEventsByType() {
|
private void executeEventsByType() {
|
||||||
if (!isRunning || runtimeEvents.isEmpty()) {
|
if (!isRunning) {
|
||||||
logDebug("跳过执行:服务未运行或事件队列为空");
|
logDebug("跳过执行:服务未运行");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (runtimeEvents.isEmpty()) {
|
||||||
|
logDebug("跳过执行:事件队列为空");
|
||||||
|
stopClicking(); // 如果事件队列为空,则停止服务
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在每一轮循环开始前排序,确保顺序正确
|
||||||
runtimeEvents.sort(Comparator.comparingInt(EventWrapper::getOrder));
|
runtimeEvents.sort(Comparator.comparingInt(EventWrapper::getOrder));
|
||||||
|
|
||||||
|
// 检查是否完成了一轮事件列表
|
||||||
if (currentEventIndex >= runtimeEvents.size()) {
|
if (currentEventIndex >= runtimeEvents.size()) {
|
||||||
currentEventIndex = 0;
|
currentEventIndex = 0; // 重置事件索引,准备开始新一轮循环
|
||||||
|
currentLoop++; // 完成一轮,增加循环计数
|
||||||
|
logDebug("完成第 " + currentLoop + " 轮事件执行。");
|
||||||
|
|
||||||
|
// 判断是否继续循环
|
||||||
|
boolean continueLoop = false;
|
||||||
|
if (loopCount > 0) { // 按次数循环模式
|
||||||
|
if (currentLoop < loopCount) {
|
||||||
|
continueLoop = true;
|
||||||
|
logDebug("继续第 " + (currentLoop + 1) + " 轮循环 (共 " + loopCount + " 轮)");
|
||||||
|
} else {
|
||||||
|
logDebug("已达到设定的循环次数 (" + loopCount + " 次),停止循环。");
|
||||||
|
}
|
||||||
|
} else if (loopTimeMillis > 0) { // 按时间循环模式
|
||||||
|
long elapsedTime = System.currentTimeMillis() - startTimeMillis;
|
||||||
|
if (elapsedTime < loopTimeMillis) {
|
||||||
|
continueLoop = true;
|
||||||
|
logDebug("继续循环 (已用时 " + (elapsedTime / 1000) + "s, 总时长 " + (loopTimeMillis / 1000) + "s)");
|
||||||
|
} else {
|
||||||
|
logDebug("已达到设定的循环时间 (" + (loopTimeMillis / 1000) + "s),停止循环。");
|
||||||
|
}
|
||||||
|
} else { // 无限循环模式 (loopCount == 0 && loopTimeMillis == 0)
|
||||||
|
continueLoop = true;
|
||||||
|
logDebug("无限循环模式,继续下一轮循环。");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!continueLoop) {
|
||||||
|
stopClicking(); // 不再继续循环,则停止服务
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EventWrapper wrapper = runtimeEvents.get(currentEventIndex);
|
EventWrapper wrapper = runtimeEvents.get(currentEventIndex);
|
||||||
@ -175,8 +274,8 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
performSlide((SlideEvent) event);
|
performSlide((SlideEvent) event);
|
||||||
} else {
|
} else {
|
||||||
logDebug("未知或不匹配的事件类型,跳过执行: " + wrapper.getType());
|
logDebug("未知或不匹配的事件类型,跳过执行: " + wrapper.getType());
|
||||||
currentEventIndex++;
|
currentEventIndex++; // 跳过当前事件
|
||||||
handler.postDelayed(this::executeEventsByType, clickInterval);
|
handler.postDelayed(this::executeEventsByType, clickInterval); // 立即尝试下一个事件
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +305,8 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
logDebug("点击完成");
|
logDebug("点击完成");
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
int feedbackIndex = currentEventIndex;
|
int feedbackIndex = currentEventIndex;
|
||||||
currentEventIndex++;
|
currentEventIndex++; // 事件索引递增
|
||||||
|
// 延迟执行下一个事件,循环逻辑在executeEventsByType中处理
|
||||||
handler.postDelayed(() -> executeEventsByType(), clickInterval);
|
handler.postDelayed(() -> executeEventsByType(), clickInterval);
|
||||||
flashTouchFeedback(feedbackIndex);
|
flashTouchFeedback(feedbackIndex);
|
||||||
}
|
}
|
||||||
@ -216,7 +316,8 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
public void onCancelled(GestureDescription gestureDescription) {
|
public void onCancelled(GestureDescription gestureDescription) {
|
||||||
Log.e(TAG, "点击被取消");
|
Log.e(TAG, "点击被取消");
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
currentEventIndex++;
|
currentEventIndex++; // 事件索引递增
|
||||||
|
// 延迟执行下一个事件
|
||||||
handler.postDelayed(() -> executeEventsByType(), clickInterval + 300);
|
handler.postDelayed(() -> executeEventsByType(), clickInterval + 300);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,12 +366,12 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
logDebug("滑动完成");
|
logDebug("滑动完成");
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
int feedbackIndex = currentEventIndex;
|
int feedbackIndex = currentEventIndex;
|
||||||
currentEventIndex++;
|
currentEventIndex++; // 事件索引递增
|
||||||
|
// 延迟执行下一个事件
|
||||||
handler.postDelayed(() -> executeEventsByType(), clickInterval);
|
handler.postDelayed(() -> executeEventsByType(), clickInterval);
|
||||||
flashTouchFeedback(feedbackIndex);
|
flashTouchFeedback(feedbackIndex);
|
||||||
}
|
}
|
||||||
logDebug("--- onCompleted: 下一个事件将是 index " + currentEventIndex + " ---");
|
logDebug("--- onCompleted: 下一个事件将是 index " + currentEventIndex + " ---");
|
||||||
// 再次打印,确认 slideEvent.getStartPoint() 和 getEndPoint() 是否被意外修改
|
|
||||||
logDebug("onCompleted 后,SlideEvent 起点: (" + slideEvent.getStartPoint().getX() + ", " + slideEvent.getStartPoint().getY() + ")");
|
logDebug("onCompleted 后,SlideEvent 起点: (" + slideEvent.getStartPoint().getX() + ", " + slideEvent.getStartPoint().getY() + ")");
|
||||||
logDebug("onCompleted 后,SlideEvent 终点: (" + slideEvent.getEndPoint().getX() + ", " + slideEvent.getEndPoint().getY() + ")");
|
logDebug("onCompleted 后,SlideEvent 终点: (" + slideEvent.getEndPoint().getX() + ", " + slideEvent.getEndPoint().getY() + ")");
|
||||||
}
|
}
|
||||||
@ -279,11 +380,11 @@ public class AutoClickService extends AccessibilityService {
|
|||||||
public void onCancelled(GestureDescription gestureDescription) {
|
public void onCancelled(GestureDescription gestureDescription) {
|
||||||
Log.e(TAG, "滑动被取消");
|
Log.e(TAG, "滑动被取消");
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
currentEventIndex++;
|
currentEventIndex++; // 事件索引递增
|
||||||
|
// 延迟执行下一个事件
|
||||||
handler.postDelayed(() -> executeEventsByType(), clickInterval + 300);
|
handler.postDelayed(() -> executeEventsByType(), clickInterval + 300);
|
||||||
}
|
}
|
||||||
logDebug("--- onCancelled: 下一个事件将是 index " + currentEventIndex + " ---");
|
logDebug("--- onCancelled: 下一个事件将是 index " + currentEventIndex + " ---");
|
||||||
// 再次打印,确认 slideEvent.getStartPoint() 和 getEndPoint() 是否被意外修改
|
|
||||||
logDebug("onCancelled 后,SlideEvent 起点: (" + slideEvent.getStartPoint().getX() + ", " + slideEvent.getStartPoint().getY() + ")");
|
logDebug("onCancelled 后,SlideEvent 起点: (" + slideEvent.getStartPoint().getX() + ", " + slideEvent.getStartPoint().getY() + ")");
|
||||||
logDebug("onCancelled 后,SlideEvent 终点: (" + slideEvent.getEndPoint().getX() + ", " + slideEvent.getEndPoint().getY() + ")");
|
logDebug("onCancelled 后,SlideEvent 终点: (" + slideEvent.getEndPoint().getX() + ", " + slideEvent.getEndPoint().getY() + ")");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import android.widget.VideoView;
|
|||||||
import androidx.activity.EdgeToEdge;
|
import androidx.activity.EdgeToEdge;
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts;
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.core.graphics.Insets;
|
import androidx.core.graphics.Insets;
|
||||||
@ -57,12 +58,14 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
private int isFloatingShown;
|
private int isFloatingShown;
|
||||||
private int selectedFloatingMode = FLOATING_SINGLE;
|
private int selectedFloatingMode = FLOATING_SINGLE;
|
||||||
|
|
||||||
|
public static final String EXTRA_FLOATING_MODE = "extra_floating_mode";
|
||||||
|
|
||||||
private final BroadcastReceiver floatingReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver floatingReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
isFloatingShown = intent.getIntExtra("isShown", FLOATING_NONE);
|
isFloatingShown = intent.getIntExtra("isShown", FLOATING_NONE);
|
||||||
logDebug("接收到浮窗状态广播: isShown = " + isFloatingShown);
|
logDebug("接收到浮窗状态广播: isShown = " + isFloatingShown);
|
||||||
|
|
||||||
if (isFloatingShown == FLOATING_NONE) {
|
if (isFloatingShown == FLOATING_NONE) {
|
||||||
} else {
|
} else {
|
||||||
selectedFloatingMode = isFloatingShown;
|
selectedFloatingMode = isFloatingShown;
|
||||||
@ -160,6 +163,29 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
logDebug("选择多点模式. selectedFloatingMode=" + selectedFloatingMode);
|
logDebug("选择多点模式. selectedFloatingMode=" + selectedFloatingMode);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
handleIncomingIntent(getIntent());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNewIntent(@NonNull Intent intent) {
|
||||||
|
super.onNewIntent(intent);
|
||||||
|
// 如果 MainActivity 已经在运行,并且再次通过 Intent 启动,会调用 onNewIntent
|
||||||
|
setIntent(intent); // 更新当前的 Intent
|
||||||
|
handleIncomingIntent(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleIncomingIntent(Intent intent) {
|
||||||
|
int mode = intent.getIntExtra(EXTRA_FLOATING_MODE, FLOATING_NONE);
|
||||||
|
Log.d(TAG, "mode: " + mode);
|
||||||
|
if (mode != FLOATING_NONE) {
|
||||||
|
if (mode == FLOATING_SINGLE) {
|
||||||
|
binding.single.performClick();
|
||||||
|
binding.animatedView.performClick();
|
||||||
|
} else if (mode == FLOATING_MULTI) {
|
||||||
|
binding.multi.performClick();
|
||||||
|
binding.animatedView.performClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkPermissions() {
|
private void checkPermissions() {
|
||||||
@ -173,7 +199,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
logDebug("无障碍服务未启用,请求权限");
|
logDebug("无障碍服务未启用,请求权限");
|
||||||
showPermissionRequest(Settings.ACTION_ACCESSIBILITY_SETTINGS, "请启用无障碍服务以便应用正常工作", "无法打开无障碍设置");
|
showPermissionRequest(Settings.ACTION_ACCESSIBILITY_SETTINGS, "请启用无障碍服务以便应用正常工作", "无法打开无障碍设置");
|
||||||
setStartButtonEnabled(false);
|
setStartButtonEnabled(false);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +208,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
|
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
|
||||||
showPermissionRequest(intent, "请授予悬浮窗权限,否则无法显示浮窗", "无法打开悬浮窗设置");
|
showPermissionRequest(intent, "请授予悬浮窗权限,否则无法显示浮窗", "无法打开悬浮窗设置");
|
||||||
setStartButtonEnabled(false);
|
setStartButtonEnabled(false);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,13 +218,13 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
intent.setData(Uri.parse("package:" + getPackageName()));
|
intent.setData(Uri.parse("package:" + getPackageName()));
|
||||||
showPermissionRequest(intent, "请禁用电池优化,以确保应用在后台稳定运行", "无法打开电池优化设置");
|
showPermissionRequest(intent, "请禁用电池优化,以确保应用在后台稳定运行", "无法打开电池优化设置");
|
||||||
setStartButtonEnabled(false);
|
setStartButtonEnabled(false);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logDebug("所有权限均已授予");
|
logDebug("所有权限均已授予");
|
||||||
setStartButtonEnabled(true);
|
setStartButtonEnabled(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showPermissionRequest(String action, String toastMessage, String errorMessage) {
|
private void showPermissionRequest(String action, String toastMessage, String errorMessage) {
|
||||||
@ -253,7 +279,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
logDebug("同步服务状态: 当前浮窗模式 = " + currentFloatingMode);
|
logDebug("同步服务状态: 当前浮窗模式 = " + currentFloatingMode);
|
||||||
isFloatingShown = currentFloatingMode;
|
isFloatingShown = currentFloatingMode;
|
||||||
PrefUtils.setFloatingShown(this, isFloatingShown);
|
PrefUtils.setFloatingShown(this, isFloatingShown);
|
||||||
|
|
||||||
updateSelectionButtons();
|
updateSelectionButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,14 +312,14 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
lastClickTime = currentTime;
|
lastClickTime = currentTime;
|
||||||
logDebug("点击启动/隐藏浮窗按钮. 当前 isFloatingShown=" + isFloatingShown + ", selectedFloatingMode=" + selectedFloatingMode);
|
logDebug("点击启动/隐藏浮窗按钮. 当前 isFloatingShown=" + isFloatingShown + ", selectedFloatingMode=" + selectedFloatingMode);
|
||||||
|
|
||||||
if (!isAccessibilityServiceEnabled() || !Settings.canDrawOverlays(this) || !isIgnoringBatteryOptimizations()) {
|
if (!isAccessibilityServiceEnabled() || !Settings.canDrawOverlays(this) || !isIgnoringBatteryOptimizations()) {
|
||||||
Toast.makeText(this, "请授予所有必要权限", Toast.LENGTH_LONG).show();
|
Toast.makeText(this, "请授予所有必要权限", Toast.LENGTH_LONG).show();
|
||||||
checkPermissions();
|
checkPermissions();
|
||||||
logDebug("权限不足,无法启动浮窗,重新检查权限");
|
logDebug("权限不足,无法启动浮窗,重新检查权限");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFloatingShown != FLOATING_NONE && isFloatingShown != selectedFloatingMode) {
|
if (isFloatingShown != FLOATING_NONE && isFloatingShown != selectedFloatingMode) {
|
||||||
Toast.makeText(this, "已显示其他悬浮窗,请先关闭", Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, "已显示其他悬浮窗,请先关闭", Toast.LENGTH_SHORT).show();
|
||||||
logDebug("已显示其他模式的浮窗,请先关闭");
|
logDebug("已显示其他模式的浮窗,请先关闭");
|
||||||
|
|||||||
@ -1,19 +1,48 @@
|
|||||||
package com.auto.clicker.autoclicker.ui.activity.menu;
|
package com.auto.clicker.autoclicker.ui.activity.menu;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.EdgeToEdge;
|
import androidx.activity.EdgeToEdge;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.graphics.Insets;
|
import androidx.core.graphics.Insets;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
|
||||||
import com.auto.clicker.autoclicker.R;
|
import com.auto.clicker.autoclicker.R;
|
||||||
import com.auto.clicker.autoclicker.databinding.ActivityFeedbackBinding;
|
|
||||||
import com.auto.clicker.autoclicker.databinding.ActivityScriptsBinding;
|
import com.auto.clicker.autoclicker.databinding.ActivityScriptsBinding;
|
||||||
|
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.ui.adapter.floating.SolutionAdapter;
|
||||||
|
import com.auto.clicker.autoclicker.ui.dialog.CreateModeSelectionDialog;
|
||||||
|
import com.auto.clicker.autoclicker.view.FloatingViewManager;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
public class ScriptsActivity extends AppCompatActivity {
|
import java.io.OutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class ScriptsActivity extends AppCompatActivity implements SolutionAdapter.OnOptionMenuClickListener {
|
||||||
private ActivityScriptsBinding binding;
|
private ActivityScriptsBinding binding;
|
||||||
|
private SolutionAdapter solutionsAdapter;
|
||||||
|
private FloatingViewManager floatingViewManager;
|
||||||
|
|
||||||
|
private static final String TAG = "ScriptsActivity";
|
||||||
|
private static final int CREATE_FILE_REQUEST_CODE = 1; // 用于导出文件的请求码
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@ -27,6 +56,336 @@ public class ScriptsActivity extends AppCompatActivity {
|
|||||||
return insets;
|
return insets;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
binding.scriptsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
// 传入 this 作为 OnOptionMenuClickListener 的实现
|
||||||
|
solutionsAdapter = new SolutionAdapter(new ArrayList<>(), this::onSolutionSelected, this);
|
||||||
|
binding.scriptsRecyclerView.setAdapter(solutionsAdapter);
|
||||||
|
|
||||||
|
floatingViewManager = new FloatingViewManager(this);
|
||||||
|
|
||||||
binding.btnBack.setOnClickListener(v -> finish());
|
binding.btnBack.setOnClickListener(v -> finish());
|
||||||
|
|
||||||
|
binding.create.setOnClickListener(v -> {
|
||||||
|
CreateModeSelectionDialog dialog = new CreateModeSelectionDialog();
|
||||||
|
dialog.show(getSupportFragmentManager(), "CreateModeSelectionDialog");
|
||||||
|
});
|
||||||
|
|
||||||
|
binding.importScripts.setOnClickListener(v -> {
|
||||||
|
Toast.makeText(this, "导入方案功能待实现", Toast.LENGTH_SHORT).show();
|
||||||
|
// TODO: 实现导入方案的逻辑
|
||||||
|
});
|
||||||
|
|
||||||
|
binding.fabImportScripts.setOnClickListener(v -> {
|
||||||
|
Toast.makeText(this, "右下角导入方案功能待实现", Toast.LENGTH_SHORT).show();
|
||||||
|
// TODO: 实现右下角导入方案的逻辑,可能与上面的importScripts按钮功能相同或类似
|
||||||
|
});
|
||||||
|
|
||||||
|
loadSolutions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
loadSolutions();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadSolutions() {
|
||||||
|
if (floatingViewManager == null) {
|
||||||
|
Log.e(TAG, "FloatingViewManager 未设置,无法加载方案列表。");
|
||||||
|
Toast.makeText(this, "加载方案列表功能不可用,请联系开发者。", Toast.LENGTH_SHORT).show();
|
||||||
|
updateLayout(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
floatingViewManager.getAllSolutions(new EventRepository.RepositoryCallback<List<Solution>>() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(List<Solution> solutions) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
solutionsAdapter.setSolutions(solutions);
|
||||||
|
updateLayout(solutions.isEmpty());
|
||||||
|
if (solutions.isEmpty()) {
|
||||||
|
Toast.makeText(ScriptsActivity.this, "没有可加载的方案。", Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(ScriptsActivity.this, "方案加载成功!", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
Log.e(TAG, "加载方案列表失败: " + e.getMessage(), e);
|
||||||
|
Toast.makeText(ScriptsActivity.this, "加载方案列表失败。", Toast.LENGTH_SHORT).show();
|
||||||
|
updateLayout(true); // 加载失败也显示无方案视图
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLayout(boolean isEmpty) {
|
||||||
|
if (isEmpty) {
|
||||||
|
binding.noScriptsGroup.setVisibility(View.VISIBLE);
|
||||||
|
binding.scriptsRecyclerView.setVisibility(View.GONE);
|
||||||
|
binding.fabImportScripts.setVisibility(View.GONE);
|
||||||
|
} else {
|
||||||
|
binding.noScriptsGroup.setVisibility(View.GONE);
|
||||||
|
binding.scriptsRecyclerView.setVisibility(View.VISIBLE);
|
||||||
|
binding.fabImportScripts.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSolutionSelected(Solution solution) {
|
||||||
|
if (floatingViewManager != null) {
|
||||||
|
floatingViewManager.showFloatingViews(solution.getMode());
|
||||||
|
floatingViewManager.loadSolution(solution.getSolutionId());
|
||||||
|
Toast.makeText(this, "正在加载方案: " + solution.getSolutionName(), Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "FloatingViewManager 未设置!无法加载方案。");
|
||||||
|
Toast.makeText(this, "加载功能不可用,请联系开发者。", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 实现 SolutionAdapter.OnOptionMenuClickListener 接口的方法 ---
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRenameClick(Solution solution) {
|
||||||
|
// 实现重命名逻辑
|
||||||
|
showRenameDialog(solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDuplicateClick(Solution solution) {
|
||||||
|
// 实现复制逻辑
|
||||||
|
duplicateSolution(solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDeleteClick(Solution solution) {
|
||||||
|
// 实现删除逻辑
|
||||||
|
showDeleteConfirmationDialog(solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onExportClick(Solution solution) {
|
||||||
|
// 实现导出逻辑
|
||||||
|
exportSolution(solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showRenameDialog(final Solution solution) {
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
|
builder.setTitle("重命名方案");
|
||||||
|
|
||||||
|
final EditText input = new EditText(this);
|
||||||
|
input.setText(solution.getSolutionName());
|
||||||
|
builder.setView(input);
|
||||||
|
|
||||||
|
builder.setPositiveButton("确定", (dialog, which) -> {
|
||||||
|
String newName = input.getText().toString().trim();
|
||||||
|
if (!newName.isEmpty() && !newName.equals(solution.getSolutionName())) {
|
||||||
|
// 调用 EventRepository 更新方案名称
|
||||||
|
floatingViewManager.getEventRepository().updateSolutionName(solution.getSolutionId(), newName, new EventRepository.RepositoryCallback<Void>() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(Void result) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
Toast.makeText(ScriptsActivity.this, "方案已重命名为: " + newName, Toast.LENGTH_SHORT).show();
|
||||||
|
loadSolutions(); // 刷新列表
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
Log.e(TAG, "重命名失败: " + e.getMessage(), e);
|
||||||
|
Toast.makeText(ScriptsActivity.this, "重命名失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (newName.isEmpty()) {
|
||||||
|
Toast.makeText(ScriptsActivity.this, "方案名称不能为空。", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton("取消", (dialog, which) -> dialog.cancel());
|
||||||
|
builder.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void duplicateSolution(final Solution originalSolution) {
|
||||||
|
floatingViewManager.getEventRepository().getSolutionWithEventsAndPoints(originalSolution.getSolutionId(), new EventRepository.RepositoryCallback<SolutionWithEventsAndPoints>() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(SolutionWithEventsAndPoints originalData) {
|
||||||
|
if (originalData != null && originalData.solution != null) {
|
||||||
|
// 创建新的 Solution 对象
|
||||||
|
Solution newSolution = new Solution();
|
||||||
|
newSolution.setSolutionId(UUID.randomUUID().toString()); // 生成新的ID
|
||||||
|
newSolution.setSolutionName(originalSolution.getSolutionName() + " (1)");
|
||||||
|
newSolution.setMode(originalSolution.getMode());
|
||||||
|
|
||||||
|
// 复制事件和点(深拷贝)
|
||||||
|
List<SolutionWithEventsAndPoints.EventWithPoints> newEventsWithPoints = new ArrayList<>();
|
||||||
|
if (originalData.events != null) {
|
||||||
|
for (SolutionWithEventsAndPoints.EventWithPoints originalEvent : originalData.events) {
|
||||||
|
SolutionWithEventsAndPoints.EventWithPoints newEvent = new SolutionWithEventsAndPoints.EventWithPoints();
|
||||||
|
// 复制 EventEntity
|
||||||
|
newEvent.eventEntity = new EventEntity();
|
||||||
|
newEvent.eventEntity.eventId = UUID.randomUUID().toString(); // 新的事件ID
|
||||||
|
newEvent.eventEntity.solutionId = newSolution.getSolutionId(); // 关联新的方案ID
|
||||||
|
newEvent.eventEntity.eventType = originalEvent.eventEntity.eventType;
|
||||||
|
newEvent.eventEntity.orderInSolution = originalEvent.eventEntity.orderInSolution;
|
||||||
|
|
||||||
|
// 复制 TouchPoint
|
||||||
|
if (originalEvent.clickTouchPoint != null) {
|
||||||
|
newEvent.clickTouchPoint = new TouchPoint();
|
||||||
|
newEvent.clickTouchPoint.pointId = UUID.randomUUID().toString(); // 新的点ID
|
||||||
|
newEvent.clickTouchPoint.eventId = newEvent.eventEntity.eventId; // 关联新的事件ID
|
||||||
|
newEvent.clickTouchPoint.x = originalEvent.clickTouchPoint.x;
|
||||||
|
newEvent.clickTouchPoint.y = originalEvent.clickTouchPoint.y;
|
||||||
|
newEvent.clickTouchPoint.pointOrder = originalEvent.clickTouchPoint.pointOrder;
|
||||||
|
}
|
||||||
|
if (originalEvent.slideStartTouchPoint != null) {
|
||||||
|
newEvent.slideStartTouchPoint = new TouchPoint();
|
||||||
|
newEvent.slideStartTouchPoint.pointId = UUID.randomUUID().toString(); // 新的点ID
|
||||||
|
newEvent.slideStartTouchPoint.eventId = newEvent.eventEntity.eventId; // 关联新的事件ID
|
||||||
|
newEvent.slideStartTouchPoint.x = originalEvent.slideStartTouchPoint.x;
|
||||||
|
newEvent.slideStartTouchPoint.y = originalEvent.slideStartTouchPoint.y;
|
||||||
|
newEvent.slideStartTouchPoint.pointOrder = originalEvent.slideStartTouchPoint.pointOrder;
|
||||||
|
}
|
||||||
|
if (originalEvent.slideEndTouchPoint != null) {
|
||||||
|
newEvent.slideEndTouchPoint = new TouchPoint();
|
||||||
|
newEvent.slideEndTouchPoint.pointId = UUID.randomUUID().toString(); // 新的点ID
|
||||||
|
newEvent.slideEndTouchPoint.eventId = newEvent.eventEntity.eventId; // 关联新的事件ID
|
||||||
|
newEvent.slideEndTouchPoint.x = originalEvent.slideEndTouchPoint.x;
|
||||||
|
newEvent.slideEndTouchPoint.y = originalEvent.slideEndTouchPoint.y;
|
||||||
|
newEvent.slideEndTouchPoint.pointOrder = originalEvent.slideEndTouchPoint.pointOrder;
|
||||||
|
}
|
||||||
|
newEventsWithPoints.add(newEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存新的方案及其事件和点
|
||||||
|
floatingViewManager.getEventRepository().saveSolutionWithEventsAndPoints(newSolution, newEventsWithPoints, new EventRepository.RepositoryCallback<Void>() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(Void result) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
Toast.makeText(ScriptsActivity.this, "方案 '" + originalSolution.getSolutionName() + "' 已复制为 '" + newSolution.getSolutionName() + "'", Toast.LENGTH_SHORT).show();
|
||||||
|
loadSolutions(); // 刷新列表
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
Log.e(TAG, "复制方案失败: " + e.getMessage(), e);
|
||||||
|
Toast.makeText(ScriptsActivity.this, "复制方案失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() ->
|
||||||
|
Toast.makeText(ScriptsActivity.this, "无法获取原始方案数据。", Toast.LENGTH_SHORT).show()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
Log.e(TAG, "获取原始方案数据失败: " + e.getMessage(), e);
|
||||||
|
Toast.makeText(ScriptsActivity.this, "复制方案失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void showDeleteConfirmationDialog(final Solution solution) {
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle("删除方案")
|
||||||
|
.setMessage("确定要删除方案 '" + solution.getSolutionName() + "' 吗?")
|
||||||
|
.setPositiveButton("删除", (dialog, which) -> deleteSolution(solution))
|
||||||
|
.setNegativeButton("取消", null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteSolution(final Solution solution) {
|
||||||
|
floatingViewManager.getEventRepository().deleteSolution(solution.getSolutionId(), new EventRepository.RepositoryCallback<Void>() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(Void result) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
Toast.makeText(ScriptsActivity.this, "方案 '" + solution.getSolutionName() + "' 已删除。", Toast.LENGTH_SHORT).show();
|
||||||
|
loadSolutions(); // 刷新列表
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
Log.e(TAG, "删除方案失败: " + e.getMessage(), e);
|
||||||
|
Toast.makeText(ScriptsActivity.this, "删除方案失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exportSolution(final Solution solution) {
|
||||||
|
floatingViewManager.getEventRepository().getSolutionWithEventsAndPoints(solution.getSolutionId(), new EventRepository.RepositoryCallback<SolutionWithEventsAndPoints>() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(SolutionWithEventsAndPoints solutionData) {
|
||||||
|
if (solutionData != null) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
String jsonString = gson.toJson(solutionData);
|
||||||
|
|
||||||
|
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
|
||||||
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
|
intent.setType("application/json"); // 导出为 JSON 文件
|
||||||
|
intent.putExtra(Intent.EXTRA_TITLE, solution.getSolutionName() + ".json");
|
||||||
|
startActivityForResult(intent, CREATE_FILE_REQUEST_CODE);
|
||||||
|
|
||||||
|
// 将 JSON 字符串保存到临时变量或直接传递
|
||||||
|
// 在 onActivityResult 中处理保存
|
||||||
|
tempExportJson = jsonString; // 临时保存待导出的JSON数据
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() ->
|
||||||
|
Toast.makeText(ScriptsActivity.this, "获取方案数据失败,无法导出。", Toast.LENGTH_SHORT).show()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
Log.e(TAG, "获取方案数据失败: " + e.getMessage(), e);
|
||||||
|
Toast.makeText(ScriptsActivity.this, "导出方案失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 临时变量,用于存储待导出的JSON数据
|
||||||
|
private String tempExportJson;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
if (requestCode == CREATE_FILE_REQUEST_CODE && resultCode == RESULT_OK) {
|
||||||
|
if (data != null && data.getData() != null) {
|
||||||
|
Uri uri = data.getData();
|
||||||
|
if (tempExportJson != null) {
|
||||||
|
try (OutputStream outputStream = getContentResolver().openOutputStream(uri)) {
|
||||||
|
if (outputStream != null) {
|
||||||
|
outputStream.write(tempExportJson.getBytes());
|
||||||
|
Toast.makeText(this, "方案已成功导出!", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "保存文件失败: " + e.getMessage(), e);
|
||||||
|
Toast.makeText(this, "保存文件失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
} finally {
|
||||||
|
tempExportJson = null; // 清除临时数据
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, "没有可导出的数据。", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,10 +1,13 @@
|
|||||||
package com.auto.clicker.autoclicker.ui.adapter.floating;
|
package com.auto.clicker.autoclicker.ui.adapter.floating;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
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.ImageView;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
@ -13,18 +16,32 @@ import com.auto.clicker.autoclicker.room.entity.Solution;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class SolutionAdapter extends RecyclerView.Adapter<SolutionAdapter.SolutionViewHolder> {
|
public class SolutionAdapter extends RecyclerView.Adapter<SolutionAdapter.SolutionViewHolder> {
|
||||||
|
|
||||||
private List<Solution> solutionList;
|
private List<Solution> solutionList;
|
||||||
private OnSolutionClickListener listener;
|
private OnSolutionClickListener listener;
|
||||||
|
private OnOptionMenuClickListener optionMenuListener;
|
||||||
|
|
||||||
|
// 新增接口定义
|
||||||
|
public interface OnOptionMenuClickListener {
|
||||||
|
void onRenameClick(Solution solution);
|
||||||
|
|
||||||
|
void onDuplicateClick(Solution solution);
|
||||||
|
|
||||||
|
void onDeleteClick(Solution solution);
|
||||||
|
|
||||||
|
void onExportClick(Solution solution);
|
||||||
|
}
|
||||||
|
|
||||||
public interface OnSolutionClickListener {
|
public interface OnSolutionClickListener {
|
||||||
void onSolutionClick(Solution solution);
|
void onSolutionClick(Solution solution);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SolutionAdapter(List<Solution> solutionList, OnSolutionClickListener listener) {
|
public SolutionAdapter(List<Solution> solutionList, OnSolutionClickListener listener, OnOptionMenuClickListener optionMenuListener) {
|
||||||
this.solutionList = solutionList;
|
this.solutionList = solutionList;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
this.optionMenuListener = optionMenuListener; // 初始化
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ -32,25 +49,31 @@ public class SolutionAdapter extends RecyclerView.Adapter<SolutionAdapter.Soluti
|
|||||||
public SolutionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public SolutionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
View view = LayoutInflater.from(parent.getContext())
|
View view = LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.item_solution, parent, false);
|
.inflate(R.layout.item_solution, parent, false);
|
||||||
return new SolutionViewHolder(view);
|
return new SolutionViewHolder(view, parent.getContext()); // 传递 Context
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull SolutionViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull SolutionViewHolder holder, int position) {
|
||||||
Solution solution = solutionList.get(position);
|
Solution solution = solutionList.get(position);
|
||||||
holder.solutionNameTextView.setText(solution.getSolutionName());
|
holder.name.setText(solution.getSolutionName());
|
||||||
if(solution.getMode() == 1){
|
if (solution.getMode() == 1) {
|
||||||
holder.solutionModeNameTextView.setText("1-point Mode");
|
holder.mode.setText("1-point Mode");
|
||||||
}else {
|
} else {
|
||||||
holder.solutionModeNameTextView.setText("Multi-Point Mode");
|
holder.mode.setText("Multi-Point Mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.solutionPlayImageView.setOnClickListener(v -> {
|
holder.play.setOnClickListener(v -> {
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.onSolutionClick(solution);
|
listener.onSolutionClick(solution);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 为 option 按钮设置点击监听器
|
||||||
|
holder.option.setOnClickListener(v -> {
|
||||||
|
if (optionMenuListener != null) {
|
||||||
|
holder.showOptionMenu(solution, optionMenuListener); // 调用方法显示菜单
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -67,15 +90,62 @@ public class SolutionAdapter extends RecyclerView.Adapter<SolutionAdapter.Soluti
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class SolutionViewHolder extends RecyclerView.ViewHolder {
|
static class SolutionViewHolder extends RecyclerView.ViewHolder {
|
||||||
TextView solutionNameTextView;
|
TextView name;
|
||||||
TextView solutionModeNameTextView;
|
TextView mode;
|
||||||
ImageView solutionPlayImageView;
|
ImageView play;
|
||||||
|
ImageView option;
|
||||||
|
Context context; // 保存 Context
|
||||||
|
|
||||||
SolutionViewHolder(View itemView) {
|
SolutionViewHolder(View itemView, Context context) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
solutionNameTextView = itemView.findViewById(R.id.textViewTopLeft);
|
this.context = context; // 初始化 Context
|
||||||
solutionModeNameTextView = itemView.findViewById(R.id.textViewBottomLeft);
|
name = itemView.findViewById(R.id.name);
|
||||||
solutionPlayImageView = itemView.findViewById(R.id.imageViewRight);
|
mode = itemView.findViewById(R.id.mode);
|
||||||
|
play = itemView.findViewById(R.id.play);
|
||||||
|
option = itemView.findViewById(R.id.option);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示选项菜单的私有方法
|
||||||
|
private void showOptionMenu(Solution solution, OnOptionMenuClickListener menuListener) {
|
||||||
|
View popupView = LayoutInflater.from(context).inflate(R.layout.option_menu_layout, null);
|
||||||
|
PopupWindow popupWindow = new PopupWindow(
|
||||||
|
popupView,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
true // 设置为 true,允许点击外部关闭
|
||||||
|
);
|
||||||
|
popupWindow.setElevation(8f); // 添加阴影
|
||||||
|
popupWindow.setBackgroundDrawable(context.getDrawable(android.R.color.transparent)); // 设置透明背景,以便显示阴影
|
||||||
|
|
||||||
|
// 查找 popupView 中的 TextView
|
||||||
|
TextView tvRename = popupView.findViewById(R.id.tv_rename);
|
||||||
|
TextView tvDuplicate = popupView.findViewById(R.id.tv_duplicate);
|
||||||
|
TextView tvDelete = popupView.findViewById(R.id.tv_delete);
|
||||||
|
TextView tvExport = popupView.findViewById(R.id.tv_export);
|
||||||
|
|
||||||
|
// 设置点击监听器
|
||||||
|
tvRename.setOnClickListener(v -> {
|
||||||
|
menuListener.onRenameClick(solution);
|
||||||
|
popupWindow.dismiss(); // 关闭弹窗
|
||||||
|
});
|
||||||
|
|
||||||
|
tvDuplicate.setOnClickListener(v -> {
|
||||||
|
menuListener.onDuplicateClick(solution);
|
||||||
|
popupWindow.dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
tvDelete.setOnClickListener(v -> {
|
||||||
|
menuListener.onDeleteClick(solution);
|
||||||
|
popupWindow.dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
tvExport.setOnClickListener(v -> {
|
||||||
|
menuListener.onExportClick(solution);
|
||||||
|
popupWindow.dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 显示 PopupWindow,锚定在 option 按钮下方
|
||||||
|
popupWindow.showAsDropDown(option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,47 +0,0 @@
|
|||||||
package com.auto.clicker.autoclicker.ui.adapter.script;
|
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.auto.clicker.autoclicker.R;
|
|
||||||
import com.auto.clicker.autoclicker.room.entity.Solution;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ScriptListAdapter extends RecyclerView.Adapter<ScriptListAdapter.ViewHolder> {
|
|
||||||
private List<Solution> solutionList;
|
|
||||||
|
|
||||||
public ScriptListAdapter(List<Solution> solutionList) {
|
|
||||||
this.solutionList = solutionList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parentGroup, int viewType) {
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(parentGroup.getContext());
|
|
||||||
View itemLayout = inflater.inflate(R.layout.item_script, parentGroup, false);
|
|
||||||
return new ViewHolder(itemLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull ViewHolder itemHolder, int pos) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
return solutionList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
|
|
||||||
public ViewHolder(@NonNull View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
package com.auto.clicker.autoclicker.ui.dialog;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
|
|
||||||
|
import com.auto.clicker.autoclicker.R;
|
||||||
|
import com.auto.clicker.autoclicker.ui.activity.main.MainActivity;
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||||
|
|
||||||
|
public class CreateModeSelectionDialog extends BottomSheetDialogFragment {
|
||||||
|
|
||||||
|
public static final String EXTRA_FLOATING_MODE = "extra_floating_mode";
|
||||||
|
public static final int FLOATING_SINGLE = 1;
|
||||||
|
public static final int FLOATING_MULTI = 2;
|
||||||
|
|
||||||
|
private int selectedMode = FLOATING_SINGLE;
|
||||||
|
|
||||||
|
private ConstraintLayout layoutSingleMode;
|
||||||
|
private ConstraintLayout layoutMultiMode;
|
||||||
|
private ImageView iconSingle;
|
||||||
|
private ImageView iconMulti;
|
||||||
|
|
||||||
|
public CreateModeSelectionDialog() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.dialog_create_mode_selection, container, false);
|
||||||
|
|
||||||
|
ImageView btnClose = view.findViewById(R.id.btn_close_dialog);
|
||||||
|
layoutSingleMode = view.findViewById(R.id.layout_single_mode);
|
||||||
|
layoutMultiMode = view.findViewById(R.id.layout_multi_mode);
|
||||||
|
Button btnStartCreate = view.findViewById(R.id.btn_start_create);
|
||||||
|
|
||||||
|
iconSingle = view.findViewById(R.id.icon_single);
|
||||||
|
iconMulti = view.findViewById(R.id.icon_multi);
|
||||||
|
|
||||||
|
btnClose.setOnClickListener(v -> dismiss());
|
||||||
|
|
||||||
|
layoutSingleMode.setOnClickListener(v -> {
|
||||||
|
setSelectedMode(FLOATING_SINGLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
layoutMultiMode.setOnClickListener(v -> {
|
||||||
|
setSelectedMode(FLOATING_MULTI);
|
||||||
|
});
|
||||||
|
|
||||||
|
btnStartCreate.setOnClickListener(v -> {
|
||||||
|
if (selectedMode == 0) {
|
||||||
|
Toast.makeText(getContext(), "请选择模式", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
navigateToMainActivity(selectedMode);
|
||||||
|
});
|
||||||
|
|
||||||
|
updateModeSelectionUI();
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSelectedMode(int mode) {
|
||||||
|
if (this.selectedMode != mode) {
|
||||||
|
this.selectedMode = mode;
|
||||||
|
updateModeSelectionUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateModeSelectionUI() {
|
||||||
|
if (selectedMode == FLOATING_SINGLE) {
|
||||||
|
layoutSingleMode.setSelected(true);
|
||||||
|
iconSingle.setImageResource(R.drawable.ic_circle_filled_check);
|
||||||
|
|
||||||
|
layoutMultiMode.setSelected(false);
|
||||||
|
iconMulti.setImageResource(R.drawable.ic_circle_hollow);
|
||||||
|
} else if (selectedMode == FLOATING_MULTI) {
|
||||||
|
layoutMultiMode.setSelected(true);
|
||||||
|
iconMulti.setImageResource(R.drawable.ic_circle_filled_check);
|
||||||
|
|
||||||
|
layoutSingleMode.setSelected(false);
|
||||||
|
iconSingle.setImageResource(R.drawable.ic_circle_hollow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void navigateToMainActivity(int mode) {
|
||||||
|
Intent intent = new Intent(getActivity(), MainActivity.class);
|
||||||
|
intent.putExtra(EXTRA_FLOATING_MODE, mode);
|
||||||
|
startActivity(intent);
|
||||||
|
dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,66 +0,0 @@
|
|||||||
package com.auto.clicker.autoclicker.ui.fragment.floating;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import com.auto.clicker.autoclicker.R;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple {@link Fragment} subclass.
|
|
||||||
* Use the {@link LoadScriptFragment#newInstance} factory method to
|
|
||||||
* create an instance of this fragment.
|
|
||||||
*/
|
|
||||||
public class LoadScriptFragment extends Fragment {
|
|
||||||
|
|
||||||
// TODO: Rename parameter arguments, choose names that match
|
|
||||||
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
|
||||||
private static final String ARG_PARAM1 = "param1";
|
|
||||||
private static final String ARG_PARAM2 = "param2";
|
|
||||||
|
|
||||||
// TODO: Rename and change types of parameters
|
|
||||||
private String mParam1;
|
|
||||||
private String mParam2;
|
|
||||||
|
|
||||||
public LoadScriptFragment() {
|
|
||||||
// Required empty public constructor
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use this factory method to create a new instance of
|
|
||||||
* this fragment using the provided parameters.
|
|
||||||
*
|
|
||||||
* @param param1 Parameter 1.
|
|
||||||
* @param param2 Parameter 2.
|
|
||||||
* @return A new instance of fragment LoadScriptFragment.
|
|
||||||
*/
|
|
||||||
// TODO: Rename and change types and number of parameters
|
|
||||||
public static LoadScriptFragment newInstance(String param1, String param2) {
|
|
||||||
LoadScriptFragment fragment = new LoadScriptFragment();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putString(ARG_PARAM1, param1);
|
|
||||||
args.putString(ARG_PARAM2, param2);
|
|
||||||
fragment.setArguments(args);
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
if (getArguments() != null) {
|
|
||||||
mParam1 = getArguments().getString(ARG_PARAM1);
|
|
||||||
mParam2 = getArguments().getString(ARG_PARAM2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState) {
|
|
||||||
// Inflate the layout for this fragment
|
|
||||||
return inflater.inflate(R.layout.fragment_load_script, container, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
package com.auto.clicker.autoclicker.ui.fragment.floating;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import com.auto.clicker.autoclicker.R;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple {@link Fragment} subclass.
|
|
||||||
* Use the {@link SaveScriptFragment#newInstance} factory method to
|
|
||||||
* create an instance of this fragment.
|
|
||||||
*/
|
|
||||||
public class SaveScriptFragment extends Fragment {
|
|
||||||
|
|
||||||
// TODO: Rename parameter arguments, choose names that match
|
|
||||||
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
|
||||||
private static final String ARG_PARAM1 = "param1";
|
|
||||||
private static final String ARG_PARAM2 = "param2";
|
|
||||||
|
|
||||||
// TODO: Rename and change types of parameters
|
|
||||||
private String mParam1;
|
|
||||||
private String mParam2;
|
|
||||||
|
|
||||||
public SaveScriptFragment() {
|
|
||||||
// Required empty public constructor
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use this factory method to create a new instance of
|
|
||||||
* this fragment using the provided parameters.
|
|
||||||
*
|
|
||||||
* @param param1 Parameter 1.
|
|
||||||
* @param param2 Parameter 2.
|
|
||||||
* @return A new instance of fragment SaveScriptFragment.
|
|
||||||
*/
|
|
||||||
// TODO: Rename and change types and number of parameters
|
|
||||||
public static SaveScriptFragment newInstance(String param1, String param2) {
|
|
||||||
SaveScriptFragment fragment = new SaveScriptFragment();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putString(ARG_PARAM1, param1);
|
|
||||||
args.putString(ARG_PARAM2, param2);
|
|
||||||
fragment.setArguments(args);
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
if (getArguments() != null) {
|
|
||||||
mParam1 = getArguments().getString(ARG_PARAM1);
|
|
||||||
mParam2 = getArguments().getString(ARG_PARAM2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState) {
|
|
||||||
// Inflate the layout for this fragment
|
|
||||||
return inflater.inflate(R.layout.fragment_save_script, container, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -12,7 +12,6 @@ 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.MotionEvent;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
@ -22,6 +21,7 @@ import android.widget.PopupWindow;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.appcompat.widget.AppCompatButton;
|
||||||
import androidx.appcompat.widget.SwitchCompat;
|
import androidx.appcompat.widget.SwitchCompat;
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||||
|
|
||||||
@ -36,8 +36,6 @@ public class FloatingSettingDialogManager {
|
|||||||
private ConstraintLayout floatingDialogView;
|
private ConstraintLayout floatingDialogView;
|
||||||
private WindowManager.LayoutParams floatingDialogParams;
|
private WindowManager.LayoutParams floatingDialogParams;
|
||||||
|
|
||||||
private FloatingViewManager floatingViewManager;
|
|
||||||
|
|
||||||
private static final int TYPE_INTERVAL = 0;
|
private static final int TYPE_INTERVAL = 0;
|
||||||
private static final int TYPE_SWIPE_DURATION = 1;
|
private static final int TYPE_SWIPE_DURATION = 1;
|
||||||
private static final int TYPE_REPEAT = 2;
|
private static final int TYPE_REPEAT = 2;
|
||||||
@ -53,16 +51,22 @@ public class FloatingSettingDialogManager {
|
|||||||
private TextView tvSelectedUnit;
|
private TextView tvSelectedUnit;
|
||||||
private EditText etRepeatValue;
|
private EditText etRepeatValue;
|
||||||
private TextView repeatSelectedUnit;
|
private TextView repeatSelectedUnit;
|
||||||
|
private AppCompatButton saveButton;
|
||||||
|
private AppCompatButton closeButton;
|
||||||
|
|
||||||
|
private String currentIntervalUnit = "";
|
||||||
|
private String currentSwipeDurationUnit = "";
|
||||||
|
private String currentRepeatUnit = "";
|
||||||
|
private String currentIntervalValue = "";
|
||||||
|
private String currentDurationValue = "";
|
||||||
|
private String currentRepeatValue = "";
|
||||||
|
private boolean isRepeatSwitchChecked = false;
|
||||||
|
|
||||||
public FloatingSettingDialogManager(Context context) {
|
public FloatingSettingDialogManager(Context context) {
|
||||||
this.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();
|
||||||
@ -85,20 +89,46 @@ public class FloatingSettingDialogManager {
|
|||||||
etRepeatValue = floatingDialogView.findViewById(R.id.dialog_et_repeat_value);
|
etRepeatValue = floatingDialogView.findViewById(R.id.dialog_et_repeat_value);
|
||||||
repeatSelectedUnit = floatingDialogView.findViewById(R.id.dialog_repeat_selected_unit);
|
repeatSelectedUnit = floatingDialogView.findViewById(R.id.dialog_repeat_selected_unit);
|
||||||
|
|
||||||
|
saveButton = floatingDialogView.findViewById(R.id.save);
|
||||||
|
closeButton = floatingDialogView.findViewById(R.id.close);
|
||||||
|
|
||||||
intervalSelectorContainer.setOnClickListener(v -> showUnitSelection(v, TYPE_INTERVAL));
|
intervalSelectorContainer.setOnClickListener(v -> showUnitSelection(v, TYPE_INTERVAL));
|
||||||
unitSelectorContainer.setOnClickListener(v -> showUnitSelection(v, TYPE_SWIPE_DURATION));
|
unitSelectorContainer.setOnClickListener(v -> showUnitSelection(v, TYPE_SWIPE_DURATION));
|
||||||
|
|
||||||
setupRepeatMode();
|
setupRepeatMode();
|
||||||
|
// --- 恢复UI状态 ---
|
||||||
|
restoreUIState();
|
||||||
|
|
||||||
floatingDialogView.setOnTouchListener((v, event) -> {
|
// floatingDialogView.setOnTouchListener((v, event) -> {
|
||||||
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
|
// if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
|
||||||
// 如果是外部点击事件,就关闭对话框
|
// // 如果是外部点击事件,就关闭对话框
|
||||||
|
// saveCurrentSettings();
|
||||||
|
// removeFloatingTabDialog();
|
||||||
|
// Log.d(TAG, "检测到外部点击,浮动标签页弹窗已关闭。");
|
||||||
|
// return true; // 消费此事件
|
||||||
|
// }
|
||||||
|
// return false; // 其他事件不处理
|
||||||
|
// });
|
||||||
|
|
||||||
|
if (saveButton != null) {
|
||||||
|
saveButton.setOnClickListener(v -> {
|
||||||
|
saveCurrentSettings();
|
||||||
|
applySettingsToService();
|
||||||
removeFloatingTabDialog();
|
removeFloatingTabDialog();
|
||||||
Log.d(TAG, "检测到外部点击,浮动标签页弹窗已关闭。");
|
showToastOnUi(context, "设置已保存!");
|
||||||
return true; // 消费此事件
|
});
|
||||||
}
|
} else {
|
||||||
return false; // 其他事件不处理
|
Log.e(TAG, "Save button not found!");
|
||||||
});
|
}
|
||||||
|
|
||||||
|
if (closeButton != null) {
|
||||||
|
closeButton.setOnClickListener(v -> {
|
||||||
|
removeFloatingTabDialog();
|
||||||
|
showToastOnUi(context, "设置已关闭,未保存更改。");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Close button not found!");
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
windowManager.addView(floatingDialogView, floatingDialogParams);
|
windowManager.addView(floatingDialogView, floatingDialogParams);
|
||||||
@ -128,6 +158,8 @@ public class FloatingSettingDialogManager {
|
|||||||
tvSelectedUnit = null;
|
tvSelectedUnit = null;
|
||||||
etRepeatValue = null;
|
etRepeatValue = null;
|
||||||
repeatSelectedUnit = null;
|
repeatSelectedUnit = null;
|
||||||
|
saveButton = null;
|
||||||
|
closeButton = null;
|
||||||
|
|
||||||
Log.d(TAG, "浮动标签页弹窗已移除");
|
Log.d(TAG, "浮动标签页弹窗已移除");
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
@ -163,31 +195,35 @@ public class FloatingSettingDialogManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
repeatSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
repeatSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||||
if (isChecked) {
|
isRepeatSwitchChecked = isChecked; // 保存开关状态
|
||||||
repeatInput.setVisibility(View.VISIBLE);
|
updateRepeatUI(isChecked);
|
||||||
repeatSelectorContainer.setVisibility(View.VISIBLE);
|
});
|
||||||
repeatSelectedUnit.setText(context.getString(R.string.infinitely_unit));
|
|
||||||
|
repeatSelectorContainer.setOnClickListener(v -> showUnitSelection(v, TYPE_REPEAT));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateRepeatUI(boolean isChecked) {
|
||||||
|
if (isChecked) {
|
||||||
|
repeatInput.setVisibility(View.VISIBLE);
|
||||||
|
repeatSelectorContainer.setVisibility(View.VISIBLE);
|
||||||
|
// 只有当单位是“无限次”时才禁用输入框
|
||||||
|
if (currentRepeatUnit.equals(context.getString(R.string.infinitely_unit)) || repeatSelectedUnit.getText().toString().equals(context.getString(R.string.infinitely_unit))) {
|
||||||
etRepeatValue.setText("");
|
etRepeatValue.setText("");
|
||||||
etRepeatValue.setEnabled(false);
|
etRepeatValue.setEnabled(false);
|
||||||
etRepeatValue.setInputType(InputType.TYPE_NULL);
|
etRepeatValue.setInputType(InputType.TYPE_NULL);
|
||||||
|
repeatSelectedUnit.setText(context.getString(R.string.infinitely_unit)); // 确保显示无限次
|
||||||
} else {
|
} else {
|
||||||
repeatInput.setVisibility(View.GONE);
|
etRepeatValue.setEnabled(true);
|
||||||
repeatSelectorContainer.setVisibility(View.GONE);
|
etRepeatValue.setInputType(InputType.TYPE_CLASS_NUMBER); // 默认设置为数字输入
|
||||||
|
// 恢复之前的输入值和单位
|
||||||
|
etRepeatValue.setText(currentRepeatValue);
|
||||||
|
repeatSelectedUnit.setText(currentRepeatUnit.isEmpty() ? context.getString(R.string.cycle_unit) : currentRepeatUnit);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// 根据初始状态设置可见性
|
} else {
|
||||||
if (!repeatSwitch.isChecked()) {
|
|
||||||
repeatInput.setVisibility(View.GONE);
|
repeatInput.setVisibility(View.GONE);
|
||||||
repeatSelectorContainer.setVisibility(View.GONE);
|
repeatSelectorContainer.setVisibility(View.GONE);
|
||||||
} else {
|
|
||||||
repeatSelectedUnit.setText(context.getString(R.string.infinitely_unit));
|
|
||||||
etRepeatValue.setText("");
|
|
||||||
etRepeatValue.setEnabled(false);
|
|
||||||
etRepeatValue.setInputType(InputType.TYPE_NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
repeatSelectorContainer.setOnClickListener(v -> showUnitSelection(v, TYPE_REPEAT));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showUnitSelection(View anchorView, int type) {
|
private void showUnitSelection(View anchorView, int type) {
|
||||||
@ -242,10 +278,10 @@ public class FloatingSettingDialogManager {
|
|||||||
String unitText = context.getString(R.string.milliseconds_unit);
|
String unitText = context.getString(R.string.milliseconds_unit);
|
||||||
if (type == TYPE_INTERVAL) {
|
if (type == TYPE_INTERVAL) {
|
||||||
intervalSelectedUnit.setText(unitText);
|
intervalSelectedUnit.setText(unitText);
|
||||||
showInputValue("Interval", etIntervalValue.getText().toString(), unitText);
|
currentIntervalUnit = unitText;
|
||||||
} else {
|
} else {
|
||||||
tvSelectedUnit.setText(unitText);
|
tvSelectedUnit.setText(unitText);
|
||||||
showInputValue("Swipe Duration", etDurationValue.getText().toString(), unitText);
|
currentSwipeDurationUnit = unitText;
|
||||||
}
|
}
|
||||||
popupWindow.dismiss();
|
popupWindow.dismiss();
|
||||||
});
|
});
|
||||||
@ -254,10 +290,10 @@ public class FloatingSettingDialogManager {
|
|||||||
String unitText = context.getString(R.string.seconds_unit);
|
String unitText = context.getString(R.string.seconds_unit);
|
||||||
if (type == TYPE_INTERVAL) {
|
if (type == TYPE_INTERVAL) {
|
||||||
intervalSelectedUnit.setText(unitText);
|
intervalSelectedUnit.setText(unitText);
|
||||||
showInputValue("Interval", etIntervalValue.getText().toString(), unitText);
|
currentIntervalUnit = unitText;
|
||||||
} else {
|
} else {
|
||||||
tvSelectedUnit.setText(unitText);
|
tvSelectedUnit.setText(unitText);
|
||||||
showInputValue("Swipe Duration", etDurationValue.getText().toString(), unitText);
|
currentSwipeDurationUnit = unitText;
|
||||||
}
|
}
|
||||||
popupWindow.dismiss();
|
popupWindow.dismiss();
|
||||||
});
|
});
|
||||||
@ -266,38 +302,41 @@ public class FloatingSettingDialogManager {
|
|||||||
tvMin.setOnClickListener(v -> {
|
tvMin.setOnClickListener(v -> {
|
||||||
String unitText = context.getString(R.string.minutes_unit);
|
String unitText = context.getString(R.string.minutes_unit);
|
||||||
intervalSelectedUnit.setText(unitText);
|
intervalSelectedUnit.setText(unitText);
|
||||||
|
currentIntervalUnit = unitText;
|
||||||
popupWindow.dismiss();
|
popupWindow.dismiss();
|
||||||
showInputValue("Interval", etIntervalValue.getText().toString(), unitText);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == TYPE_REPEAT) {
|
if (type == TYPE_REPEAT) {
|
||||||
tvInfinitely.setOnClickListener(v -> {
|
tvInfinitely.setOnClickListener(v -> {
|
||||||
repeatSelectedUnit.setText(context.getString(R.string.infinitely_unit));
|
String unitText = context.getString(R.string.infinitely_unit);
|
||||||
|
repeatSelectedUnit.setText(unitText);
|
||||||
|
currentRepeatUnit = unitText;
|
||||||
etRepeatValue.setText("");
|
etRepeatValue.setText("");
|
||||||
etRepeatValue.setEnabled(false);
|
etRepeatValue.setEnabled(false);
|
||||||
etRepeatValue.setInputType(InputType.TYPE_NULL);
|
etRepeatValue.setInputType(InputType.TYPE_NULL);
|
||||||
popupWindow.dismiss();
|
popupWindow.dismiss();
|
||||||
showInputValue("Repeat", etRepeatValue.getText().toString(), context.getString(R.string.infinitely_unit));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tvDuration.setOnClickListener(v -> {
|
tvDuration.setOnClickListener(v -> {
|
||||||
repeatSelectedUnit.setText(context.getString(R.string.duration_unit));
|
String unitText = context.getString(R.string.duration_unit);
|
||||||
etRepeatValue.setText("");
|
repeatSelectedUnit.setText(unitText);
|
||||||
|
currentRepeatUnit = unitText;
|
||||||
|
etRepeatValue.setText(""); // 清空以便用户输入新值
|
||||||
etRepeatValue.setEnabled(true);
|
etRepeatValue.setEnabled(true);
|
||||||
etRepeatValue.setInputType(InputType.TYPE_CLASS_NUMBER);
|
etRepeatValue.setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||||
popupWindow.dismiss();
|
popupWindow.dismiss();
|
||||||
showInputValue("Repeat", etRepeatValue.getText().toString(), context.getString(R.string.duration_unit));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tvCycle.setOnClickListener(v -> {
|
tvCycle.setOnClickListener(v -> {
|
||||||
repeatSelectedUnit.setText(context.getString(R.string.cycle_unit));
|
String unitText = context.getString(R.string.cycle_unit);
|
||||||
|
repeatSelectedUnit.setText(unitText);
|
||||||
|
currentRepeatUnit = unitText;
|
||||||
etRepeatValue.setText("");
|
etRepeatValue.setText("");
|
||||||
etRepeatValue.setEnabled(true);
|
etRepeatValue.setEnabled(true);
|
||||||
etRepeatValue.setInputType(InputType.TYPE_CLASS_NUMBER);
|
etRepeatValue.setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||||
popupWindow.dismiss();
|
popupWindow.dismiss();
|
||||||
showInputValue("Repeat", etRepeatValue.getText().toString(), context.getString(R.string.cycle_unit));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,98 +345,164 @@ public class FloatingSettingDialogManager {
|
|||||||
} else {
|
} else {
|
||||||
popupWindow.showAsDropDown(anchorView);
|
popupWindow.showAsDropDown(anchorView);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showInputValue(String type, String value, String unit) {
|
private void saveCurrentSettings() {
|
||||||
String message = type + " 值: " + (value.isEmpty() ? "未输入" : value) + ", 单位: " + unit;
|
currentIntervalValue = etIntervalValue.getText().toString();
|
||||||
showToastOnUi(context, message);
|
currentDurationValue = etDurationValue.getText().toString();
|
||||||
|
currentRepeatValue = etRepeatValue.getText().toString();
|
||||||
|
|
||||||
|
Log.d(TAG, "UI设置已保存到Manager: Interval=" + currentIntervalValue + " " + currentIntervalUnit +
|
||||||
|
", Duration=" + currentDurationValue + " " + currentSwipeDurationUnit +
|
||||||
|
", Repeat=" + currentRepeatValue + " " + currentRepeatUnit +
|
||||||
|
", RepeatSwitch=" + isRepeatSwitchChecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applySettingsToService() {
|
||||||
AutoClickService service = AutoClickService.getInstance();
|
AutoClickService service = AutoClickService.getInstance();
|
||||||
|
if (service == null) {
|
||||||
|
Log.e(TAG, "AutoClickService 实例为空,无法应用设置。");
|
||||||
|
showToastOnUi(context, "自动点击服务未运行,无法应用设置。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (type) {
|
// 应用点击间隔
|
||||||
case "Interval":
|
long intervalValue = 0;
|
||||||
long intervalValue = 0;
|
if (!currentIntervalValue.isEmpty()) {
|
||||||
if (!value.isEmpty()) {
|
try {
|
||||||
try {
|
intervalValue = Long.parseLong(currentIntervalValue);
|
||||||
intervalValue = Long.parseLong(value);
|
if (currentIntervalUnit.equals(context.getString(R.string.seconds_unit))) {
|
||||||
// 根据 unit 进行单位转换
|
intervalValue *= 1000;
|
||||||
if (unit.equals(context.getString(R.string.seconds_unit))) {
|
} else if (currentIntervalUnit.equals(context.getString(R.string.minutes_unit))) {
|
||||||
intervalValue *= 1000; // 如果单位是秒,转换为毫秒
|
intervalValue *= 60 * 1000;
|
||||||
}
|
|
||||||
if (service != null) {
|
|
||||||
service.setClickInterval(intervalValue);
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "AutoClickService 实例为空,无法设置点击间隔。");
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Log.e(TAG, "点击间隔值解析错误: " + value, e);
|
|
||||||
showToastOnUi(context, "点击间隔值无效,请输入有效数字。");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 你可以在这里将 intervalValue 保存到你的数据模型或 SharedPreferences
|
service.setClickInterval(intervalValue);
|
||||||
break;
|
Log.d(TAG, "应用点击间隔到服务: " + intervalValue + "ms");
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Log.e(TAG, "点击间隔值解析错误: " + currentIntervalValue, e);
|
||||||
|
showToastOnUi(context, "点击间隔值无效,请输入有效数字。");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果为空,设置一个默认值或不设置,这取决于你的业务逻辑
|
||||||
|
// service.setClickInterval(默认值);
|
||||||
|
Log.d(TAG, "点击间隔值为空,未应用到服务。");
|
||||||
|
}
|
||||||
|
|
||||||
case "Swipe Duration":
|
int slideDurationValue = 0;
|
||||||
int slideDurationValue = 0;
|
if (!currentDurationValue.isEmpty()) {
|
||||||
if (!value.isEmpty()) {
|
try {
|
||||||
try {
|
slideDurationValue = Integer.parseInt(currentDurationValue);
|
||||||
slideDurationValue = Integer.parseInt(value);
|
if (currentSwipeDurationUnit.equals(context.getString(R.string.seconds_unit))) {
|
||||||
if (unit.equals(context.getString(R.string.seconds_unit))) {
|
slideDurationValue *= 1000;
|
||||||
slideDurationValue *= 1000; // 如果单位是秒,转换为毫秒
|
|
||||||
}
|
|
||||||
if (service != null) {
|
|
||||||
service.setSlideDuration(slideDurationValue);
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "AutoClickService 实例为空,无法设置滑动时长。");
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Log.e(TAG, "滑动时长值解析错误: " + value, e);
|
|
||||||
showToastOnUi(context, "滑动时长值无效,请输入有效数字。");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 你可以在这里将 slideDurationValue 保存到你的数据模型或 SharedPreferences
|
service.setSlideDuration(slideDurationValue);
|
||||||
break;
|
Log.d(TAG, "应用滑动时长到服务: " + slideDurationValue + "ms");
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Log.e(TAG, "滑动时长值解析错误: " + currentDurationValue, e);
|
||||||
|
showToastOnUi(context, "滑动时长值无效,请输入有效数字。");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果为空,设置一个默认值或不设置
|
||||||
|
// service.setSlideDuration(默认值);
|
||||||
|
Log.d(TAG, "滑动时长值为空,未应用到服务。");
|
||||||
|
}
|
||||||
|
|
||||||
case "Repeat":
|
// 应用重复设置
|
||||||
if (unit.equals(context.getString(R.string.infinitely_unit))) {
|
if (isRepeatSwitchChecked) {
|
||||||
// Repeat 为无限次,不需要处理输入值
|
if (currentRepeatUnit.equals(context.getString(R.string.infinitely_unit))) {
|
||||||
// 确保 etRepeatValue 是禁用的
|
service.setLoopCount(0); // 无限循环
|
||||||
|
Log.d(TAG, "应用重复模式: 无限次。");
|
||||||
|
} else if (currentRepeatUnit.equals(context.getString(R.string.duration_unit))) {
|
||||||
|
long repeatDurationMillis = 0;
|
||||||
|
if (!currentRepeatValue.isEmpty()) {
|
||||||
|
try {
|
||||||
|
repeatDurationMillis = Long.parseLong(currentRepeatValue);
|
||||||
|
// 根据你的UI单位,这里可能需要进一步转换,例如用户输入的是秒
|
||||||
|
// repeatDurationMillis *= 1000L;
|
||||||
|
service.setLoopTime(repeatDurationMillis);
|
||||||
|
Log.d(TAG, "应用重复时长: " + repeatDurationMillis + "ms。");
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Log.e(TAG, "重复时长值解析错误: " + currentRepeatValue, e);
|
||||||
|
showToastOnUi(context, "重复时长值无效,请输入有效数字。");
|
||||||
|
service.setLoopTime(0); // 错误时,取消时间循环
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
service.setLoopTime(0); // 如果值为空,取消时间循环
|
||||||
|
Log.d(TAG, "重复时长值为空,取消时间循环。");
|
||||||
|
}
|
||||||
|
service.setLoopCount(0); // 确保与时间循环互斥
|
||||||
|
} else if (currentRepeatUnit.equals(context.getString(R.string.cycle_unit))) {
|
||||||
|
int repeatCount = 0;
|
||||||
|
if (!currentRepeatValue.isEmpty()) {
|
||||||
|
try {
|
||||||
|
repeatCount = Integer.parseInt(currentRepeatValue);
|
||||||
|
service.setLoopCount(repeatCount);
|
||||||
|
Log.d(TAG, "应用重复次数: " + repeatCount + "次。");
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
Log.e(TAG, "重复次数值解析错误: " + currentRepeatValue, e);
|
||||||
|
showToastOnUi(context, "重复次数值无效,请输入有效数字。");
|
||||||
|
service.setLoopCount(1); // 错误时,设置为执行一次
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
service.setLoopCount(1); // 如果值为空,设置为执行一次
|
||||||
|
Log.d(TAG, "重复次数值为空,设置为执行一次。");
|
||||||
|
}
|
||||||
|
service.setLoopTime(0); // 确保与次数循环互斥
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
service.setLoopCount(1);
|
||||||
|
service.setLoopTime(0);
|
||||||
|
Log.d(TAG, "重复开关关闭,服务设置为执行一次。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreUIState() {
|
||||||
|
// 恢复点击间隔
|
||||||
|
if (!currentIntervalValue.isEmpty()) {
|
||||||
|
etIntervalValue.setText(currentIntervalValue);
|
||||||
|
}
|
||||||
|
if (!currentIntervalUnit.isEmpty()) {
|
||||||
|
intervalSelectedUnit.setText(currentIntervalUnit);
|
||||||
|
} else {
|
||||||
|
intervalSelectedUnit.setText(context.getString(R.string.milliseconds_unit)); // 默认单位
|
||||||
|
currentIntervalUnit = context.getString(R.string.milliseconds_unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复滑动时长
|
||||||
|
if (!currentDurationValue.isEmpty()) {
|
||||||
|
etDurationValue.setText(currentDurationValue);
|
||||||
|
}
|
||||||
|
if (!currentSwipeDurationUnit.isEmpty()) {
|
||||||
|
tvSelectedUnit.setText(currentSwipeDurationUnit);
|
||||||
|
} else {
|
||||||
|
tvSelectedUnit.setText(context.getString(R.string.milliseconds_unit)); // 默认单位
|
||||||
|
currentSwipeDurationUnit = context.getString(R.string.milliseconds_unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复重复设置
|
||||||
|
repeatSwitch.setChecked(isRepeatSwitchChecked);
|
||||||
|
updateRepeatUI(isRepeatSwitchChecked); // 根据开关状态更新UI
|
||||||
|
|
||||||
|
if (isRepeatSwitchChecked) {
|
||||||
|
if (currentRepeatUnit.isEmpty()) {
|
||||||
|
// 如果没有保存的单位,默认为无限次
|
||||||
|
repeatSelectedUnit.setText(context.getString(R.string.infinitely_unit));
|
||||||
|
currentRepeatUnit = context.getString(R.string.infinitely_unit);
|
||||||
|
etRepeatValue.setText("");
|
||||||
|
etRepeatValue.setEnabled(false);
|
||||||
|
etRepeatValue.setInputType(InputType.TYPE_NULL);
|
||||||
|
} else {
|
||||||
|
repeatSelectedUnit.setText(currentRepeatUnit);
|
||||||
|
if (currentRepeatUnit.equals(context.getString(R.string.infinitely_unit))) {
|
||||||
etRepeatValue.setText("");
|
etRepeatValue.setText("");
|
||||||
etRepeatValue.setEnabled(false);
|
etRepeatValue.setEnabled(false);
|
||||||
etRepeatValue.setInputType(InputType.TYPE_NULL);
|
etRepeatValue.setInputType(InputType.TYPE_NULL);
|
||||||
showToastOnUi(context, "重复模式: 无限次");
|
} else {
|
||||||
// AutoClickService 内部已是循环执行,无限次意味着一直运行直到用户停止。
|
etRepeatValue.setText(currentRepeatValue);
|
||||||
// 如果需要更明确的无限次模式,可以在 AutoClickService 中设置一个标志位。
|
|
||||||
} else if (unit.equals(context.getString(R.string.duration_unit))) {
|
|
||||||
// Repeat 为时长,处理时间格式的输入 (例如 "HH:mm:ss" -> 毫秒)
|
|
||||||
String durationValueStr = value.isEmpty() ? "0" : value;
|
|
||||||
// TODO: 你需要在这里添加解析时间格式的逻辑,例如:
|
|
||||||
// long parsedDuration = parseDurationString(durationValueStr); // 自定义方法解析时间
|
|
||||||
// 如果 AutoClickService 需要总运行时间限制,你需要修改 AutoClickService 来支持。
|
|
||||||
// 否则,你可能需要在悬浮窗管理类中实现一个计时器,当达到设定时长时调用 service.stopClicking()。
|
|
||||||
etRepeatValue.setEnabled(true);
|
|
||||||
etRepeatValue.setInputType(InputType.TYPE_CLASS_NUMBER); // 这里暂时设置为数字,如果需要特定时间输入,需要更复杂的实现
|
|
||||||
showToastOnUi(context, "重复时长: " + durationValueStr);
|
|
||||||
} else if (unit.equals(context.getString(R.string.cycle_unit))) {
|
|
||||||
// Repeat 为次数,处理整数输入
|
|
||||||
int repeatCount = 0;
|
|
||||||
if (!value.isEmpty()) {
|
|
||||||
try {
|
|
||||||
repeatCount = Integer.parseInt(value);
|
|
||||||
// TODO: 如果 AutoClickService 需要总循环次数限制,你需要修改 AutoClickService 来支持。
|
|
||||||
// 可以在 AutoClickService 中添加一个变量来跟踪剩余循环次数,并在每次事件队列执行完毕后递减。
|
|
||||||
// 当次数为 0 时,调用 stopClicking()。
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
Log.e(TAG, "重复次数值解析错误: " + value, e);
|
|
||||||
showToastOnUi(context, "重复次数值无效,请输入有效数字。");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
etRepeatValue.setEnabled(true);
|
etRepeatValue.setEnabled(true);
|
||||||
etRepeatValue.setInputType(InputType.TYPE_CLASS_NUMBER);
|
etRepeatValue.setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||||
showToastOnUi(context, "重复次数: " + repeatCount);
|
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -97,7 +97,6 @@ public class FloatingViewManager {
|
|||||||
this.floatingTabDialogManager = new FloatingTabDialogManager(context);
|
this.floatingTabDialogManager = new FloatingTabDialogManager(context);
|
||||||
this.floatingSettingDialogManager = new FloatingSettingDialogManager(context);
|
this.floatingSettingDialogManager = new FloatingSettingDialogManager(context);
|
||||||
this.floatingTabDialogManager.setFloatingViewManager(this);
|
this.floatingTabDialogManager.setFloatingViewManager(this);
|
||||||
this.floatingSettingDialogManager.setFloatingViewManager(this);
|
|
||||||
this.eventRepository = new EventRepository(context.getApplicationContext());
|
this.eventRepository = new EventRepository(context.getApplicationContext());
|
||||||
this.touchPointSize = 100;
|
this.touchPointSize = 100;
|
||||||
|
|
||||||
@ -926,4 +925,8 @@ public class FloatingViewManager {
|
|||||||
playButton.setImageResource(R.drawable.play);
|
playButton.setImageResource(R.drawable.play);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EventRepository getEventRepository() {
|
||||||
|
return eventRepository;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
5
app/src/main/res/drawable/bg_mode_item_selector.xml
Normal file
5
app/src/main/res/drawable/bg_mode_item_selector.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_selected="true" android:drawable="@drawable/bg_selected" />
|
||||||
|
<item android:drawable="@drawable/bg_rounded_rect" />
|
||||||
|
</selector>
|
||||||
12
app/src/main/res/drawable/bg_selected.xml
Normal file
12
app/src/main/res/drawable/bg_selected.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@android:color/transparent" />
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
<stroke android:width="2dp" android:color="@color/blue" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:drawable="@drawable/bg_rounded_rect"
|
||||||
|
android:left="2dp" android:top="2dp"
|
||||||
|
android:right="2dp" android:bottom="2dp" />
|
||||||
|
</layer-list>
|
||||||
9
app/src/main/res/drawable/ic_circle_filled_check.xml
Normal file
9
app/src/main/res/drawable/ic_circle_filled_check.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="17dp"
|
||||||
|
android:height="17dp"
|
||||||
|
android:viewportWidth="17"
|
||||||
|
android:viewportHeight="17">
|
||||||
|
<path
|
||||||
|
android:pathData="M8.5,0C13.194,0 17,3.806 17,8.5C17,13.194 13.194,17 8.5,17C3.806,17 0,13.194 0,8.5C0,3.806 3.806,0 8.5,0ZM7.412,10.442L4.413,7.449L3,8.864L7.247,13.104L7.248,13.102L7.41,13.265L14.298,6.418L12.888,5L7.412,10.442Z"
|
||||||
|
android:fillColor="#0BC4FC"/>
|
||||||
|
</vector>
|
||||||
9
app/src/main/res/drawable/ic_circle_hollow.xml
Normal file
9
app/src/main/res/drawable/ic_circle_hollow.xml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="17dp"
|
||||||
|
android:height="17dp"
|
||||||
|
android:viewportWidth="17"
|
||||||
|
android:viewportHeight="17">
|
||||||
|
<path
|
||||||
|
android:pathData="M8.5,8.5m-8.5,0a8.5,8.5 0,1 1,17 0a8.5,8.5 0,1 1,-17 0"
|
||||||
|
android:fillColor="#3A6876"/>
|
||||||
|
</vector>
|
||||||
42
app/src/main/res/drawable/import_script.xml
Normal file
42
app/src/main/res/drawable/import_script.xml
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="17dp"
|
||||||
|
android:height="17dp"
|
||||||
|
android:viewportWidth="17"
|
||||||
|
android:viewportHeight="17">
|
||||||
|
<path
|
||||||
|
android:pathData="M0,0h17v17h-17z"
|
||||||
|
android:fillColor="#B3B3B3"/>
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M-222,-703h360v800h-360z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M-222,-703h360v800h-360z"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M138,-703H-222V97H138V-703Z"
|
||||||
|
android:fillColor="#171717"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M0,-14L81,-14A23,23 0,0 1,104 9L104,9A23,23 0,0 1,81 32L0,32A23,23 0,0 1,-23 9L-23,9A23,23 0,0 1,0 -14z"
|
||||||
|
android:fillColor="#0BC4FC"/>
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M0,0h17v17h-17z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M15.637,15.619H1.36V1.361H7.699V0.003H1.02C0.459,0.003 0,0.462 0,1.022V15.958C0,16.518 0.459,16.977 1.02,16.977H15.977C16.538,16.977 16.997,16.518 16.997,15.958V9.059H15.637V15.619V15.619Z"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M16.317,13.497C15.943,13.497 15.637,13.191 15.637,12.818V8.829C15.637,8.456 15.943,8.15 16.317,8.15C16.691,8.15 16.997,8.456 16.997,8.829V12.818C16.997,13.191 16.699,13.497 16.317,13.497ZM8.158,1.361H6.374C6,1.361 5.694,1.056 5.694,0.682C5.694,0.309 6,0.003 6.374,0.003H8.158C8.532,0.003 8.838,0.309 8.838,0.682C8.838,1.055 8.541,1.361 8.158,1.361V1.361ZM11.821,10.255H7.436C7.054,10.255 6.739,9.941 6.739,9.559C6.739,9.177 7.054,8.863 7.436,8.863H11.821C12.203,8.863 12.518,9.177 12.518,9.559C12.518,9.941 12.212,10.255 11.821,10.255Z"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
<group>
|
||||||
|
<clip-path
|
||||||
|
android:pathData="M17,0H0V17H17V0Z"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M6.739,9.559V5.18C6.739,4.798 7.054,4.484 7.436,4.484C7.819,4.484 8.133,4.798 8.133,5.18V9.559C8.133,9.941 7.819,10.255 7.436,10.255C7.054,10.255 6.739,9.941 6.739,9.559Z"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M6.952,10.051L6.943,10.043C6.68,9.78 6.68,9.355 6.943,9.092L15.841,0.199C16.104,-0.064 16.529,-0.064 16.793,0.199L16.801,0.207C17.065,0.47 17.065,0.895 16.801,1.158L7.895,10.051C7.632,10.314 7.207,10.314 6.952,10.051Z"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
45
app/src/main/res/drawable/multi_dialog.xml
Normal file
45
app/src/main/res/drawable/multi_dialog.xml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="41dp"
|
||||||
|
android:height="48dp"
|
||||||
|
android:viewportWidth="41"
|
||||||
|
android:viewportHeight="48">
|
||||||
|
<path
|
||||||
|
android:pathData="M33.969,22.647C33.721,22.75 33.043,22.69 32.086,21.816C30.403,20.282 25.605,20.639 24.026,20.8C23.775,20.348 23.478,19.576 23.9,19.171C24.031,19.06 24.185,18.968 24.345,18.909C25.394,18.476 27.308,18.386 27.954,18.386L29.089,18.386L25.385,9.407C25.347,9.264 25.35,8.895 26.096,8.587C26.842,8.28 27.273,8.498 27.419,8.611L29.252,13.055L29.843,12.905C32.874,12.152 37.43,11.656 38.045,12.888L40.524,18.897C40.524,18.897 40.684,19.249 40.513,19.608C40.383,19.878 40.075,20.113 39.596,20.311L33.981,22.642"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M10.966,22.294L20.294,12.034"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#9DB9C2"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M11.691,30.85L24.85,39.309"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#9DB9C2"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M24.5,6.5m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#ffffff"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M6.5,26.5m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#9DB9C2"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M30.5,41.5m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#436873"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M24.946,9H24.295V4.905L23.287,5.374L23.098,4.905L24.393,4.324H24.946V9Z"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M5.196,29V28.433C5.695,27.896 6.127,27.409 6.491,26.97C6.855,26.527 7.077,26.233 7.156,26.088C7.24,25.943 7.282,25.761 7.282,25.542C7.282,25.318 7.212,25.143 7.072,25.017C6.932,24.891 6.727,24.828 6.456,24.828C6.185,24.828 5.903,24.886 5.609,25.003L5.455,24.499C5.838,24.322 6.225,24.233 6.617,24.233C7.009,24.233 7.319,24.347 7.548,24.576C7.781,24.805 7.898,25.122 7.898,25.528C7.898,25.934 7.7,26.382 7.303,26.872C6.738,27.577 6.304,28.097 6.001,28.433H8.066L8.017,29H5.196Z"
|
||||||
|
android:fillColor="#9DB9C2"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M30.267,41.725H29.931V41.249H30.26C30.535,41.216 30.748,41.123 30.897,40.969C31.051,40.815 31.128,40.635 31.128,40.43C31.128,40.22 31.058,40.066 30.918,39.968C30.783,39.87 30.584,39.821 30.323,39.821C30.066,39.821 29.791,39.879 29.497,39.996L29.343,39.492C29.74,39.319 30.127,39.233 30.505,39.233C30.888,39.233 31.191,39.338 31.415,39.548C31.644,39.753 31.758,40.031 31.758,40.381C31.758,40.596 31.707,40.799 31.604,40.99C31.506,41.177 31.364,41.321 31.177,41.424C31.69,41.615 31.947,42.003 31.947,42.586C31.947,43.029 31.809,43.391 31.534,43.671C31.263,43.951 30.904,44.091 30.456,44.091C30.013,44.091 29.593,43.97 29.196,43.727L29.427,43.202C29.819,43.398 30.15,43.496 30.421,43.496C30.696,43.496 30.913,43.412 31.072,43.244C31.231,43.071 31.31,42.854 31.31,42.593C31.31,42.332 31.219,42.122 31.037,41.963C30.855,41.804 30.598,41.725 30.267,41.725Z"
|
||||||
|
android:fillColor="#436773"/>
|
||||||
|
</vector>
|
||||||
14
app/src/main/res/drawable/single_dialog.xml
Normal file
14
app/src/main/res/drawable/single_dialog.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="16dp"
|
||||||
|
android:height="20dp"
|
||||||
|
android:viewportWidth="16"
|
||||||
|
android:viewportHeight="20">
|
||||||
|
<path
|
||||||
|
android:pathData="M8.51,20C8.241,20 7.638,19.687 7.087,18.513C6.116,16.453 1.544,14.953 0.023,14.5C-0.036,13.987 -0.017,13.16 0.528,12.947C0.692,12.893 0.869,12.867 1.039,12.873C2.174,12.873 3.978,13.52 4.575,13.767L5.624,14.2V4.487C5.644,4.34 5.788,4 6.595,4C7.401,4 7.716,4.367 7.808,4.527V9.333L8.411,9.42C11.501,9.88 15.901,11.16 16,12.533V19.033C16,19.033 16.013,19.42 15.718,19.687C15.495,19.887 15.121,19.987 14.603,19.987L8.523,20"
|
||||||
|
android:fillColor="#ffffff"/>
|
||||||
|
<path
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:pathData="M6.5,6.5m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="#ffffff"/>
|
||||||
|
</vector>
|
||||||
@ -30,6 +30,12 @@
|
|||||||
app:layout_constraintStart_toEndOf="@+id/btn_back"
|
app:layout_constraintStart_toEndOf="@+id/btn_back"
|
||||||
app:layout_constraintTop_toTopOf="@+id/btn_back" />
|
app:layout_constraintTop_toTopOf="@+id/btn_back" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Group
|
||||||
|
android:id="@+id/no_scripts_group"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:constraint_referenced_ids="no_scripts, no_scripts_text, create, import_scripts" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/no_scripts"
|
android:id="@+id/no_scripts"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -43,6 +49,7 @@
|
|||||||
app:layout_constraintVertical_bias="0.38" />
|
app:layout_constraintVertical_bias="0.38" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/no_scripts_text"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/no_scripts_text"
|
android:text="@string/no_scripts_text"
|
||||||
@ -58,11 +65,11 @@
|
|||||||
android:id="@+id/create"
|
android:id="@+id/create"
|
||||||
android:layout_width="223dp"
|
android:layout_width="223dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
android:background="@drawable/btn_border_background"
|
android:background="@drawable/btn_border_background"
|
||||||
android:text="@string/create_now"
|
android:text="@string/create_now"
|
||||||
android:textAllCaps="false"
|
android:textAllCaps="false"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:layout_marginTop="32dp"
|
|
||||||
android:textSize="22sp"
|
android:textSize="22sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
@ -83,4 +90,34 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/create" />
|
app:layout_constraintTop_toBottomOf="@+id/create" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/scripts_recycler_view"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/title_scripts"
|
||||||
|
app:layout_constraintVertical_bias="1.0"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/fab_import_scripts"
|
||||||
|
android:layout_width="127dp"
|
||||||
|
android:layout_height="46dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:src="@drawable/import_script"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:backgroundTint="#0BC4FC"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:tint="@color/white" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
167
app/src/main/res/layout/dialog_create_mode_selection.xml
Normal file
167
app/src/main/res/layout/dialog_create_mode_selection.xml
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_rounded_rect"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="18dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/dialog_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Start New Script"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="25sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/btn_close_dialog"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:backgroundTint="@color/close_blue"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:src="@drawable/cancel"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:tint="@color/gray" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/layout_single_mode"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="120dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:background="@drawable/bg_mode_item_selector"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon_single"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:src="@drawable/ic_circle_hollow"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_single_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:text="Single Point Mode"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="19sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/icon_single"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_single_desc"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:text="Tap a single position repeatedly at\nspecified intervals"
|
||||||
|
android:textColor="@color/text_gray"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/iv_single_arrow"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/text_single_title"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/text_single_title" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_single_arrow"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:src="@drawable/single_dialog"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/layout_multi_mode"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="120dp"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:background="@drawable/bg_mode_item_selector"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon_multi"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:src="@drawable/ic_circle_hollow"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_multi_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:text="Multi-Point Mode"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="19sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/icon_multi"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_multi_desc"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:text="Set a series of taps/swipes in\ndifferent positions"
|
||||||
|
android:textColor="@color/text_gray"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/iv_multi_arrow"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/text_multi_title"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/text_multi_title" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_multi_arrow"
|
||||||
|
android:layout_width="41dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:src="@drawable/multi_dialog"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
|
android:id="@+id/btn_start_create"
|
||||||
|
android:layout_width="257dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="@drawable/bg_rounded_rect"
|
||||||
|
android:backgroundTint="@color/blue"
|
||||||
|
android:text="Start"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="21sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@ -2,7 +2,7 @@
|
|||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="321dp"
|
android:layout_width="321dp"
|
||||||
android:layout_height="386dp"
|
android:layout_height="420dp"
|
||||||
android:background="@drawable/bg_rounded_rect"
|
android:background="@drawable/bg_rounded_rect"
|
||||||
android:paddingBottom="25dp">
|
android:paddingBottom="25dp">
|
||||||
|
|
||||||
@ -285,4 +285,33 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
|
android:id="@+id/save"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:background="@drawable/btn_border_background"
|
||||||
|
android:text="Save"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:layout_marginTop="18dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
android:backgroundTint="#0BC4FC"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/dialog_repeat_input"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/close"
|
||||||
|
android:textColor="@color/white" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
|
android:id="@+id/close"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:background="@drawable/close_bg"
|
||||||
|
android:text="Close"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/save"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/save"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/save"
|
||||||
|
android:textColor="@color/white" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@ -1,28 +1,28 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="250dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="11dp"
|
||||||
android:background="@drawable/bg_rounded_rect"
|
android:background="@drawable/bg_rounded_rect"
|
||||||
android:backgroundTint="#164958"
|
android:backgroundTint="#164958"
|
||||||
android:layout_marginBottom="11dp"
|
|
||||||
android:padding="16dp">
|
android:padding="16dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textViewTopLeft"
|
android:id="@+id/name"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="My Script 1"
|
android:text="My Script 1"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/textViewBottomLeft"
|
app:layout_constraintBottom_toTopOf="@+id/mode"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_chainStyle="packed" />
|
app:layout_constraintVertical_chainStyle="packed" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textViewBottomLeft"
|
android:id="@+id/mode"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
@ -31,14 +31,24 @@
|
|||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textViewTopLeft" />
|
app:layout_constraintTop_toBottomOf="@+id/name" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/imageViewRight"
|
android:id="@+id/play"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="32dp"
|
||||||
android:src="@drawable/solution_play"
|
android:src="@drawable/solution_play"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/option"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/option"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/script_option"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|||||||
50
app/src/main/res/layout/option_menu_layout.xml
Normal file
50
app/src/main/res/layout/option_menu_layout.xml
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/bg_blue"
|
||||||
|
android:elevation="8dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_rename"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:text="Rename"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_duplicate"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:text="Duplicate"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_delete"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:text="Delete"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_export"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:text="Export"
|
||||||
|
android:textColor="@color/black"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@ -10,4 +10,5 @@
|
|||||||
<color name="button_gray">#446672</color>
|
<color name="button_gray">#446672</color>
|
||||||
<color name="button_selected">#1A546B</color>
|
<color name="button_selected">#1A546B</color>
|
||||||
<color name="button_unselected">#171717</color>
|
<color name="button_unselected">#171717</color>
|
||||||
|
<color name="close_blue">#368298</color>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
Reference in New Issue
Block a user