feat: 与文件系统的交互迁移至Android存储访问框架(SAF),所有文件改为Uri形式

This commit is contained in:
ProjectXero 2022-11-08 11:14:30 +08:00
parent 83df2b32c3
commit 21d3ee3f3a
No known key found for this signature in database
GPG Key ID: C6021259092968FC
13 changed files with 1779 additions and 459 deletions

View File

@ -1,9 +1,6 @@
@downloadSource
{
"酷安网(最推荐)": "https://www.coolapk.com/game/com.xero.ca",
"话唠兔的小站(直链)": "https://projectxero.top/ca/release.apk",
"Gitee": "https://gitee.com/projectxero/ca/releases",
"反馈群加群303697689获得": "https://jq.qq.com/?_wv=1027&k=5OOYWLn"
"官方网站(最推荐)": "https://projectxero.top/ca/release.apk"
}
@end downloadSource
可用的下载地址

View File

@ -21,6 +21,8 @@
"edit": "Edit",
"edit_desc": "Return to edit JSON",
"nowhereEditable": "Nowhere is editable",
"replace": "Replace",
"replace_desc": "Create a new JSON and replace the original",
"copy": "Copy",
"copy_desc": "Copy JSON value",
"copy_success": "JSON value copied",

View File

@ -28,6 +28,7 @@
"path": "路径",
"fileName": "文件名",
"fileNotExist": "文件或目录不存在",
"directoryCannotRead": "目录不存在或拒绝访问",
"createDir": "新建文件夹",
"emptyDirName": "文件夹名称不能为空",
"errCreateDir": "创建目录失败%n%s",
@ -35,6 +36,7 @@
"emptyFileName": "文件名不能为空",
"dirAlreadyExist": "同名目录已存在",
"invaildFileName": "无效的文件名",
"loading": "获取文件列表中……",
"errAccessDir": "拒绝访问%n%s"
}
}

View File

@ -21,6 +21,8 @@
"edit": "继续编辑",
"edit_desc": "继续编辑JSON",
"nowhereEditable": "该JSON没有可以编辑的地方",
"replace": "替换",
"replace_desc": "新建JSON并替换原有内容",
"copy": "复制",
"copy_desc": "复制JSON",
"copy_success": "JSON已复制至剪贴板",

View File

