功能优化
This commit is contained in:
parent
73e2478168
commit
5a78b467fc
@ -9,8 +9,11 @@ import com.auto.clicker.autoclicker.room.entity.Solution;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose; // 确保导入 @Expose
|
||||||
|
|
||||||
public class SolutionWithEventsAndPoints {
|
public class SolutionWithEventsAndPoints {
|
||||||
@Embedded
|
@Embedded
|
||||||
|
@Expose
|
||||||
public Solution solution;
|
public Solution solution;
|
||||||
|
|
||||||
@Relation(
|
@Relation(
|
||||||
@ -18,10 +21,12 @@ public class SolutionWithEventsAndPoints {
|
|||||||
entityColumn = "solution_id",
|
entityColumn = "solution_id",
|
||||||
entity = EventEntity.class
|
entity = EventEntity.class
|
||||||
)
|
)
|
||||||
|
@Expose
|
||||||
public List<EventWithPoints> events;
|
public List<EventWithPoints> events;
|
||||||
|
|
||||||
public static class EventWithPoints {
|
public static class EventWithPoints {
|
||||||
@Embedded
|
@Embedded
|
||||||
|
@Expose
|
||||||
public EventEntity eventEntity;
|
public EventEntity eventEntity;
|
||||||
|
|
||||||
@Relation(
|
@Relation(
|
||||||
@ -29,6 +34,7 @@ public class SolutionWithEventsAndPoints {
|
|||||||
entityColumn = "pointId",
|
entityColumn = "pointId",
|
||||||
entity = TouchPoint.class
|
entity = TouchPoint.class
|
||||||
)
|
)
|
||||||
|
@Expose
|
||||||
public TouchPoint clickTouchPoint;
|
public TouchPoint clickTouchPoint;
|
||||||
|
|
||||||
@Relation(
|
@Relation(
|
||||||
@ -36,6 +42,7 @@ public class SolutionWithEventsAndPoints {
|
|||||||
entityColumn = "pointId",
|
entityColumn = "pointId",
|
||||||
entity = TouchPoint.class
|
entity = TouchPoint.class
|
||||||
)
|
)
|
||||||
|
@Expose
|
||||||
public TouchPoint slideStartTouchPoint;
|
public TouchPoint slideStartTouchPoint;
|
||||||
|
|
||||||
@Relation(
|
@Relation(
|
||||||
@ -43,6 +50,7 @@ public class SolutionWithEventsAndPoints {
|
|||||||
entityColumn = "pointId",
|
entityColumn = "pointId",
|
||||||
entity = TouchPoint.class
|
entity = TouchPoint.class
|
||||||
)
|
)
|
||||||
|
@Expose
|
||||||
public TouchPoint slideEndTouchPoint;
|
public TouchPoint slideEndTouchPoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,6 +164,73 @@ public class EventRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
public void importSolutionFromData(SolutionWithEventsAndPoints importedData, RepositoryCallback<Void> callback) {
|
||||||
|
databaseWriteExecutor.execute(() -> {
|
||||||
|
try {
|
||||||
|
Solution newSolution = new Solution(importedData.solution.solutionName, importedData.solution.mode);
|
||||||
|
long newSolutionId = solutionDao.insertSolution(newSolution);
|
||||||
|
|
||||||
|
if (newSolutionId == -1) {
|
||||||
|
throw new RuntimeException("Failed to import solution: Could not insert new Solution.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SolutionWithEventsAndPoints.EventWithPoints eventWithPoints : importedData.events) {
|
||||||
|
Long newClickPointId = null;
|
||||||
|
if (eventWithPoints.clickTouchPoint != null) {
|
||||||
|
TouchPoint newClickPoint = new TouchPoint(eventWithPoints.clickTouchPoint.x, eventWithPoints.clickTouchPoint.y);
|
||||||
|
newClickPointId = touchPointDao.insertPoint(newClickPoint);
|
||||||
|
if (newClickPointId == -1) throw new RuntimeException("Failed to import click point.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Long newSlideStartPointId = null;
|
||||||
|
if (eventWithPoints.slideStartTouchPoint != null) {
|
||||||
|
TouchPoint newSlideStartPoint = new TouchPoint(eventWithPoints.slideStartTouchPoint.x, eventWithPoints.slideStartTouchPoint.y);
|
||||||
|
newSlideStartPointId = touchPointDao.insertPoint(newSlideStartPoint);
|
||||||
|
if (newSlideStartPointId == -1) throw new RuntimeException("Failed to import slide start point.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Long newSlideEndPointId = null;
|
||||||
|
if (eventWithPoints.slideEndTouchPoint != null) {
|
||||||
|
TouchPoint newSlideEndPoint = new TouchPoint(eventWithPoints.slideEndTouchPoint.x, eventWithPoints.slideEndTouchPoint.y);
|
||||||
|
newSlideEndPointId = touchPointDao.insertPoint(newSlideEndPoint);
|
||||||
|
if (newSlideEndPointId == -1) throw new RuntimeException("Failed to import slide end point.");
|
||||||
|
}
|
||||||
|
|
||||||
|
EventEntity newEventEntity = new EventEntity(
|
||||||
|
newSolutionId, // 关联到新生成的方案ID
|
||||||
|
eventWithPoints.eventEntity.eventType,
|
||||||
|
eventWithPoints.eventEntity.orderInSolution,
|
||||||
|
newClickPointId,
|
||||||
|
newSlideStartPointId,
|
||||||
|
newSlideEndPointId,
|
||||||
|
eventWithPoints.eventEntity.duration
|
||||||
|
);
|
||||||
|
long newEventEntityId = eventEntityDao.insertEventEntity(newEventEntity);
|
||||||
|
if (newEventEntityId == -1) {
|
||||||
|
throw new RuntimeException("Failed to import event entity.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (callback != null) callback.onComplete(null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("EventRepository", "Error importing solution: " + e.getMessage(), e);
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public SolutionWithEventsAndPoints importSolutionFromJson(String jsonString) {
|
||||||
|
try {
|
||||||
|
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
|
||||||
|
return gson.fromJson(jsonString, SolutionWithEventsAndPoints.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("EventRepository", "Error parsing JSON for import: " + e.getMessage(), e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
public void saveDuplicateSolution(SolutionWithEventsAndPoints originalData, RepositoryCallback<Void> callback) {
|
public void saveDuplicateSolution(SolutionWithEventsAndPoints originalData, RepositoryCallback<Void> callback) {
|
||||||
databaseWriteExecutor.execute(() -> {
|
databaseWriteExecutor.execute(() -> {
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import android.os.Looper;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.activity.EdgeToEdge;
|
import androidx.activity.EdgeToEdge;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@ -28,6 +27,9 @@ import com.auto.clicker.autoclicker.ui.adapter.floating.SolutionAdapter;
|
|||||||
import com.auto.clicker.autoclicker.ui.dialog.CreateModeSelectionDialog;
|
import com.auto.clicker.autoclicker.ui.dialog.CreateModeSelectionDialog;
|
||||||
import com.auto.clicker.autoclicker.view.FloatingViewManager;
|
import com.auto.clicker.autoclicker.view.FloatingViewManager;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -40,6 +42,7 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
|
|
||||||
private static final String TAG = "ScriptsActivity";
|
private static final String TAG = "ScriptsActivity";
|
||||||
private static final int CREATE_FILE_REQUEST_CODE = 1;
|
private static final int CREATE_FILE_REQUEST_CODE = 1;
|
||||||
|
private static final int PICK_FILE_REQUEST_CODE = 2;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@ -54,12 +57,10 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
});
|
});
|
||||||
|
|
||||||
binding.scriptsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
binding.scriptsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
// 将 this 作为 OnSolutionClickListener 和 OnOptionMenuClickListener 传入
|
|
||||||
solutionsAdapter = new SolutionAdapter(new ArrayList<>(), this::onSolutionSelected, this);
|
solutionsAdapter = new SolutionAdapter(new ArrayList<>(), this::onSolutionSelected, this);
|
||||||
binding.scriptsRecyclerView.setAdapter(solutionsAdapter);
|
binding.scriptsRecyclerView.setAdapter(solutionsAdapter);
|
||||||
|
|
||||||
// 确保 FloatingViewManager 在 Activity 创建时被初始化
|
floatingViewManager = new FloatingViewManager(this);
|
||||||
floatingViewManager = new FloatingViewManager(this); // 如果 FloatingViewManager 依赖 Context,这里需要传递
|
|
||||||
|
|
||||||
binding.btnBack.setOnClickListener(v -> finish());
|
binding.btnBack.setOnClickListener(v -> finish());
|
||||||
|
|
||||||
@ -69,13 +70,11 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
});
|
});
|
||||||
|
|
||||||
binding.importScripts.setOnClickListener(v -> {
|
binding.importScripts.setOnClickListener(v -> {
|
||||||
Toast.makeText(this, "导入方案功能待实现", Toast.LENGTH_SHORT).show();
|
pickJsonFileForImport();
|
||||||
// TODO: 实现导入方案的逻辑
|
|
||||||
});
|
});
|
||||||
|
|
||||||
binding.fabImportScripts.setOnClickListener(v -> {
|
binding.customImportView.setOnClickListener(v -> {
|
||||||
Toast.makeText(this, "右下角导入方案功能待实现", Toast.LENGTH_SHORT).show();
|
pickJsonFileForImport();
|
||||||
// TODO: 实现右下角导入方案的逻辑,可能与上面的importScripts按钮功能相同或类似
|
|
||||||
});
|
});
|
||||||
|
|
||||||
loadSolutions();
|
loadSolutions();
|
||||||
@ -90,24 +89,16 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
private void loadSolutions() {
|
private void loadSolutions() {
|
||||||
if (floatingViewManager == null) {
|
if (floatingViewManager == null) {
|
||||||
Log.e(TAG, "FloatingViewManager 未设置,无法加载方案列表。");
|
Log.e(TAG, "FloatingViewManager 未设置,无法加载方案列表。");
|
||||||
Toast.makeText(this, "加载方案列表功能不可用,请联系开发者。", Toast.LENGTH_SHORT).show();
|
|
||||||
updateLayout(true);
|
updateLayout(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保 FloatingViewManager 能够提供 EventRepository 实例
|
|
||||||
// 假设 FloatingViewManager 内部管理着 EventRepository
|
|
||||||
floatingViewManager.getEventRepository().getAllSolutions(new EventRepository.RepositoryCallback<List<Solution>>() {
|
floatingViewManager.getEventRepository().getAllSolutions(new EventRepository.RepositoryCallback<List<Solution>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onComplete(List<Solution> solutions) {
|
public void onComplete(List<Solution> solutions) {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
solutionsAdapter.setSolutions(solutions);
|
solutionsAdapter.setSolutions(solutions);
|
||||||
updateLayout(solutions.isEmpty());
|
updateLayout(solutions.isEmpty());
|
||||||
if (solutions.isEmpty()) {
|
|
||||||
Toast.makeText(ScriptsActivity.this, "没有可加载的方案。", Toast.LENGTH_SHORT).show();
|
|
||||||
} else {
|
|
||||||
Toast.makeText(ScriptsActivity.this, "方案加载成功!", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +106,6 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
public void onError(Exception e) {
|
public void onError(Exception e) {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
Log.e(TAG, "加载方案列表失败: " + e.getMessage(), e);
|
Log.e(TAG, "加载方案列表失败: " + e.getMessage(), e);
|
||||||
Toast.makeText(ScriptsActivity.this, "加载方案列表失败。", Toast.LENGTH_SHORT).show();
|
|
||||||
updateLayout(true);
|
updateLayout(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -126,11 +116,11 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
if (isEmpty) {
|
if (isEmpty) {
|
||||||
binding.noScriptsGroup.setVisibility(View.VISIBLE);
|
binding.noScriptsGroup.setVisibility(View.VISIBLE);
|
||||||
binding.scriptsRecyclerView.setVisibility(View.GONE);
|
binding.scriptsRecyclerView.setVisibility(View.GONE);
|
||||||
binding.fabImportScripts.setVisibility(View.GONE);
|
binding.customImportView.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
binding.noScriptsGroup.setVisibility(View.GONE);
|
binding.noScriptsGroup.setVisibility(View.GONE);
|
||||||
binding.scriptsRecyclerView.setVisibility(View.VISIBLE);
|
binding.scriptsRecyclerView.setVisibility(View.VISIBLE);
|
||||||
binding.fabImportScripts.setVisibility(View.VISIBLE);
|
binding.customImportView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,10 +128,8 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
if (floatingViewManager != null) {
|
if (floatingViewManager != null) {
|
||||||
floatingViewManager.showFloatingViews(solution.getMode());
|
floatingViewManager.showFloatingViews(solution.getMode());
|
||||||
floatingViewManager.loadSolution(solution.getSolutionId());
|
floatingViewManager.loadSolution(solution.getSolutionId());
|
||||||
Toast.makeText(this, "正在加载方案: " + solution.getSolutionName(), Toast.LENGTH_SHORT).show();
|
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "FloatingViewManager 未设置!无法加载方案。");
|
Log.e(TAG, "FloatingViewManager 未设置!无法加载方案。");
|
||||||
Toast.makeText(this, "加载功能不可用,请联系开发者。", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,8 +168,7 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
@Override
|
@Override
|
||||||
public void onComplete(Void result) {
|
public void onComplete(Void result) {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
Toast.makeText(ScriptsActivity.this, "方案已重命名为: " + newName, Toast.LENGTH_SHORT).show();
|
loadSolutions();
|
||||||
loadSolutions(); // 刷新列表
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,14 +176,9 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
public void onError(Exception e) {
|
public void onError(Exception e) {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
Log.e(TAG, "重命名失败: " + e.getMessage(), e);
|
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();
|
|
||||||
} else {
|
|
||||||
Toast.makeText(ScriptsActivity.this, "新名称与原名称相同。", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
builder.setNegativeButton("取消", (dialog, which) -> dialog.cancel());
|
builder.setNegativeButton("取消", (dialog, which) -> dialog.cancel());
|
||||||
@ -211,23 +193,18 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
floatingViewManager.getEventRepository().saveDuplicateSolution(originalData, new EventRepository.RepositoryCallback<Void>() {
|
floatingViewManager.getEventRepository().saveDuplicateSolution(originalData, new EventRepository.RepositoryCallback<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public void onComplete(Void result) {
|
public void onComplete(Void result) {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(ScriptsActivity.this::loadSolutions);
|
||||||
Toast.makeText(ScriptsActivity.this, "方案 '" + originalSolution.getSolutionName() + "' 已复制成功!", Toast.LENGTH_SHORT).show();
|
|
||||||
loadSolutions(); // 刷新列表
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Exception e) {
|
public void onError(Exception e) {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
Log.e(TAG, "复制方案失败: " + e.getMessage(), e);
|
Log.e(TAG, "复制方案失败: " + e.getMessage(), e);
|
||||||
Toast.makeText(ScriptsActivity.this, "复制方案失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
Toast.makeText(ScriptsActivity.this, "无法找到原始方案数据进行复制。", Toast.LENGTH_SHORT).show();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,7 +213,6 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
public void onError(Exception e) {
|
public void onError(Exception e) {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
Log.e(TAG, "获取原始方案数据失败: " + e.getMessage(), e);
|
Log.e(TAG, "获取原始方案数据失败: " + e.getMessage(), e);
|
||||||
Toast.makeText(ScriptsActivity.this, "获取原始方案数据失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -256,8 +232,7 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
@Override
|
@Override
|
||||||
public void onComplete(Void result) {
|
public void onComplete(Void result) {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
Toast.makeText(ScriptsActivity.this, "方案 '" + solution.getSolutionName() + "' 已删除。", Toast.LENGTH_SHORT).show();
|
loadSolutions();
|
||||||
loadSolutions(); // 刷新列表
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,12 +240,18 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
public void onError(Exception e) {
|
public void onError(Exception e) {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
Log.e(TAG, "删除方案失败: " + e.getMessage(), e);
|
Log.e(TAG, "删除方案失败: " + e.getMessage(), e);
|
||||||
Toast.makeText(ScriptsActivity.this, "删除方案失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void pickJsonFileForImport() {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||||
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
|
intent.setType("application/json");
|
||||||
|
startActivityForResult(intent, PICK_FILE_REQUEST_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
private void exportSolution(final Solution solution) {
|
private void exportSolution(final Solution solution) {
|
||||||
floatingViewManager.getEventRepository().getSolutionWithEventsAndPoints(solution.getSolutionId(), new EventRepository.RepositoryCallback<SolutionWithEventsAndPoints>() {
|
floatingViewManager.getEventRepository().getSolutionWithEventsAndPoints(solution.getSolutionId(), new EventRepository.RepositoryCallback<SolutionWithEventsAndPoints>() {
|
||||||
@Override
|
@Override
|
||||||
@ -283,11 +264,7 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
intent.setType("application/json");
|
intent.setType("application/json");
|
||||||
intent.putExtra(Intent.EXTRA_TITLE, solution.getSolutionName() + ".json");
|
intent.putExtra(Intent.EXTRA_TITLE, solution.getSolutionName() + ".json");
|
||||||
startActivityForResult(intent, CREATE_FILE_REQUEST_CODE);
|
startActivityForResult(intent, CREATE_FILE_REQUEST_CODE);
|
||||||
} else {
|
|
||||||
Toast.makeText(ScriptsActivity.this, "无法生成导出数据。", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Toast.makeText(ScriptsActivity.this, "无法获取方案数据进行导出。", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,12 +272,57 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
public void onError(Exception e) {
|
public void onError(Exception e) {
|
||||||
new Handler(Looper.getMainLooper()).post(() -> {
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
Log.e(TAG, "获取方案数据失败: " + e.getMessage(), e);
|
Log.e(TAG, "获取方案数据失败: " + e.getMessage(), e);
|
||||||
Toast.makeText(ScriptsActivity.this, "获取方案数据失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void importSolutionFromFile(Uri uri) {
|
||||||
|
try {
|
||||||
|
InputStream inputStream = getContentResolver().openInputStream(uri);
|
||||||
|
if (inputStream == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
stringBuilder.append(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String jsonString = stringBuilder.toString();
|
||||||
|
if (jsonString.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SolutionWithEventsAndPoints importedData = floatingViewManager.getEventRepository().importSolutionFromJson(jsonString);
|
||||||
|
|
||||||
|
if (importedData != null && importedData.solution != null) {
|
||||||
|
// 保存到数据库
|
||||||
|
floatingViewManager.getEventRepository().importSolutionFromData(importedData, new EventRepository.RepositoryCallback<Void>() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(Void result) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
loadSolutions(); // 刷新列表
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) {
|
||||||
|
new Handler(Looper.getMainLooper()).post(() -> {
|
||||||
|
Log.e(TAG, "导入方案失败: " + e.getMessage(), e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "读取或解析导入文件失败: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
@ -311,20 +333,20 @@ public class ScriptsActivity extends AppCompatActivity implements SolutionAdapte
|
|||||||
try (OutputStream outputStream = getContentResolver().openOutputStream(uri)) {
|
try (OutputStream outputStream = getContentResolver().openOutputStream(uri)) {
|
||||||
if (outputStream != null) {
|
if (outputStream != null) {
|
||||||
outputStream.write(tempExportJson.getBytes());
|
outputStream.write(tempExportJson.getBytes());
|
||||||
Toast.makeText(this, "方案已成功导出!", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "保存文件失败: " + e.getMessage(), e);
|
Log.e(TAG, "保存文件失败: " + e.getMessage(), e);
|
||||||
Toast.makeText(this, "保存文件失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
|
||||||
} finally {
|
} finally {
|
||||||
tempExportJson = null; // 清除临时数据
|
tempExportJson = null;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Toast.makeText(this, "没有可导出的数据。", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Toast.makeText(this, "文件创建操作被取消或数据无效。", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (requestCode == PICK_FILE_REQUEST_CODE && resultCode == RESULT_OK) {
|
||||||
|
if (data != null && data.getData() != null) {
|
||||||
|
Uri uri = data.getData();
|
||||||
|
importSolutionFromFile(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -76,12 +76,12 @@ public class SolutionAdapter extends RecyclerView.Adapter<SolutionAdapter.Soluti
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (optionMenuListener != null) {
|
if (optionMenuListener != null) {
|
||||||
holder.option.setVisibility(View.VISIBLE); // 显示按钮
|
holder.option.setVisibility(View.VISIBLE);
|
||||||
holder.option.setOnClickListener(v -> {
|
holder.option.setOnClickListener(v -> {
|
||||||
holder.showOptionMenu(solution, optionMenuListener); // 调用方法显示菜单
|
holder.showOptionMenu(solution, optionMenuListener);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
holder.option.setVisibility(View.GONE); // 隐藏按钮
|
holder.option.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,28 +114,25 @@ public class SolutionAdapter extends RecyclerView.Adapter<SolutionAdapter.Soluti
|
|||||||
option = itemView.findViewById(R.id.option);
|
option = itemView.findViewById(R.id.option);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示选项菜单的私有方法
|
|
||||||
private void showOptionMenu(Solution solution, OnOptionMenuClickListener menuListener) {
|
private void showOptionMenu(Solution solution, OnOptionMenuClickListener menuListener) {
|
||||||
View popupView = LayoutInflater.from(context).inflate(R.layout.option_menu_layout, null);
|
View popupView = LayoutInflater.from(context).inflate(R.layout.option_menu_layout, null);
|
||||||
PopupWindow popupWindow = new PopupWindow(
|
PopupWindow popupWindow = new PopupWindow(
|
||||||
popupView,
|
popupView,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
true // 设置为 true,允许点击外部关闭
|
true
|
||||||
);
|
);
|
||||||
popupWindow.setElevation(8f); // 添加阴影
|
popupWindow.setElevation(8f);
|
||||||
popupWindow.setBackgroundDrawable(context.getDrawable(android.R.color.transparent)); // 设置透明背景,以便显示阴影
|
popupWindow.setBackgroundDrawable(context.getDrawable(android.R.color.transparent));
|
||||||
|
|
||||||
// 查找 popupView 中的 TextView
|
|
||||||
TextView tvRename = popupView.findViewById(R.id.tv_rename);
|
TextView tvRename = popupView.findViewById(R.id.tv_rename);
|
||||||
TextView tvDuplicate = popupView.findViewById(R.id.tv_duplicate);
|
TextView tvDuplicate = popupView.findViewById(R.id.tv_duplicate);
|
||||||
TextView tvDelete = popupView.findViewById(R.id.tv_delete);
|
TextView tvDelete = popupView.findViewById(R.id.tv_delete);
|
||||||
TextView tvExport = popupView.findViewById(R.id.tv_export);
|
TextView tvExport = popupView.findViewById(R.id.tv_export);
|
||||||
|
|
||||||
// 设置点击监听器
|
|
||||||
tvRename.setOnClickListener(v -> {
|
tvRename.setOnClickListener(v -> {
|
||||||
menuListener.onRenameClick(solution);
|
menuListener.onRenameClick(solution);
|
||||||
popupWindow.dismiss(); // 关闭弹窗
|
popupWindow.dismiss();
|
||||||
});
|
});
|
||||||
|
|
||||||
tvDuplicate.setOnClickListener(v -> {
|
tvDuplicate.setOnClickListener(v -> {
|
||||||
@ -153,7 +150,6 @@ public class SolutionAdapter extends RecyclerView.Adapter<SolutionAdapter.Soluti
|
|||||||
popupWindow.dismiss();
|
popupWindow.dismiss();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 显示 PopupWindow,锚定在 option 按钮下方
|
|
||||||
popupWindow.showAsDropDown(option);
|
popupWindow.showAsDropDown(option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,7 +84,7 @@ public class FloatingViewManager {
|
|||||||
private static final String KEY_CONTROL_BAR_WIDTH = "control_bar_width";
|
private static final String KEY_CONTROL_BAR_WIDTH = "control_bar_width";
|
||||||
|
|
||||||
private static final int DEFAULT_TOUCH_POINT_SIZE = 100;
|
private static final int DEFAULT_TOUCH_POINT_SIZE = 100;
|
||||||
private static final int DEFAULT_CONTROL_BAR_WIDTH_DP = 38;
|
private static final int DEFAULT_CONTROL_BAR_WIDTH_DP = 50;
|
||||||
|
|
||||||
private ImageView playButton;
|
private ImageView playButton;
|
||||||
|
|
||||||
|
|||||||
@ -96,8 +96,9 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginBottom="15dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toTopOf="@+id/custom_import_view"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
@ -105,19 +106,42 @@
|
|||||||
app:layout_constraintVertical_bias="1.0"
|
app:layout_constraintVertical_bias="1.0"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<LinearLayout
|
||||||
android:id="@+id/fab_import_scripts"
|
android:id="@+id/custom_import_view"
|
||||||
android:layout_width="127dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="46dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
|
android:background="@drawable/rounded_edittext_background"
|
||||||
|
android:backgroundTint="@color/blue"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:src="@drawable/import_script"
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingEnd="24dp"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:backgroundTint="#0BC4FC"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
app:tint="@color/white" />
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/icon_import"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@drawable/import_script" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_import"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:text="Import"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@ -48,7 +48,9 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:src="@drawable/script_option"
|
android:src="@drawable/script_option"
|
||||||
android:visibility="gone"
|
android:paddingEnd="10dp"
|
||||||
|
android:paddingStart="10dp"
|
||||||
|
android:visibility="visible"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
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" />
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
android:text="Rename"
|
android:text="Rename"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/white"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -24,7 +24,7 @@
|
|||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
android:text="Duplicate"
|
android:text="Duplicate"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/white"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -34,7 +34,7 @@
|
|||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
android:text="Delete"
|
android:text="Delete"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/white"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -44,7 +44,7 @@
|
|||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
android:text="Export"
|
android:text="Export"
|
||||||
android:textColor="@color/black"
|
android:textColor="@color/white"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
Loading…
Reference in New Issue
Block a user