@ -267,7 +267,7 @@ var proto = {
return (this.println("Debug", this.debug("D", s, 0).join("\n")), s);
},
t : function self(s) { //显示Toast
ctx.runOnUiThread(function() {
gHandler.post(function() {
if (self.last) self.last.cancel();
(self.last = android.widget.Toast.makeText(ctx, String(s), 0)).show();
});
@ -335,7 +335,7 @@ MapScript.loadModule("erp", function self(error, silent, extra) {
if (extra) tech += "\n" + Log.debug("额外数据", extra, 0).join("\n");
android.util.Log.e("CA", tech);
try {
var fs = new java.io.PrintWriter(new java.io.FileOutputStream(android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/com.xero.ca.error.log", true));
var fs = new java.io.PrintWriter(new java.io.FileOutputStream(MapScript.baseDir + "com.xero.ca.error.log", true));
fs.println("* " + (silent ? "Warning" : "Error") + ": " + new Date().toLocaleString());
fs.println(tech);
fs.close();
@ -381,7 +381,7 @@ MapScript.loadModule("erp", function self(error, silent, extra) {
var dialog = new android.app.AlertDialog.Builder(ctx);
dialog.setTitle("错误");
dialog.setCancelable(false);
dialog.setMessage("您好," + error.fileName + "出现了一个错误。您可以将这个错误反馈给我们来推动这个Mod的更新。您也可以选择忽略。作者联系方式QQ-814518615(Xero)\n\n错误信息\n" + tech);
dialog.setMessage("您好," + error.fileName + "出现了一个错误。您可以将这个错误反馈给我们来推动这个Mod的更新。您也可以选择忽略。您可以直接在设置-关于-意见与反馈里进行反馈也可直接联系作者QQ-2687587184Email-projectxero@163.com\n\n错误信息\n" + tech);
dialog.setPositiveButton("忽略", new android.content.DialogInterface.OnClickListener({
onClick : function(dia,w) {
dia.dismiss();
@ -676,6 +676,8 @@ Loader.fromFile("modules/MCAdapter.js")
Loader.fromFile("modules/AndroidBridge.js")
Loader.fromFile("modules/utils/ExternalStorage.js")
Loader.fromFile("modules/core/DexPlugin.js")
Loader.fromFile("modules/NeteaseAdapter.js")

View File

@ -136,23 +136,30 @@ MapScript.loadModule("AndroidBridge", {
if (!intent) return;
switch (intent.getAction()) {
case ScriptInterface.ACTION_ADD_LIBRARY:
t = AndroidBridge.uriToFile(intent.getData());
t = intent.getData();
if (!t) {
Common.toast("无法从" + intent.getData() + "读取拓展包");
Common.toast("无法读取拓展包");
break;
}
Common.showConfirmDialog({
title : "确定加载拓展包“" + t + "”?",
title : "确定加载拓展包“" + ExternalStorage.uriToName(t) + "”?",
callback : function(id) {
if (id != 0) return onReturn();
if (!CA.Library.enableLibrary(String(t))) {
Common.toast("无法导入该拓展包,可能文件不存在");
const importFile = ExternalStorage.importFile(t, "caclib_*.json");
try {
CA.Library.enableLibrary(String(ExternalStorage.toUri(importFile)));
CA.Library.initLibrary(function() {
Common.toast("导入成功!");
CA.showLibraryMan(onReturn);
});
} catch(e) {
Log.e(e);
Common.toast("无法导入该拓展包\n" + e);
return CA.showLibraryMan(onReturn);
}
CA.Library.initLibrary(function() {
Common.toast("导入成功!");
CA.showLibraryMan(onReturn);
});
},
onDismiss : function() {
ctx.revokeUriPermission(ctx.getPackageName(), t, 0x3); // Intent.FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION
}
});
break;
@ -249,12 +256,12 @@ MapScript.loadModule("AndroidBridge", {
},
openUriAction : function(uri, extras) {
if (!uri) return;
var path, obj, query, fragment;
path = uri.getPath();
query = uri.getEncodedQuery();
fragment = uri.getFragment();
switch (String(uri.getHost()).toLowerCase()) {
case "base":
var path, obj, query, fragment;
path = uri.getPath();
query = uri.getEncodedQuery();
fragment = uri.getFragment();
if (path) {
obj = this.getBaseUriAction(String(path));
if (obj) {
@ -338,14 +345,14 @@ MapScript.loadModule("AndroidBridge", {
},
onclick : function(fset) {
var self = this;
AndroidBridge.listApp(function(pkg) {
AndroidBridge.listLaunchableApp(function(pkg) {
if (pkg == ctx.getPackageName()) {
Common.toast("不能连锁启动自身!");
return;
}
CA.settings.chainLaunch = pkg;
fset(self.get());
});
}, true);
}
}, {
name : "WebSocket服务器",
@ -391,12 +398,6 @@ MapScript.loadModule("AndroidBridge", {
CA.settings.hideRecent = Boolean(v);
Common.toast("本项设置将在重启命令助手后应用");
}
}, {
name : "隐藏通知",
description : "可能导致应用被自动关闭",
type : "boolean",
get : preference.getHideNotification.bind(preference),
set : ScriptInterface.setHideNotification.bind(ScriptInterface)
}, {
name : "自动启动无障碍服务",
description : "需要Root",
@ -523,15 +524,18 @@ MapScript.loadModule("AndroidBridge", {
};
}
},
listApp : function(callback) {
listLaunchableApp : function(callback, includeCancel) {
Common.showProgressDialog(function(o) {
var pm = ctx.getPackageManager();
o.setText("正在加载列表……");
o.setTextDelayed("正在加载列表……", 200);
var lp = pm.getInstalledPackages(0).toArray();
var i, r = [{
text : "不使用",
result : null
}];
var i, r = [];
if (includeCancel) {
r.push({
text : "取消选择",
result : null
});
}
for (i in lp) {
if (!lp[i].applicationInfo) continue;
if (!pm.getLaunchIntentForPackage(lp[i].packageName)) continue;
@ -548,6 +552,9 @@ MapScript.loadModule("AndroidBridge", {
});
}, true);
},
listApp : function(callback) { // Deprecated
this.listLaunchableApp(callback, true);
},
startActivity : function(intent) {
try {
if (ctx.getPackageManager().queryIntentActivities(intent, android.content.pm.PackageManager.MATCH_DEFAULT_ONLY).size() > 0) {
@ -769,48 +776,49 @@ MapScript.loadModule("AndroidBridge", {
var i = new android.content.Intent(android.content.Intent.ACTION_GET_CONTENT);
i.setType(mimeType);
this.startActivityForResult(i, function(resultCode, data) {
if (resultCode != -1) return; // RESULT_OK = -1
if (resultCode != -1) return; // RESULT_OK
callback(AndroidBridge.uriToFile(data.getData()));
});
},
selectImage : function(callback) {
if (MapScript.host == "Android") {
try {
this.selectFile("image/*", function(path) {
callback(path);
});
return;
} catch(e) {erp(e, true)}
}
Common.showFileDialog({
type : 0,
check : function(path) {
var bmp = G.BitmapFactory.decodeFile(path.getAbsolutePath());
if (!bmp) {
Common.toast("不支持的图片格式");
return false;
}
bmp.recycle();
return true;
},
callback : function(f) {
var path = String(f.result.getAbsolutePath());
try {
this.selectFile("image/*", function(path) {
callback(path);
}
});
});
return;
} catch(e) {erp(e, true)}
},
sendText : function(text, withSharesheet) {
let intent = new android.content.Intent(android.content.Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(android.content.Intent.EXTRA_TEXT, new java.lang.String(String(text)));
if (withSharesheet) {
intent = android.content.Intent.createChooser(intent, null);
}
return this.startActivity(intent);
},
sendUri : function(uri, mimeType, withSharesheet) {
let intent = new android.content.Intent(android.content.Intent.ACTION_SEND);
intent.setType(mimeType);
intent.putExtra(android.content.Intent.EXTRA_STREAM, uri);
intent.addFlags(android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION | android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
if (withSharesheet) {
intent = android.content.Intent.createChooser(intent, null);
}
return this.startActivity(intent);
},
sendFile : function(file, mimeType, withSharesheet) {
return this.sendUri(this.fileToUri(file), mimeType, withSharesheet);
},
shareText : function(text) {
return this.sendText(text, true);
},
viewUri : function(uri) {
return AndroidBridge.startActivity(new android.content.Intent(android.content.Intent.ACTION_VIEW, android.net.Uri.parse(uri)));
},
createShortcut : function(intent, name, icon) {
if (android.os.Build.VERSION.SDK_INT >= 26) {
if (ScriptInterface.isForeground()) {
AndroidBridge.doCreateShortcut(ctx, intent, name, icon);
} else {
this.beginForegroundTask("createShortcut@" + intent.hashCode().toString(16), function(activity) {
AndroidBridge.doCreateShortcut(activity, intent, name, icon);
});
}
AndroidBridge.doCreateShortcut(ctx, intent, name, icon);
} else {
var i = new android.content.Intent("com.android.launcher.action.INSTALL_SHORTCUT");
i.putExtra(android.content.Intent.EXTRA_SHORTCUT_NAME, name);
@ -976,23 +984,6 @@ MapScript.loadModule("AndroidBridge", {
},
checkNecessaryPermissions : function(callback) {
AndroidBridge.requestPermissionsByGroup([{
permissions : [
"android.permission.READ_EXTERNAL_STORAGE",
"android.permission.WRITE_EXTERNAL_STORAGE"
],
explanation : "读取内部存储\n写入内部存储\n\n这些权限将用于读写命令库、编辑JSON、记录错误日志等",
callback : function(flag, success, denied, sync) {
if (!sync) {
if (flag) {
CA.load();
Common.toast("权限请求成功,已重新加载配置");
} else {
Common.toast("权限请求失败\n将造成部分命令库无法读取等问题");
}
}
},
mode : 2
}, {
permissions : [
"android.permission.READ_PHONE_STATE"
],

View File

@ -4,7 +4,7 @@
loadingStatus : null,
currentLoadingLibrary : null,
initLibrary : function(callback) {
var info, flag = true, t, t2, lib;
var info, flag = true, lib;
if (this.loadingStatus) return false;
this.loadingStatus = "core";
CA.IntelliSense.library = lib = {
@ -42,15 +42,15 @@
} catch(e) {erp(e)}});
return true;
},
clearCache : function(src) {
if (src) {
delete this.cache[src];
clearCache : function(uriStr) {
if (uriStr) {
delete this.cache[uriStr];
} else {
this.cache = {};
}
},
isLibrary : function(path) {
return path in CA.Library.inner || new java.io.File(path).isFile();
isLibrary : function(uriStr) { // Deprecated
return uriStr in CA.Library.inner || ExternalStorage.canRead(ExternalStorage.toUri(uriStr));
},
isDeprecated : function(uuid, version) {
if (!Array.isArray(version)) return true;
@ -59,44 +59,45 @@
if (uuid == "5a204d07-4b6d-4c51-9470-a2d8c8676ab8") return true; //调试屏幕:根本没用
return false;
},
enableLibrary : function(path) {
Common.removeSet(CA.settings.disabledLibrarys, path);
Common.removeSet(CA.settings.coreLibrarys, path);
return Common.addSet(CA.settings.enabledLibrarys, path);
enableLibrary : function(uriStr) {
Common.removeSet(CA.settings.disabledLibrarys, uriStr);
Common.removeSet(CA.settings.coreLibrarys, uriStr);
return Common.addSet(CA.settings.enabledLibrarys, uriStr);
},
disableLibrary : function(path) {
Common.removeSet(CA.settings.enabledLibrarys, path);
Common.removeSet(CA.settings.coreLibrarys, path);
return Common.addSet(CA.settings.disabledLibrarys, path);
disableLibrary : function(uriStr) {
Common.removeSet(CA.settings.enabledLibrarys, uriStr);
Common.removeSet(CA.settings.coreLibrarys, uriStr);
return Common.addSet(CA.settings.disabledLibrarys, uriStr);
},
removeLibrary : function(path) {
removeLibrary : function(uriStr) {
var fl = false;
fl = Common.removeSet(CA.settings.enabledLibrarys, path) || fl;
fl = Common.removeSet(CA.settings.coreLibrarys, path) || fl;
return Common.removeSet(CA.settings.disabledLibrarys, path) || fl;
ExternalStorage.tryReleaseImportUri(ExternalStorage.toUri(uriStr));
fl = Common.removeSet(CA.settings.enabledLibrarys, uriStr) || fl;
fl = Common.removeSet(CA.settings.coreLibrarys, uriStr) || fl;
return Common.removeSet(CA.settings.disabledLibrarys, uriStr) || fl;
},
enableCoreLibrary : function(path) {
Common.removeSet(CA.settings.enabledLibrarys, path);
Common.removeSet(CA.settings.disabledLibrarys, path);
return Common.addSet(CA.settings.coreLibrarys, path);
enableCoreLibrary : function(uriStr) {
Common.removeSet(CA.settings.enabledLibrarys, uriStr);
Common.removeSet(CA.settings.disabledLibrarys, uriStr);
return Common.addSet(CA.settings.coreLibrarys, uriStr);
},
loadLibrary : function(path, targetLib) {
var m, v, cur, resolved;
loadLibrary : function(uriStr, targetLib) {
var m, cur, resolved;
try {
if (this.cache[path]) {
cur = this.cache[path].data;
m = this.cache[path].mode;
if (this.cache[uriStr]) {
cur = this.cache[uriStr].data;
m = this.cache[uriStr].mode;
} else {
cur = this.readLibrary(path);
cur = this.readLibrary(uriStr);
if (!cur) throw "无法读取或解析拓展包";
if (cur.error) throw cur.error;
if (!(cur.data instanceof Object)) throw "错误的拓展包格式";
this.cache[path] = cur;
this.cache[uriStr] = cur;
m = cur.mode;
cur = cur.data;
}
resolved = {
src : path,
src : uriStr,
name : cur.name,
author : cur.author,
description : cur.description,
@ -117,8 +118,8 @@
return resolved;
} else {
return {
src : path,
name : m == 0 ? path : (new java.io.File(path)).getName(),
src : uriStr,
name : m == 0 ? uriStr : ExternalStorage.uriToName(ExternalStorage.toUri(uriStr)),
hasError : true,
mode : m,
error : err
@ -126,13 +127,13 @@
}
}
},
readLibrary : function(path) {
var t, er, f, securityLevel = CA.settings.securityLevel, requiredSecLevel;
readLibrary : function(uriStr) {
var t, er, uri, securityLevel = CA.settings.securityLevel, requiredSecLevel;
//-1 禁止所有非内置拓展包
//0 允许所有拓展包
//1 仅允许锁定拓展包与官方拓展包
//2+ 仅允许商店下载的拓展包
if (t = CA.Library.inner[path]) {
if (t = CA.Library.inner[uriStr]) {
return {
data : t,
mode : 0
@ -143,35 +144,37 @@
};
}
if (securityLevel >= 0) {
f = new java.io.File(path);
if (!f.isFile()) {
uri = ExternalStorage.toUri(uriStr);
ExternalStorage.tryTakeUriPermission(uri);
if (!ExternalStorage.isFile(uri)) {
return {
error : "拓展包文件不存在"
};
}
requiredSecLevel = this.testSecurityLevel(f);
requiredSecLevel = this.testSecurityLevel(uri);
if (requiredSecLevel < securityLevel) {
return {
error : "您正在使用的安全等级不允许加载此拓展包\n您可以在右上角▼处打开菜单然后点击“设置安全级别”来调整当前安全级别"
};
}
if (requiredSecLevel >= 2) {
if (t = CA.Library.loadSignedV1(f, null, er)) {
if (t = CA.Library.loadSignedV1(uri, null, er)) {
return {
data : t,
mode : 3
};
}
} else if (requiredSecLevel == 1) {
if (t = CA.Library.loadPrefixed(f, null, er)) {
if (t = CA.Library.loadPrefixed(uri, null, er)) {
return {
data : t,
mode : 2
};
}
} else if (requiredSecLevel == 0) {
if (t = Common.readFile(f.getPath(), null, false, er)) {
t = this.safeEval(f, t, er);
t = ExternalStorage.readFileContent(uri, "UTF-8", (error) => void (er = { error }))
if (t) {
t = this.safeEval(uri, t, er);
if (t) {
return {
data : t,
@ -187,29 +190,25 @@
}
return er;
},
evalLib : function(file, code) {
return Loader.evalSpecial("(" + code + ")", file.getName(), 0, {
path : String(file.getPath()),
code : code,
LibInfo : {
file : file,
uri : android.net.Uri.fromFile(file),
code : code
}
evalLib : function(uri, code) {
return Loader.evalSpecial("(" + code + ")", ExternalStorage.uriToName(uri), 0, {
path : String(uri.getPath()),
code,
LibInfo : { uri, code }
}, this);
},
safeEval :function(file, code, defaultValue, error) {
safeEval : function(uri, code, defaultValue, error) {
try {
return this.evalLib(file, code);
return this.evalLib(uri, code);
} catch(e) {
if (error) error.error = e;
return defaultValue;
}
},
testSecurityLevel : function(file) {
if (this.shouldVerifySigned(file) >= 0) {
testSecurityLevel : function(uri) {
if (this.shouldVerifySigned(uri) >= 0) {
return 2;
} else if (this.isPrefixed(file)) {
} else if (this.isPrefixed(uri)) {
return 1;
} else return 0;
},
@ -263,10 +262,10 @@
}
return null;
},
isPrefixed : function(file) {
isPrefixed : function(uri) {
try {
var rd, q, start = [0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59];
rd = new java.io.FileInputStream(file);
rd = ExternalStorage.openInputStream(uri);
while (start.length) {
if (rd.read() != start.shift()) {
rd.close();
@ -282,10 +281,10 @@
return false;
}
},
loadPrefixed : function(file, defaultValue, error) {
loadPrefixed : function(uri, defaultValue, error) {
try{
var rd, s = [], q, start = [0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59];
rd = new java.io.FileInputStream(file);
rd = ExternalStorage.openInputStream(uri);
while (start.length) {
if (rd.read() != start.shift()) {
rd.close();
@ -296,18 +295,16 @@
rd = new java.io.BufferedReader(new java.io.InputStreamReader(new java.util.zip.GZIPInputStream(rd)));
while (q = rd.readLine()) s.push(q);
rd.close();
return this.evalLib(file, s.join("\n"));
return this.evalLib(uri, s.join("\n"));
} catch(e) {
if (error) error.error = e;
return defaultValue;
}
},
savePrefixed : function(path, object) {
savePrefixed : function(uri, object) {
var wr, ar;
var f = new java.io.File(path).getParentFile();
if (f) f.mkdirs();
wr = new java.io.FileOutputStream(path);
ar = java.nio.ByteBuffer.allocate(15); //LIBRARY
wr = ExternalStorage.openOutputStream(uri);
ar = java.nio.ByteBuffer.allocate(15); // LIBRARY
ar.put([0x4c, 0x49, 0x42, 0x52, 0x41, 0x52, 0x59]).putLong((new java.util.Date()).getTime());
wr.write(ar.array());
wr = new java.util.zip.GZIPOutputStream(wr);
@ -424,7 +421,7 @@
op = o.patterns;
sp = src.patterns;
if (Array.isArray(sp) != Array.isArray(op)) throw "命令模式格式不一致,无法合并";
if (Array.isArray(op)) {
if (Array.isArray(op)) { // Deprecated
for (i in op) {
t = sp.indexOf(op[i]);
if (t < 0) sp.push(op[i]);
@ -441,7 +438,7 @@
op = o.patterns;
sp = src.patterns;
if (Array.isArray(sp) != Array.isArray(op)) throw "命令模式格式不一致,无法过滤";
if (Array.isArray(op)) {
if (Array.isArray(op)) { // Deprecated
for (i in op) {
t = sp.indexOf(op[i]);
if (t >= 0) sp.splice(t, 1);
@ -537,7 +534,7 @@
} else if ((i in cur.commands) && l.mode != "overwrite") {
joinCmd(cur.commands[i], l.commands[i]);
} else {
cur.commands[i] = l.commands[i];
cur.commands[i] = Object.copy(l.commands[i]);
}
}
for (i in l.enums) {
@ -550,7 +547,7 @@
} else if ((i in cur.enums) && l.mode != "overwrite") {
joinEnum(cur.enums[i], parseAliasEnum(cur, l.enums[i]));
} else {
cur.enums[i] = parseAliasEnum(cur, l.enums[i]);
cur.enums[i] = Object.copy(parseAliasEnum(cur, l.enums[i]));
}
}
for (i in l.selectors) {
@ -792,10 +789,12 @@
os.write(arr);
os.close();
}
return MapScript.baseDir + "libs/" + libinfo.uuid + ".lib";
return ExternalStorage.toUri(MapScript.baseDir + "libs/" + libinfo.uuid + ".lib");
},
shouldVerifySigned : function(file) {
if (!file.isFile()) return -1;
shouldVerifySigned : function(uri) {
if (!ExternalStorage.isFile(uri)) return -1;
const file = ExternalStorage.uriToFile(uri);
if (!file) return -1;
var i, arr = this.readAsArray(new java.io.FileInputStream(file)), digest, bytes, buf;
if (this.arrayStartsWith(arr, [0x4c, 0x49, 0x42, 0x53, 0x49, 0x47, 0x4e, 0x30, 0x31])) { //LIBSIGN01
buf = java.nio.ByteBuffer.wrap(arr);
@ -815,10 +814,10 @@
return 1;
} else return -1;
},
loadSignedV1 : function(file, defaultValue, error) {
loadSignedV1 : function(uri, defaultValue, error) {
try{
var rd, s = [], q, start = [0x4c, 0x49, 0x42, 0x53, 0x49, 0x47, 0x4e, 0x30, 0x31]; //LIBSIGN01
rd = new java.io.FileInputStream(file);
rd = ExternalStorage.openInputStream(uri);
while (start.length) {
if (rd.read() != start.shift()) {
rd.close();
@ -832,7 +831,7 @@
rd = new java.io.BufferedReader(new java.io.InputStreamReader(new java.util.zip.GZIPInputStream(rd)));
while (q = rd.readLine()) s.push(q);
rd.close();
return this.evalLib(file, s.join("\n"));
return this.evalLib(uri, s.join("\n"));
} catch(e) {
if (error) error.error = e;
return defaultValue;
@ -880,32 +879,33 @@
callback(NeteaseAdapter.compareVersion(r.version, libinfo.version) > 0 ? 1 : 0, r, libinfo);
},
doUpdate : function(updateInfo, libInfo, statusListener) {
var path;
var uriStr;
if (updateInfo.method == "intent") { //通过链接启动
statusListener("downloadFromUri", String(updateInfo.uri));
} else {
statusListener("startDownload");
try {
if (updateInfo.source) {
path = this.downloadLib({
uriStr = String(this.downloadLib({
downloadurl : updateInfo.url,
sha1 : updateInfo.sha1,
uuid : updateInfo.uuid
}, this.requestSourceInfoCached(updateInfo.source));
if (path != libInfo.src) {
}, this.requestSourceInfoCached(updateInfo.source)));
if (uriStr != libInfo.src) {
ExternalStorage.tryReleaseImportUri(ExternalStorage.toUri(libInfo.src));
if (Common.inSet(CA.settings.coreLibrarys, libInfo.src)) {
Common.replaceLinkedSet(CA.settings.coreLibrarys, libInfo.src, path);
Common.removeSet(CA.settings.enabledLibrarys, path);
Common.replaceLinkedSet(CA.settings.coreLibrarys, libInfo.src, uriStr);
Common.removeSet(CA.settings.enabledLibrarys, uriStr);
} else {
Common.replaceLinkedSet(CA.settings.enabledLibrarys, libInfo.src, path);
Common.removeSet(CA.settings.coreLibrarys, path);
Common.replaceLinkedSet(CA.settings.enabledLibrarys, libInfo.src, uriStr);
Common.removeSet(CA.settings.coreLibrarys, uriStr);
}
if (libInfo.mode == 0) {
Common.addSet(CA.settings.disabledLibrarys, libInfo.src);
}
}
} else {
NetworkUtils.download(updateInfo.url, libInfo.src);
NetworkUtils.downloadToUri(updateInfo.url, ExternalStorage.toUri(libInfo.src));
}
} catch(e) {
statusListener("downloadError", e);
@ -936,7 +936,7 @@
}
});
}
} else if (statusCode == 1) {
} else if (statusCode == 0) {
e.updateState = "latest";
} else if (statusCode < 0) {
e.updateState = "unavailable";

View File

@ -2003,13 +2003,14 @@ MapScript.loadModule("CA", {
type : 0,
text : "导入",
action : function() {
Common.showFileDialog({
type : 0,
callback : function(f) {
ExternalStorage.showImportActions({
mimeType: "application/json",
uri(uri) {
try {
var r = JSON.parse(Common.readFile(f.result, "[]"));
const content = ExternalStorage.readFileContent(uri, "UTF-8", "[]");
const r = JSON.parse(content);
if (!Array.isArray(r)) throw "不正确的收藏夹格式";
r.forEach(function(e) {
r.forEach((e) => {
e = String(e);
if (e.length) CA.addHistory(e);
});
@ -2031,16 +2032,11 @@ MapScript.loadModule("CA", {
if (!self.selection[i]) continue;
z.push(CA.his[i]);
}
Common.showFileDialog({
type : 1,
callback : function(f) {
try {
Common.saveFile(f.result, JSON.stringify(z, null, 4));
Common.toast("历史已保存至" + f.result);
} catch(e) {
erp(e, true);
Common.toast("文件保存失败,无法导出\n" + e);
}
ExternalStorage.showExportActions({
mimeType: "application/json",
hint: "历史.json",
export(uri) {
ExternalStorage.writeFileContent(uri, JSON.stringify(z, null, 4));
}
});
}
@ -2291,13 +2287,14 @@ MapScript.loadModule("CA", {
text : "导入",
action : function() {
var fd = self.path[self.path.length - 1];
Common.showFileDialog({
type : 0,
callback : function(f) {
ExternalStorage.showImportActions({
mimeType: "application/json",
uri(uri) {
try {
var r = JSON.parse(Common.readFile(f.result, "[]"));
const content = ExternalStorage.readFileContent(uri, "UTF-8", "[]");
const r = JSON.parse(content);
if (!Array.isArray(r)) throw "不正确的收藏夹格式";
r.forEach(function(e) {
r.forEach((e) => {
CA.addFavorite(e, fd.children);
});
self.refresh();
@ -2319,16 +2316,11 @@ MapScript.loadModule("CA", {
if (!self.selection[i]) continue;
a.push(self.array[i]);
}
Common.showFileDialog({
type : 1,
callback : function(f) {
try {
Common.saveFile(f.result, JSON.stringify(a, null, 4));
Common.toast("收藏已保存至" + f.result);
} catch(e) {
erp(e, true);
Common.toast("文件保存失败,无法导出\n" + e);
}
ExternalStorage.showExportActions({
mimeType: "application/json",
hint: "收藏.json",
export(uri) {
ExternalStorage.writeFileContent(uri, JSON.stringify(a, null, 4));
}
});
}
@ -2629,12 +2621,9 @@ MapScript.loadModule("CA", {
name : "分享软件",
type : "custom",
onclick : function() {
var t = "https://www.coolapk.com/game/190152";
var t = "https://ca.projectxero.top";
try {
AndroidBridge.startActivity(new android.content.Intent(android.content.Intent.ACTION_SEND)
.setType("text/plain")
.putExtra(android.content.Intent.EXTRA_TEXT, new java.lang.String("Hi我发现一款很棒的Minecraft辅助软件命令助手。下载链接" + t))
.addFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK));
AndroidBridge.shareText("Hi我发现一款很棒的Minecraft辅助软件命令助手。下载链接" + t);
} catch(e) {
Common.setClipboardText(t);
Common.toast("下载链接已复制到剪贴板");
@ -2658,6 +2647,19 @@ MapScript.loadModule("CA", {
}
}
}, {
name : "爱发电主页",
type : "custom",
onclick : function() {
try {
if (!AndroidBridge.viewUri("afd://app/openapp?params=%7B%22url%22:%22https://afdian.net/a/projectxero%22,%22type%22:%221%22%7D")) {
AndroidBridge.viewUri("https://afdian.net/a/projectxero");
}
} catch(e) {
Common.toast("爱发电打开失败");
Log.e(e);
}
}
},/*{
name : "哔哩哔哩空间",
type : "custom",
onclick : function() {
@ -2670,7 +2672,17 @@ MapScript.loadModule("CA", {
Log.e(e);
}
}
}, {
},*/{
name : "加入内测群",
type : "custom",
onclick : function() {
try {
AndroidBridge.viewUri("https://projectxero.top/qqgroup/cabeta/");
} catch(e) {
Log.e(e);
}
}
},/*{
name : "加入交流群",
type : "custom",
onclick : function() {
@ -2682,7 +2694,7 @@ MapScript.loadModule("CA", {
Log.e(e);
}
}
}, {
},*/{
name : "许可协议",
type : "custom",
onclick : function() {
@ -3211,14 +3223,15 @@ MapScript.loadModule("CA", {
name : "导入用户数据",
type : "custom",
onclick : function() {
Common.showFileDialog({
type : 0,
callback : function(f) {
ExternalStorage.showImportActions({
mimeType: "*/*",
file(f) {
try {
CA.importSettings(f.result);
CA.importSettings(f);
} catch(e) {
Common.toast("从" + f.result + "导入用户数据失败\n" + e);
Common.toast("导入用户数据失败\n" + e);
}
ExternalStorage.tryReleaseImportFile(f);
}
});
}
@ -3290,13 +3303,13 @@ MapScript.loadModule("CA", {
Common.showOperateDialog([{
text : "导出",
onclick : function() {
Common.showFileDialog({
type : 1,
defaultFileName : "ca_settings.dat",
callback : function(f) {
ExternalStorage.showExportActions({
mimeType: "application/octet-stream",
hint: "ca_settings.dat",
export(uri) {
try {
Common.fileCopy(new java.io.File(CA.profilePath), f.result);
Common.toast("配置已导出" + f.result);
ExternalStorage.copy(ExternalStorage.toUri(CA.profilePath), uri);
Common.toast("配置已导出");
} catch(e) {
erp(e, true);
Common.toast("文件保存失败,无法导出\n" + e);
@ -3310,26 +3323,17 @@ MapScript.loadModule("CA", {
onclick : function() {
try {
Common.fileCopy(new java.io.File(CA.profilePath), this.path);
AndroidBridge.startActivity(this.intent);
AndroidBridge.sendFile(this.path);
} catch(e) {
Log.e(e);
Common.toast("发送配置文件失败\n" + e);
}
},
hidden : function() {
try {
this.intent = new android.content.Intent(android.content.Intent.ACTION_SEND)
.setType("text/plain")
.putExtra(android.content.Intent.EXTRA_STREAM, AndroidBridge.fileToUri(this.path))
.addFlags(android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION | android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION | android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
} catch(e) {Log.e(e)}
return !this.intent;
}
}]);
},
manageErrors : function() {
var f = new java.io.File(android.os.Environment.getExternalStorageDirectory(), "com.xero.ca.error.log");
var f = new java.io.File(MapScript.baseDir, "com.xero.ca.error.log");
if (!f.isFile()) return Common.toast("无错误记录");
Common.showOperateDialog([{
text : "打开",
@ -3353,19 +3357,8 @@ MapScript.loadModule("CA", {
}
}, {
text : "发送",
intent : (function() {
try {
return new android.content.Intent(android.content.Intent.ACTION_SEND)
.setType("text/plain")
.putExtra(android.content.Intent.EXTRA_STREAM, AndroidBridge.fileToUri(f))
.addFlags(android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION | android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION | android.content.Intent.FLAG_ACTIVITY_NEW_TASK);
} catch(e) {Log.e(e)}
})(),
onclick : function() {
AndroidBridge.startActivity(this.intent);
},
hidden : function() {
return !this.intent;
AndroidBridge.sendFile(f);
}
}, {
text : "清空",
@ -3376,7 +3369,7 @@ MapScript.loadModule("CA", {
}]);
},
listErrors : function() {
var f = Common.readFile(android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/com.xero.ca.error.log", "");
var f = Common.readFile(MapScript.baseDir + "com.xero.ca.error.log", "");
if (!f.length) return;
var a = f.slice(9).split("\n* ");
a.reverse();
@ -3939,17 +3932,13 @@ MapScript.loadModule("CA", {
text : "从文件中导入",
description : "导入外置拓展包",
onclick : function(v, tag) {
Common.showFileDialog({
type : 0,
callback : function(f) {
self.postTask(function(cb) {
var path = String(f.result.getAbsolutePath());
if (!CA.Library.isLibrary(path)) {
Common.toast("无法导入该拓展包,可能文件不存在");
cb(false);
return;
}
CA.Library.enableLibrary(path);
ExternalStorage.showImportActions({
mimeType: "*/*",
hint: "caclib_*.json",
file(f) {
self.postTask((cb) => {
const uriStr = String(ExternalStorage.toUri(f));
CA.Library.enableLibrary(uriStr);
cb(true, function() {
Common.toast("导入成功!");
});
@ -3960,27 +3949,49 @@ MapScript.loadModule("CA", {
hidden : function() {
return CA.settings.securityLevel < 0;
}
},{
text : "从外部存储加载",
description : "从外部存储中加载外置拓展包",
onclick : function(v, tag) {
ExternalStorage.showOpenActions({
mimeType: "*/*",
callback(uri) {
ExternalStorage.tryTakeUriPermission(uri);
self.postTask((cb) => {
const uriStr = String(uri);
CA.Library.enableLibrary(uriStr);
cb(true, function() {
Common.toast("加载成功!");
});
});
}
});
},
hidden : function() {
return CA.settings.securityLevel != 0;
}
},{
text : "新建拓展包",
description : "新建一个不包含内容的包",
onclick : function(v, tag) {
Common.showFileDialog({
type : 1,
callback : function(f) {
self.postTask(function(cb) {
var fp = String(f.result.getAbsolutePath());
ExternalStorage.showSaveActions({
mimeType: "application/json",
hint: "新建拓展包.json",
callback(uri) {
ExternalStorage.tryTakeUriPermission(uri);
self.postTask((cb) => {
try {
MapScript.saveJSON(fp, {
ExternalStorage.writeFileContent(uri, JSON.stringify({
"name": "新建拓展包",
"author": "作者名",
"description": "此处填写介绍,可留空,新建于" + new Date().toLocaleDateString(),
"description": "此处填写介绍,可留空,新建于" + new Date().toLocaleString(),
"uuid": String(java.util.UUID.randomUUID().toString()),
"version": [0, 0, 1],
"require": []
});
CA.Library.enableLibrary(fp);
}));
CA.Library.enableLibrary(String(uri));
cb(true, function() {
Common.toast("拓展包已新建:" + fp);
Common.toast("拓展包已新建");
});
} catch(e) {
Common.toast("文件保存失败,无法新建\n" + e);
@ -3991,7 +4002,7 @@ MapScript.loadModule("CA", {
});
},
hidden : function() {
return CA.settings.securityLevel >= 1 || CA.settings.securityLevel < 0;
return CA.settings.securityLevel != 0;
}
},{
text : "刷新",
@ -4124,7 +4135,7 @@ MapScript.loadModule("CA", {
text : "忽略版本",
description : "暂时忽略版本限制",
hidden : function() {
return CA.Library.ignoreVersion;
return CA.settings.securityLevel != 0 || CA.Library.ignoreVersion;
},
onclick : function(v, tag) {
self.postTask(function(cb) {
@ -4139,7 +4150,7 @@ MapScript.loadModule("CA", {
text : "取消忽略版本",
description : "取消忽略版本限制",
hidden : function() {
return !CA.Library.ignoreVersion;
return CA.settings.securityLevel != 0 || !CA.Library.ignoreVersion;
},
onclick : function(v, tag) {
self.postTask(function(cb) {
@ -4155,10 +4166,12 @@ MapScript.loadModule("CA", {
description : "将拓展包列表恢复为默认",
onclick : function(v, tag) {
self.postTask(function(cb) {
CA.settings.enabledLibrarys = Object.keys(CA.Library.inner);
CA.settings.disabledLibrarys = [];
CA.settings.coreLibrarys = [];
CA.settings.deprecatedLibrarys = [];
CA.settings.enabledLibrarys.concat(
CA.settings.disabledLibrarys,
CA.settings.coreLibrarys
).forEach((e) => CA.Library.removeLibrary(e));
CA.Library.recommended.forEach((e) => CA.Library.enableLibrary(e));
CA.Library.defaultDisabled.forEach((e) => CA.Library.disableLibrary(e));
CA.Library.clearCache();
cb(true, function() {
Common.toast("已恢复为默认拓展包列表");
@ -4186,39 +4199,46 @@ MapScript.loadModule("CA", {
text : "查看信息",
description : "查看该拓展包的相关信息",
onclick : function(v, tag) {
var f = new java.io.File(tag.data.src), s;
s = "名称 : " + tag.data.name;
if (f.isFile()) s += "\n位置 : " + tag.data.src + "\n大小 : " + Common.getFileSize(f, true) + "\n时间 : " + new Date(f.lastModified()).toLocaleString();
var uri = ExternalStorage.toUri(tag.data.src);
var s = ["名称 : " + tag.data.name];
if (ExternalStorage.isFile(uri)) {
s.push("位置 : " + tag.data.src);
s.push("大小 : " + ExternalStorage.getLengthString(uri));
s.push("时间 : " + ExternalStorage.getLastModifiedString(uri));
}
if (tag.data.updateState) {
s += "\n更新状态 : ";
let updateStateStr;
switch (tag.data.updateState) {
case "checking":
s += "正在检测";
updateStateStr = "正在检测";
break;
case "latest":
s += "已是最新版";
updateStateStr = "已是最新版";
break;
case "unavailable":
s += "更新源不可用";
updateStateStr = "更新源不可用";
break;
case "ready":
s += "已准备更新";
updateStateStr = "已准备更新";
break;
case "waitForUser":
s += "等待用户手动更新";
updateStateStr = "等待用户手动更新";
break;
case "error":
s += "下载更新出错";
updateStateStr = "下载更新出错";
break;
case "finished":
s += "已下载更新";
updateStateStr = "已下载更新";
break;
default:
s += "未知";
updateStateStr = "未知";
}
s.push("更新状态 : " + updateStateStr);
}
if (!tag.data.disabled && !tag.data.hasError && tag.data.stat) s += "\n\n" + tag.data.stat.toString();
Common.showTextDialog(s);
if (!tag.data.disabled && !tag.data.hasError && tag.data.stat) {
s.push("", tag.data.stat.toString());
}
Common.showTextDialog(s.join("\n"));
}
}];
self.enabledMenu = [{
@ -4275,90 +4295,99 @@ MapScript.loadModule("CA", {
text : "编辑",
description : "用JSON编辑器编辑该拓展包",
hidden : function(tag) {
return tag.data.mode != 1;
return CA.settings.securityLevel != 0 || tag.data.mode != 1;
},
onclick : function(v, tag) {
self.postTask(function(cb) {
var a = MapScript.readJSON(tag.data.src, {});
if (!(a instanceof Object)) a = {};
JSONEdit.show({
source : a,
rootname : "拓展包",
update : function() {
var uri = ExternalStorage.toUri(tag.data.src);
var content;
try {
content = ExternalStorage.readFileContent(uri, "UTF-8");
a = JSON.parse(content);
} catch(e) {
Common.toast("此拓展包无法使用JSON编辑器进行编辑\n" + e);
return;
}
if (!(a instanceof Object)) a = {};
JSONEdit.show({
source : a,
rootname : "拓展包",
update : function() {
self.postTask(function(cb) {
try {
self.processing = true;
MapScript.saveJSON(tag.data.src, a);
ExternalStorage.writeFileContent(uri, JSON.stringify(a));
CA.Library.clearCache(tag.data.src);
cb(true, function() {
Common.toast("加载成功!");
});
} catch(e) {
Common.toast("格式不合法,无法保存\n" + e);
Common.toast("文件保存失败\n" + e);
cb(false);
return;
}
}
});
});
}
},{
text : "另存为",
description : "将该拓展包保存到一个新文件里",
onclick : function(v, tag) {
if (tag.data.hasError) {
Common.toast("拓展包“" + tag.data.name + "”有错误,请先解决错误再另存为");
return true;
}
Common.showFileDialog({
type : 1,
callback : function(f) {
self.postTask(function(cb) {
var fp = String(f.result.getAbsolutePath());
try {
if (tag.data.mode == 0) {
MapScript.saveJSON(fp, CA.Library.inner[tag.data.src]);
} else {
Common.fileCopy(new java.io.File(tag.data.src), f.result);
}
CA.Library.clearCache(fp);
CA.Library.disableLibrary(fp);
cb(true, function() {
Common.toast("拓展包“" + tag.data.name + "”已另存为" + fp);
});
} catch(e) {
Common.toast("文件保存失败,无法另存为\n" + e);
cb(false);
}
});
}
});
}
},{
text : "导出",
description : "将该拓展包保存到一个新文件里",
onclick : function(v, tag) {
if (tag.data.hasError) {
Common.toast("拓展包“" + tag.data.name + "”有错误,请先解决错误再导出");
return true;
}
if (tag.data.mode == 0) {
ExternalStorage.showExportActions({
mimeType: "application/json",
hint: tag.data.name + ".json",
export(uri) {
ExternalStorage.writeFileContent(uri, JSON.stringify(CA.Library.inner[tag.data.src]));
}
});
} else {
ExternalStorage.showExportActions({
mimeType: "application/json",
hint: tag.data.name + ".json",
export: tag.data.src
});
}
}
},{
text : "创建副本",
description : "创建该拓展包的副本(副本不会被认为与原拓展包相同)",
hidden : function(tag) {
return tag.data.hasError || tag.data.mode >= 2;
return CA.settings.securityLevel != 0 || tag.data.hasError || tag.data.mode >= 2;
},
onclick : function(v, tag) {
Common.showFileDialog({
type : 1,
callback : function(f) {
ExternalStorage.showSaveActions({
mimeType: "application/json",
hint: tag.data.name + ".json",
callback(uri) {
self.postTask(function(cb) {
var fp = String(f.result.getAbsolutePath()), l;
try {
if (tag.data.mode == 0) {
l = Object.copy(CA.Library.inner[tag.data.src]);
} else {
l = MapScript.readJSON(tag.data.src, null);
if (!(l instanceof Object)) throw "无法读取文件";
let l;
const uriStr = String(uri);
if (tag.data.mode == 0) {
l = Object.copy(CA.Library.inner[tag.data.src]);
} else {
try {
const origUri = ExternalStorage.toUri(tag.data.src);
const content = ExternalStorage.readFileContent(origUri, "UTF-8");
l = JSON.parse(content);
if (!(l instanceof Object)) throw "格式错误";
} catch(e) {
Common.toast("此拓展包无法创建副本\n" + e);
cb(false);
return;
}
l.name = String(l.name) + " 的副本";
l.uuid = String(java.util.UUID.randomUUID().toString());
MapScript.saveJSON(fp, l);
CA.Library.clearCache(fp);
CA.Library.enableLibrary(fp);
}
l.name = String(l.name) + " 的副本";
l.uuid = String(java.util.UUID.randomUUID().toString());
try {
ExternalStorage.writeFileContent(uri, JSON.stringify(l));
CA.Library.clearCache(uriStr);
CA.Library.enableLibrary(uriStr);
cb(true, function() {
Common.toast("拓展包“" + tag.data.name + "”的副本已创建" + fp);
Common.toast("拓展包“" + tag.data.name + "”的副本已创建");
});
} catch(e) {
Common.toast("文件保存失败,无法创建副本\n" + e);
@ -4372,7 +4401,7 @@ MapScript.loadModule("CA", {
text : "锁定",
description : "锁定拓展包,使其不能被编辑",
hidden : function(tag) {
return tag.data.hasError || tag.data.mode != 1;
return CA.settings.securityLevel != 0 || tag.data.hasError || tag.data.mode != 1;
},
onclick : function(v, tag) {
Common.showConfirmDialog({
@ -4382,7 +4411,10 @@ MapScript.loadModule("CA", {
if (id != 0) return;
self.postTask(function(cb) {
try {
CA.Library.savePrefixed(tag.data.src, MapScript.readJSON(tag.data.src));
const uri = ExternalStorage.toUri(tag.data.src);
const content = ExternalStorage.readFileContent(uri, "UTF-8");
const obj = JSON.parse(content);
CA.Library.savePrefixed(uri, obj);
CA.Library.clearCache(tag.data.src);
cb(true, function() {
Common.toast("拓展包“" + tag.data.name + "”已被锁定");
@ -4531,12 +4563,18 @@ MapScript.loadModule("CA", {
return;
}
var arr = CA.IntelliSense.library.info.concat(CA.settings.disabledLibrarys.map(function(e, i, a) {
var k = e in CA.Library.inner;
var isInternal = e in CA.Library.inner;
var name;
if (isInternal) {
name = CA.Library.inner[e].name;
} else {
name = ExternalStorage.uriToName(ExternalStorage.toUri(e));
}
return {
src : e,
index : i,
mode : k ? 0 : -1,
name : k ? CA.Library.inner[e].name : (new java.io.File(e)).getName(),
mode : isInternal ? 0 : -1,
name : name,
disabled : true
};
}));
@ -4766,12 +4804,12 @@ MapScript.loadModule("CA", {
}
self.downloadLib = function(data) {
Common.showProgressDialog(function(dia) {
var path;
var uriStr;
dia.setText("正在下载拓展包: " + data.name);
try {
path = CA.Library.downloadLib(data, self.libsrc);
CA.Library.clearCache(path);
CA.Library.enableLibrary(path);
uriStr = String(CA.Library.downloadLib(data, self.libsrc));
CA.Library.clearCache(uriStr);
CA.Library.enableLibrary(uriStr);
} catch(e) {
Common.toast("下载拓展包“" + data.name + "”失败\n" + e);
return;
@ -4898,6 +4936,10 @@ MapScript.loadModule("CA", {
Common.showOperateDialog([{
text : "不使用",
onclick : function() {
if (CA.settings.bgImage) {
const file = new java.io.File(CA.settings.bgImage);
ExternalStorage.tryReleaseImportFile(file);
}
CA.settings.bgImage = null;
callback();
Common.toast("背景图片已设置为 无");
@ -4905,11 +4947,14 @@ MapScript.loadModule("CA", {
}, {
text : "从文件中选择",
onclick : function(v, tag) {
AndroidBridge.selectImage(function(path) {
if (!path) return Common.toast("背景图片无效");
CA.settings.bgImage = path;
callback();
Common.toast("背景图片已设置为 " + path);
ExternalStorage.showImportActions({
mimeType: "image/*",
hint: "ca_background_image",
file(f) {
CA.settings.bgImage = String(f.getAbsolutePath());
callback();
Common.toast("背景图片已设置");
}
});
}
}, {
@ -4945,11 +4990,15 @@ MapScript.loadModule("CA", {
return view;
}
self.selectIcon = function(callback) {
AndroidBridge.selectImage(function(path) {
if (!path) return Common.toast("图片无效");
CA.settings.icon = path;
if (self.recent.indexOf(path) < 0) self.recent.push(path);
if (callback) callback();
ExternalStorage.showImportActions({
mimeType: "image/*",
hint: "ca_icon_image",
file(f) {
const path = String(f.getAbsolutePath());
CA.settings.icon = path;
if (self.recent.indexOf(path) < 0) self.recent.push(path);
if (callback) callback();
}
});
}
self.recent = [];
@ -5407,9 +5456,15 @@ MapScript.loadModule("CA", {
PWM.registerResetFlag(self, "linear");
}
self.init(list);
self.callback = callback;
self.popup.enter();
Common.showProgressDialog(function(o) {
o.setText("正在加载列表……");
self.init(list);
if (o.cancelled) return;
G.ui(function() {try {
self.callback = callback;
self.popup.enter();
} catch(e) {erp(e)}});
}, true);
} catch(e) {erp(e)}})},
SpecialTips : [
@ -6033,13 +6088,13 @@ MapScript.loadModule("CA", {
return;
}
self.addExp();
Common.showFileDialog({
type : 1,
callback : function(f) {
var fp = String(f.result.getAbsolutePath());
ExternalStorage.showExportActions({
mimeType: "text/plain",
hint: "generated.mcfunction",
export(uri) {
try {
Common.saveFile(fp, "# This file is spawned by CA\n# Template: " + self.flatten() + "\n\n" + self.export().join("\n"));
Common.toast("已保存" + fp);
ExternalStorage.writeFileContent(uri, "# This file is spawned by CA\n# Template: " + self.flatten() + "\n\n" + self.export().join("\n"));
Common.toast("函数文件已保存");
} catch(e) {
Common.toast("保存函数文件失败\n" + e);
}

View File

@ -578,7 +578,7 @@ MapScript.loadModule("Common", {
prg.startAnimation(aset);
}
self.init = function(o) {G.ui(function() {try {
var layout, text, prg, popup;
var layout, text, prg;
layout = new G.LinearLayout(ctx);
layout.setOrientation(G.LinearLayout.VERTICAL);
Common.applyStyle(layout, "message_bg");
@ -601,34 +601,45 @@ MapScript.loadModule("Common", {
});
} catch(e) {erp(e)}})},
self.controller = {
setText : function(s) {
setText : function(s, uptimeMillis) {
var o = this;
G.ui(function() {try {
gHandler.postAtTime(() => {try {
if (o.closed) return;
o.currentText = s;
if (!o.popup) {
self.init(o);
}
o.text.setText(Common.toString(s));
} catch(e) {erp(e)}});
} catch(e) {erp(e)}}, uptimeMillis || android.os.SystemClock.uptimeMillis());
},
close : function() {
setTextDelayed : function(s, millis) {
this.setText(s, android.os.SystemClock.uptimeMillis() + millis);
},
close : function(callback) {
var o = this;
G.ui(function() {try {
if (o.closed) return;
o.closed = true;
o.popup.exit();
if (o.popup) {
o.popup.exit();
}
if (callback) callback();
} catch(e) {erp(e)}});
},
async : function(f) {
async : function(f, onFinally) {
var o = this;
Threads.run(function() {
try {
f(o);
} catch(e) {erp(e)}
o.close();
o.close(onFinally);
});
}
};
}
var o = Object.create(self.controller);
o.startTime = android.os.SystemClock.uptimeMillis();
o.onCancel = onCancel;
self.init(o);
if (f) o.async(f);
return o;
},
@ -1048,7 +1059,10 @@ MapScript.loadModule("Common", {
fi.sort(self.compare);
}
var a = o.fileFirst ? fi.concat(dir) : dir.concat(fi);
if (o.curdir.getParent()) a.unshift(null);
var parent = o.curdir.getParent();
if (parent && ExternalStorage.isInStorage(parent)) {
a.unshift(null);
}
self.list.setAdapter(self.curadp = new SimpleListAdapter(a, self.vmaker, self.vbinder));
}
self.linear = new G.LinearLayout(ctx);
@ -1142,10 +1156,21 @@ MapScript.loadModule("Common", {
self.list.setOnItemClickListener(new G.AdapterView.OnItemClickListener({onItemClick : function(parent, view, pos, id) {try {
var o = self.sets;
var e = self.curadp.getItem(pos);
if (!e) {
o.curdir = o.curdir.getParentFile();
} else if (e.isDirectory()) {
o.curdir = e;
var newdir;
if (!e || e.isDirectory()) {
if (e) {
newdir = e;
} else {
newdir = o.curdir.getParentFile();
}
if (ExternalStorage.isAccessible(newdir.getAbsolutePath())) {
o.curdir = newdir;
} else {
ExternalStorage.ensureExternalStorage(function() {
o.curdir = newdir;
self.refresh();
});
}
} else if (o.type == 0) {
self.choose(e);
return true;
@ -1217,7 +1242,9 @@ MapScript.loadModule("Common", {
self.sets = o;
try {
o.curdir = new java.io.File(String(o.initDir ? o.initDir : self.lastDir));
if (!o.curdir.isDirectory()) o.curdir = android.os.Environment.getExternalStorageDirectory();
if (!o.curdir.isDirectory() || !ExternalStorage.isAccessible(o.curdir.getAbsolutePath())) {
o.curdir = ExternalStorage.getAccessibleRoot();
}
self.refresh();
} catch (e) {
Common.toast(self.intl.resolve("errAccessDir", e));
@ -1750,5 +1777,15 @@ MapScript.loadModule("Common", {
while (o.hasNext()) r.push(o.next());
}
return r;
},
stringComparator : function(a, b) {
a = String(a);
b = String(b);
return a > b ? 1 : a < b ? -1 : 0;
},
stringComparatorIgnoreCase : function(a, b) {
a = String(a).toLowerCase();
b = String(b).toLowerCase();
return a > b ? 1 : a < b ? -1 : 0;
}
});

View File

@ -139,10 +139,7 @@ MapScript.loadModule("DebugUtils", {
_fs.println(_t);
_fs.close();
try {
AndroidBridge.startActivity(new android.content.Intent(android.content.Intent.ACTION_SEND)
.setType("text/plain")
.putExtra(android.content.Intent.EXTRA_STREAM, AndroidBridge.fileToUri(_file))
.addFlags(android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION | android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION | android.content.Intent.FLAG_ACTIVITY_NEW_TASK));
AndroidBridge.sendFile(_file);
} catch(e) {
Common.toast("文件已生成于" + _file.getAbsolutePath());
}

View File

@ -22,30 +22,42 @@ MapScript.loadModule("JSONEdit", {
if (!self.menu) {
self.intl = Intl.getNamespace("jsonEdit.main");
self.saveMenu = [{
text : self.intl.edit,
description : self.intl.edit_desc,
onclick : function(v, tag) {
if (!JSONEdit.show(tag.par)) {
Common.toast(self.intl.nowhereEditable);
return true;
}
text: self.intl.edit,
description: self.intl.edit_desc,
hidden(tag) {
return tag.data === null;
},
onclick(v, tag) {
tag.editCallback();
}
}, {
text : self.intl.copy,
description : self.intl.copy_desc,
onclick : function(v, tag) {
text: self.intl.replace,
description: self.intl.replace_desc,
hidden(tag) {
return tag.data !== null;
},
onclick(v, tag) {
JSONEdit.create((data) => {
tag.replaceCallback(data);
});
}
}, {
text: self.intl.copy,
description: self.intl.copy_desc,
onclick(v, tag) {
Common.setClipboardText(JSON.stringify(tag.data, null, "\t"));
Common.toast(self.intl.copy_success);
return true;
}
}, {
text : self.intl.save,
description : self.intl.save_desc,
hidden : function(tag) {
return !tag.path;
text: self.intl.save,
description: self.intl.save_desc,
hidden(tag) {
return !tag.uri;
},
onclick : function(v, tag) {
onclick(v, tag) {
try {
MapScript.saveJSON(tag.path, tag.data);
ExternalStorage.writeFileContent(tag.uri, JSON.stringify(tag.data));
Common.toast(self.intl.save_success);
} catch(e) {
Common.toast(self.intl.resolve("save_failed", e));
@ -53,15 +65,17 @@ MapScript.loadModule("JSONEdit", {
return true;
}
}, {
text : self.intl.saveAs,
description : self.intl.saveAs_desc,
onclick : function(v, tag) {
Common.showFileDialog({
type : 1,
callback : function(f) {
text: self.intl.saveAs,
description: self.intl.saveAs_desc,
onclick(v, tag) {
ExternalStorage.showSaveActions({
mimeType: "application/json",
hint: "untitled.json",
callback(uri) {
try {
MapScript.saveJSON(tag.path = f.result.getAbsolutePath(), tag.data);
Common.toast(self.intl.saveAs_success);
ExternalStorage.writeFileContent(uri, JSON.stringify(tag.data));
tag.uri = uri;
Common.toast(self.intl.save_success);
} catch(e) {
Common.toast(self.intl.resolve("save_failed", e));
}
@ -70,46 +84,29 @@ MapScript.loadModule("JSONEdit", {
return true;
}
}, {
text : Common.intl.close,
onclick : function(v, tag) {}
text: Common.intl.close,
onclick(v, tag) {}
}];
self.menu = [{
text : self.intl.new,
description : self.intl.new_desc,
onclick : function() {
JSONEdit.create(function cb(o) {
Common.showOperateDialog(self.saveMenu, {
data : o,
path : null,
par : {
source : o,
update : function() {
cb(this.source);
}
}
});
self.openMenu = [{
text: self.intl.new,
description: self.intl.new_desc,
onclick(v, tag) {
JSONEdit.create((data) => {
tag.saveCallback(null, data);
});
}
}, {
text : self.intl.open,
description : self.intl.open_desc,
onclick : function() {
Common.showFileDialog({
type : 0,
callback : function(f) {
var o;
text: self.intl.open,
description: self.intl.open_desc,
onclick(v, tag) {
ExternalStorage.showOpenActions({
mimeType: "application/json",
callback(uri) {
let data;
try {
o = {
data : MapScript.readJSON(f.result.getAbsolutePath(), null),
path : f.result.getAbsolutePath()
}
if (!JSONEdit.show(o.par = {
source : o.data,
update : function() {
o.data = this.source;
Common.showOperateDialog(self.saveMenu, o);
}
})) Common.showOperateDialog(self.saveMenu, o);
data = JSON.parse(ExternalStorage.readFileContent(uri, "UTF-8"));
ExternalStorage.tryTakeUriPermission(uri);
tag.openCallback(uri, data, false);
} catch(e) {
Common.toast(JSONEdit.intl.resolve("invaildJSON", e));
}
@ -118,10 +115,34 @@ MapScript.loadModule("JSONEdit", {
}
}, {
text : Common.intl.close,
onclick : function(v, tag) {}
onclick(v, tag) {}
}];
}
Common.showOperateDialog(self.menu);
Common.showOperateDialog(self.openMenu, {
openCallback(uri, data, needEditablePrompt) {
const self = this;
Log.d("open")
if (!JSONEdit.show({
source: data,
update() {
Log.d("update")
self.saveCallback(uri, data);
}
})) {
if (needEditablePrompt) {
Common.toast(self.intl.nowhereEditable);
}
self.saveCallback(uri, data);
}
},
saveCallback(uri, data) {
Common.showOperateDialog(self.saveMenu, {
uri, data,
editCallback: () => this.openCallback(uri, data, true),
replaceCallback: (data) => this.openCallback(uri, data),
});
}
});
},
show : function(o) {
var i, name, data;
@ -438,16 +459,21 @@ MapScript.loadModule("JSONEdit", {
holder.e = e;
}
self.getDesp = function(obj, propertyName) {
var e;
var e, result;
try {
e = obj[propertyName];
if (Array.isArray(e)) {
return e.length ? JSONEdit.intl.resolve("arrayDesc", e[0], e.length) : JSONEdit.intl.emptyArrayDesc;
} else if (e instanceof Object && typeof e !== "function" && !(e instanceof java.lang.CharSequence)) {
return JSONEdit.intl.resolve("objectDesc", self.itemAccessor.getCount(e));
} else if (e === null) {
return JSONEdit.intl.nullDesc;
} else return String(e);
new java.lang.Runnable(function() {
e = obj[propertyName];
if (Array.isArray(e)) {
result = e.length ? JSONEdit.intl.resolve("arrayDesc", e[0], e.length) : JSONEdit.intl.emptyArrayDesc;
} else if (e instanceof Object && typeof e !== "function" && !(e instanceof java.lang.CharSequence)) {
result = JSONEdit.intl.resolve("objectDesc", self.itemAccessor.getCount(e));
} else if (e === null) {
result = JSONEdit.intl.nullDesc;
} else {
result = String(e);
}
}).run();
return result;
} catch(er) {
Log.e(er);
return String(er);

View File

@ -90,6 +90,20 @@ MapScript.loadModule("NetworkUtils", {
is.close();
return android.util.Base64.encodeToString(digest.digest(), android.util.Base64.NO_WRAP) == sha1;
},
downloadToUri : function(url, uri) {
var url = new java.net.URL(url);
var conn = url.openConnection();
conn.setConnectTimeout(5000);
conn.setUseCaches(false);
conn.setRequestMethod("GET");
conn.connect();
var is, os;
is = conn.getInputStream();
os = ExternalStorage.openOutputStream(uri);
ExternalStorage.pipe(is, os, 8192);
os.close();
is.close();
},
verifyFile : function(path, sha1) {
const BUFFER_SIZE = 8192;
var is, digest, buf, hr;

File diff suppressed because it is too large Load Diff