1. Virtual Keyboard config editor
2. More json file config options 3. Mod install manifest adjust(silent remove/upgrade support)
This commit is contained in:
parent
a0a8810145
commit
3328a9af52
|
@ -66,8 +66,8 @@ dependencies {
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
implementation 'com.google.android.material:material:1.2.1'
|
implementation 'com.google.android.material:material:1.2.1'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
|
||||||
implementation "androidx.navigation:navigation-fragment:2.3.0"
|
implementation "androidx.navigation:navigation-fragment:2.3.1"
|
||||||
implementation "androidx.navigation:navigation-ui:2.3.0"
|
implementation "androidx.navigation:navigation-ui:2.3.1"
|
||||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||||
// https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on
|
// https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on
|
||||||
implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.65.01'
|
implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.65.01'
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"assetPath":"mods/virtual-keyboard.zip",
|
"assetPath":"mods/virtual-keyboard.zip",
|
||||||
"Name": "VirtualKeyboard",
|
"Name": "648c4b387c5b61642614aa6677909a755a9b84fd96d717703fc83f5f73f515c0board",
|
||||||
"UniqueID": "VirtualKeyboard"
|
"UniqueID": "VirtualKeyboard"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"assetPath":"mods/custom-localization.zip",
|
"assetPath":"mods/custom-localization.zip",
|
||||||
"Name": "CustomLocalization",
|
"Name": "CustomLocalization",
|
||||||
"UniqueID": "ZaneYork.CustomLocalization"
|
"UniqueID": "ZaneYork.CustomLocalization",
|
||||||
|
"CleanInstall": true,
|
||||||
|
"Version": "1.1.0",
|
||||||
|
"OriginUniqueId": ["SMAPI.CustomLocalization"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"assetPath":"mods/console-commands.zip",
|
"assetPath":"mods/console-commands.zip",
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html><html><head><meta charset=utf-8><title>Virtual Keyboard Config Editor</title><link href=./static/css/app.css rel=stylesheet></head><body><div id=app></div><script>window.getJsonCallback = null;
|
||||||
|
// window.webObject = { getText: function(){ return '{"vToggle":{"key":"None","rectangle":{"X":36,"Y":12,"Width":64,"Height":64},"autoHidden":false},"buttons":[{"key":"Q","rectangle":{"X":200,"Y":80,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"I","rectangle":{"X":363,"Y":80,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"P","rectangle":{"X":526,"Y":80,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"B","rectangle":{"X":1180,"Y":12,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null}],"buttonsExtend":[{"key":"F1","rectangle":{"X":190,"Y":170,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"F2","rectangle":{"X":290,"Y":170,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"F3","rectangle":{"X":390,"Y":170,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"H","rectangle":{"X":490,"Y":170,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"O","rectangle":{"X":590,"Y":170,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"K","rectangle":{"X":690,"Y":170,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"U","rectangle":{"X":790,"Y":170,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"M","rectangle":{"X":890,"Y":170,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"V","rectangle":{"X":990,"Y":170,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"RightWindows","rectangle":{"X":1090,"Y":170,"Width":90,"Height":90},"transparency":0.5,"alias":"CMD","command":null},{"key":"S","rectangle":{"X":1080,"Y":12,"Width":90,"Height":90},"transparency":0.5,"alias":null,"command":null},{"key":"None","rectangle":{"X":980,"Y":12,"Width":90,"Height":90},"transparency":0.5,"alias":"Zoom","command":"zoom"}]}'; }, getMode: function(){ return 'tree';}, getLanguage: function(){ return 'zh-CN';}, isEditable: function(){ return true;}, getHeight: function(){ return 720;}, getWidth: function(){ return 1280;}, };
|
||||||
|
window.getJson = function()
|
||||||
|
{
|
||||||
|
if(window.getJsonCallback != null) {
|
||||||
|
window.webObject.setText(JSON.stringify(window.getJsonCallback()));
|
||||||
|
}
|
||||||
|
}</script><script type=text/javascript src=./static/js/manifest.js></script><script type=text/javascript src=./static/js/vendor.js></script><script type=text/javascript src=./static/js/app.js></script></body></html>
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
||||||
|
!function(r){var n=window.webpackJsonp;window.webpackJsonp=function(e,u,c){for(var f,i,p,a=0,l=[];a<e.length;a++)i=e[a],o[i]&&l.push(o[i][0]),o[i]=0;for(f in u)Object.prototype.hasOwnProperty.call(u,f)&&(r[f]=u[f]);for(n&&n(e,u,c);l.length;)l.shift()();if(c)for(a=0;a<c.length;a++)p=t(t.s=c[a]);return p};var e={},o={2:0};function t(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return r[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=r,t.c=e,t.d=function(r,n,e){t.o(r,n)||Object.defineProperty(r,n,{configurable:!1,enumerable:!0,get:e})},t.n=function(r){var n=r&&r.__esModule?function(){return r.default}:function(){return r};return t.d(n,"a",n),n},t.o=function(r,n){return Object.prototype.hasOwnProperty.call(r,n)},t.p="./",t.oe=function(r){throw console.error(r),r}}([]);
|
File diff suppressed because one or more lines are too long
|
@ -24,6 +24,7 @@ public class WebViewObject {
|
||||||
private String language;
|
private String language;
|
||||||
private boolean editable;
|
private boolean editable;
|
||||||
private int height;
|
private int height;
|
||||||
|
private int width;
|
||||||
private Consumer<String> setterCallback;
|
private Consumer<String> setterCallback;
|
||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
|
@ -49,6 +50,11 @@ public class WebViewObject {
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JavascriptInterface
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
public String getMode() {
|
public String getMode() {
|
||||||
return mode;
|
return mode;
|
||||||
|
|
|
@ -56,6 +56,16 @@ public class ModManifestEntry {
|
||||||
*/
|
*/
|
||||||
private Boolean IsRequired;
|
private Boolean IsRequired;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否清理安装
|
||||||
|
*/
|
||||||
|
private Boolean CleanInstall;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 原唯一ID列表
|
||||||
|
*/
|
||||||
|
private List<String> OriginUniqueId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 翻译后的Description
|
* 翻译后的Description
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -171,15 +171,35 @@ public class ModAssetsManager {
|
||||||
File modFolder = new File(FileUtils.getStadewValleyBasePath(), Constants.MOD_PATH);
|
File modFolder = new File(FileUtils.getStadewValleyBasePath(), Constants.MOD_PATH);
|
||||||
ImmutableListMultimap<String, ModManifestEntry> installedModMap = Multimaps.index(findAllInstalledMods(), ModManifestEntry::getUniqueID);
|
ImmutableListMultimap<String, ModManifestEntry> installedModMap = Multimaps.index(findAllInstalledMods(), ModManifestEntry::getUniqueID);
|
||||||
for (ModManifestEntry mod : modManifestEntries) {
|
for (ModManifestEntry mod : modManifestEntries) {
|
||||||
if (installedModMap.containsKey(mod.getUniqueID()) || installedModMap.containsKey(mod.getUniqueID().replace("ZaneYork.CustomLocalization", "SMAPI.CustomLocalization"))) {
|
if (installedModMap.containsKey(mod.getUniqueID())) {
|
||||||
ImmutableList<ModManifestEntry> installedMods = installedModMap.get(mod.getUniqueID());
|
ImmutableList<ModManifestEntry> installedMods = installedModMap.get(mod.getUniqueID());
|
||||||
if (installedMods.size() > 1) {
|
if (installedMods.size() > 1) {
|
||||||
DialogUtils.showAlertDialog(root, R.string.error,
|
DialogUtils.showAlertDialog(root, R.string.error,
|
||||||
String.format(context.getString(R.string.duplicate_mod_found),
|
String.format(context.getString(R.string.duplicate_mod_found),
|
||||||
installedMods.stream().map(item -> FileUtils.toPrettyPath(item.getAssetPath())).collect(Collectors.joining(","))));
|
installedMods.stream().map(item -> FileUtils.toPrettyPath(item.getAssetPath())).collect(Collectors.joining(","))));
|
||||||
return false;
|
return false;
|
||||||
} else if (installedMods.size() == 0) {
|
}
|
||||||
installedMods = installedModMap.get(mod.getUniqueID().replace("ZaneYork.CustomLocalization", "SMAPI.CustomLocalization"));
|
if (mod.getCleanInstall() != null && mod.getCleanInstall()) {
|
||||||
|
// Delete origin version with different Unique ID
|
||||||
|
if(mod.getOriginUniqueId() != null) {
|
||||||
|
installedModMap.keys().stream().filter(id -> mod.getOriginUniqueId().contains(id)).map(installedModMap::get).forEach(list -> {
|
||||||
|
for (ModManifestEntry entry : list) {
|
||||||
|
try {
|
||||||
|
FileUtils.deleteDirectory(new File(entry.getAssetPath()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Install Mod Error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Delete old version
|
||||||
|
if(installedMods.size() > 0 && mod.getVersion() != null && VersionUtil.compareVersion(installedMods.get(0).getVersion(), mod.getVersion()) < 0) {
|
||||||
|
try {
|
||||||
|
FileUtils.deleteDirectory(new File(installedMods.get(0).getAssetPath()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Install Mod Error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (installedMods.size() > 0) {
|
if (installedMods.size() > 0) {
|
||||||
try {
|
try {
|
||||||
|
@ -187,13 +207,13 @@ public class ModAssetsManager {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Install Mod Error", e);
|
Log.e(TAG, "Install Mod Error", e);
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
try {
|
try {
|
||||||
ZipUtil.unpack(context.getAssets().open(mod.getAssetPath()), modFolder);
|
ZipUtil.unpack(context.getAssets().open(mod.getAssetPath()), modFolder);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Install Mod Error", e);
|
Log.e(TAG, "Install Mod Error", e);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package com.zane.smapiinstaller.ui.config;
|
package com.zane.smapiinstaller.ui.config;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ActivityInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -8,11 +10,9 @@ import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.webkit.WebChromeClient;
|
import android.webkit.WebChromeClient;
|
||||||
import android.webkit.WebResourceError;
|
|
||||||
import android.webkit.WebResourceRequest;
|
|
||||||
import android.webkit.WebView;
|
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.hjq.language.LanguagesManager;
|
import com.hjq.language.LanguagesManager;
|
||||||
import com.zane.smapiinstaller.BuildConfig;
|
import com.zane.smapiinstaller.BuildConfig;
|
||||||
import com.zane.smapiinstaller.R;
|
import com.zane.smapiinstaller.R;
|
||||||
|
@ -28,7 +28,6 @@ import com.zane.smapiinstaller.utils.JsonUtil;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
|
@ -40,6 +39,7 @@ import androidx.navigation.Navigation;
|
||||||
*/
|
*/
|
||||||
public class ConfigEditFragment extends Fragment {
|
public class ConfigEditFragment extends Fragment {
|
||||||
private Boolean editable;
|
private Boolean editable;
|
||||||
|
private Boolean virtualKeyboardConfigMode;
|
||||||
private String configPath;
|
private String configPath;
|
||||||
|
|
||||||
private FragmentConfigEditBinding binding;
|
private FragmentConfigEditBinding binding;
|
||||||
|
@ -60,6 +60,7 @@ public class ConfigEditFragment extends Fragment {
|
||||||
CommonLogic.doOnNonNull(this.getArguments(), arguments -> {
|
CommonLogic.doOnNonNull(this.getArguments(), arguments -> {
|
||||||
ConfigEditFragmentArgs args = ConfigEditFragmentArgs.fromBundle(arguments);
|
ConfigEditFragmentArgs args = ConfigEditFragmentArgs.fromBundle(arguments);
|
||||||
editable = args.getEditable();
|
editable = args.getEditable();
|
||||||
|
virtualKeyboardConfigMode = args.getVirtualKeyboardConfigMode();
|
||||||
if (!editable) {
|
if (!editable) {
|
||||||
binding.buttonConfigSave.setVisibility(View.INVISIBLE);
|
binding.buttonConfigSave.setVisibility(View.INVISIBLE);
|
||||||
binding.buttonConfigCancel.setVisibility(View.INVISIBLE);
|
binding.buttonConfigCancel.setVisibility(View.INVISIBLE);
|
||||||
|
@ -75,7 +76,6 @@ public class ConfigEditFragment extends Fragment {
|
||||||
if (fileText != null) {
|
if (fileText != null) {
|
||||||
binding.scrollView.post(() -> {
|
binding.scrollView.post(() -> {
|
||||||
CommonLogic.doOnNonNull(this.getContext(), (context -> {
|
CommonLogic.doOnNonNull(this.getContext(), (context -> {
|
||||||
int height = (int) (binding.scrollView.getMeasuredHeight() / context.getResources().getDisplayMetrics().density * 0.95);
|
|
||||||
String lang = LanguagesManager.getAppLanguage(context).getCountry();
|
String lang = LanguagesManager.getAppLanguage(context).getCountry();
|
||||||
switch (lang) {
|
switch (lang) {
|
||||||
case "zh":
|
case "zh":
|
||||||
|
@ -90,17 +90,47 @@ public class ConfigEditFragment extends Fragment {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (editable) {
|
String assetText;
|
||||||
webObject = new WebViewObject(fileText, "tree", lang, true, height, this::configSave);
|
String baseUrl;
|
||||||
binding.editTextConfigWebview.addJavascriptInterface(webObject, "webObject");
|
if(!virtualKeyboardConfigMode) {
|
||||||
} else {
|
int height = (int) (binding.scrollView.getMeasuredHeight() / context.getResources().getDisplayMetrics().density * 0.95);
|
||||||
webObject = new WebViewObject(fileText, "text-plain", lang, false, height, null);
|
if (editable) {
|
||||||
binding.editTextConfigWebview.addJavascriptInterface(webObject, "webObject");
|
try {
|
||||||
|
JsonUtil.checkJson(fileText);
|
||||||
|
String jsonText = JsonUtil.toJson(JsonUtil.fromJson(fileText, Object.class));
|
||||||
|
webObject = new WebViewObject(jsonText, "tree", lang, true, height, 0, this::configSave);
|
||||||
|
binding.editTextConfigWebview.addJavascriptInterface(webObject, "webObject");
|
||||||
|
} catch (Exception e) {
|
||||||
|
DialogUtils.showAlertDialog(getView(), R.string.error, e.getLocalizedMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
webObject = new WebViewObject(fileText, "text-plain", lang, false, height, 0, null);
|
||||||
|
binding.editTextConfigWebview.addJavascriptInterface(webObject, "webObject");
|
||||||
|
}
|
||||||
|
baseUrl = "file:///android_asset/jsoneditor/";
|
||||||
|
assetText = FileUtils.getAssetText(context, "jsoneditor/editor.html");
|
||||||
|
Activity activity = CommonLogic.getActivityFromView(binding.editTextConfigWebview);
|
||||||
|
if(activity.getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){
|
||||||
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int height = context.getResources().getDisplayMetrics().heightPixels;
|
||||||
|
int width = context.getResources().getDisplayMetrics().widthPixels;
|
||||||
|
webObject = new WebViewObject(fileText, "tree", lang, true, height, width, this::configSave);
|
||||||
|
binding.editTextConfigWebview.addJavascriptInterface(webObject, "webObject");
|
||||||
|
binding.editTextConfigWebview.setInitialScale(100);
|
||||||
|
assetText = FileUtils.getAssetText(context, "vkconfig/index.html");
|
||||||
|
baseUrl = "file:///android_asset/vkconfig/";
|
||||||
|
Activity activity = CommonLogic.getActivityFromView(binding.editTextConfigWebview);
|
||||||
|
if(activity.getRequestedOrientation() != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE){
|
||||||
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
String assetText = FileUtils.getAssetText(context, "jsoneditor/editor.html");
|
|
||||||
if (assetText != null) {
|
if (assetText != null) {
|
||||||
binding.editTextConfigWebview.loadDataWithBaseURL(
|
binding.editTextConfigWebview.loadDataWithBaseURL(
|
||||||
"file:///android_asset/jsoneditor/",
|
baseUrl,
|
||||||
assetText,
|
assetText,
|
||||||
"text/html",
|
"text/html",
|
||||||
"utf-8", "");
|
"utf-8", "");
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.navigation.NavController;
|
import androidx.navigation.NavController;
|
||||||
|
@ -51,7 +52,7 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
||||||
ModManifestEntry mod = modList.get(position);
|
ModManifestEntry mod = modList.get(position);
|
||||||
holder.binding.textViewModName.setText(mod.getName());
|
holder.binding.textViewModName.setText(mod.getName());
|
||||||
holder.binding.textViewModDescription.setText(StringUtils.firstNonBlank(mod.getTranslatedDescription(), mod.getDescription()));
|
holder.binding.textViewModDescription.setText(StringUtils.firstNonBlank(mod.getTranslatedDescription(), mod.getDescription()));
|
||||||
holder.setModPath(mod.getAssetPath());
|
holder.setModInfo(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -66,12 +67,22 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
||||||
|
|
||||||
class ViewHolder extends RecyclerView.ViewHolder {
|
class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
private ModListItemBinding binding;
|
private ModListItemBinding binding;
|
||||||
private String modPath;
|
private ModManifestEntry modInfo;
|
||||||
|
private List<String> configList;
|
||||||
|
|
||||||
void setModPath(String modPath) {
|
void setModInfo(ModManifestEntry modInfo) {
|
||||||
this.modPath = modPath;
|
this.modInfo = modInfo;
|
||||||
File file = new File(modPath, "config.json");
|
File file = new File(modInfo.getAssetPath(), "config.json");
|
||||||
if (!file.exists()) {
|
configList = FileUtils.listAll(modInfo.getAssetPath(), (f) ->
|
||||||
|
!StringUtils.equals(f.getAbsolutePath(), file.getAbsolutePath())
|
||||||
|
&& f.getName().endsWith(".json")
|
||||||
|
&& !f.getName().startsWith(".")
|
||||||
|
&& !StringUtils.equals(f.getName(), "manifest.json")
|
||||||
|
);
|
||||||
|
if (file.exists()) {
|
||||||
|
configList.add(0, file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
if (configList.size() == 0) {
|
||||||
binding.buttonConfigMod.setVisibility(View.INVISIBLE);
|
binding.buttonConfigMod.setVisibility(View.INVISIBLE);
|
||||||
} else {
|
} else {
|
||||||
binding.buttonConfigMod.setVisibility(View.VISIBLE);
|
binding.buttonConfigMod.setVisibility(View.VISIBLE);
|
||||||
|
@ -88,7 +99,7 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setStrike() {
|
private void setStrike() {
|
||||||
File file = new File(modPath);
|
File file = new File(modInfo.getAssetPath());
|
||||||
if (StringUtils.startsWith(file.getName(), Constants.HIDDEN_FILE_PREFIX)) {
|
if (StringUtils.startsWith(file.getName(), Constants.HIDDEN_FILE_PREFIX)) {
|
||||||
binding.textViewModName.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
|
binding.textViewModName.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
|
||||||
} else {
|
} else {
|
||||||
|
@ -110,12 +121,12 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
||||||
void removeMod() {
|
void removeMod() {
|
||||||
DialogUtils.showConfirmDialog(itemView, R.string.confirm, R.string.confirm_delete_content, (dialog, which) -> {
|
DialogUtils.showConfirmDialog(itemView, R.string.confirm, R.string.confirm_delete_content, (dialog, which) -> {
|
||||||
if (which == DialogAction.POSITIVE) {
|
if (which == DialogAction.POSITIVE) {
|
||||||
File file = new File(modPath);
|
File file = new File(modInfo.getAssetPath());
|
||||||
if (file.exists()) {
|
if (file.exists()) {
|
||||||
try {
|
try {
|
||||||
FileUtils.forceDelete(file);
|
FileUtils.forceDelete(file);
|
||||||
model.removeAll(entry -> StringUtils.equals(entry.getAssetPath(), modPath));
|
model.removeAll(entry -> StringUtils.equals(entry.getAssetPath(), modInfo.getAssetPath()));
|
||||||
List<Integer> removed = removeAll(entry -> StringUtils.equals(entry.getAssetPath(), modPath));
|
List<Integer> removed = removeAll(entry -> StringUtils.equals(entry.getAssetPath(), modInfo.getAssetPath()));
|
||||||
for (int idx : removed) {
|
for (int idx : removed) {
|
||||||
notifyItemRemoved(idx);
|
notifyItemRemoved(idx);
|
||||||
}
|
}
|
||||||
|
@ -128,7 +139,7 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
||||||
}
|
}
|
||||||
|
|
||||||
void disableMod() {
|
void disableMod() {
|
||||||
File file = new File(modPath);
|
File file = new File(modInfo.getAssetPath());
|
||||||
if (file.exists() && file.isDirectory()) {
|
if (file.exists() && file.isDirectory()) {
|
||||||
if (StringUtils.startsWith(file.getName(), Constants.HIDDEN_FILE_PREFIX)) {
|
if (StringUtils.startsWith(file.getName(), Constants.HIDDEN_FILE_PREFIX)) {
|
||||||
File newFile = new File(file.getParent(), StringUtils.stripStart(file.getName(), "."));
|
File newFile = new File(file.getParent(), StringUtils.stripStart(file.getName(), "."));
|
||||||
|
@ -156,7 +167,7 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
||||||
private void moveMod(File file, File newFile) {
|
private void moveMod(File file, File newFile) {
|
||||||
try {
|
try {
|
||||||
FileUtils.moveDirectory(file, newFile);
|
FileUtils.moveDirectory(file, newFile);
|
||||||
Integer idx = findFirst(mod -> StringUtils.equalsIgnoreCase(mod.getAssetPath(), modPath));
|
Integer idx = findFirst(mod -> StringUtils.equalsIgnoreCase(mod.getAssetPath(), modInfo.getAssetPath()));
|
||||||
if (idx != null) {
|
if (idx != null) {
|
||||||
modList.get(idx).setAssetPath(newFile.getAbsolutePath());
|
modList.get(idx).setAssetPath(newFile.getAbsolutePath());
|
||||||
notifyItemChanged(idx);
|
notifyItemChanged(idx);
|
||||||
|
@ -167,10 +178,30 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
||||||
}
|
}
|
||||||
|
|
||||||
void configMod() {
|
void configMod() {
|
||||||
File file = new File(modPath, "config.json");
|
if (configList.size() > 0) {
|
||||||
if (file.exists()) {
|
if (configList.size() > 1) {
|
||||||
NavController controller = Navigation.findNavController(itemView);
|
List<String> selections = configList.stream().map(path -> StringUtils.removeStart(path, modInfo.getAssetPath())).collect(Collectors.toList());
|
||||||
MobileNavigationDirections.ActionNavAnyToConfigEditFragment action = ConfigFragmentDirections.actionNavAnyToConfigEditFragment(file.getAbsolutePath());
|
DialogUtils.showListItemsDialog(itemView, R.string.menu_config_edit, selections, (materialDialog, index) -> {
|
||||||
|
navigateToConfigEditor(configList.get(index));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
navigateToConfigEditor(configList.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void navigateToConfigEditor(String path) {
|
||||||
|
NavController controller = Navigation.findNavController(itemView);
|
||||||
|
MobileNavigationDirections.ActionNavAnyToConfigEditFragment action;
|
||||||
|
action = ConfigFragmentDirections.actionNavAnyToConfigEditFragment(path);
|
||||||
|
if ("VirtualKeyboard".equals(modInfo.getUniqueID()) && path.equals(new File(modInfo.getAssetPath(), "config.json").getAbsolutePath())) {
|
||||||
|
DialogUtils.showListItemsDialog(itemView, R.string.menu_config_edit, R.array.vk_config_mode, ((materialDialog, index) -> {
|
||||||
|
if (index == 0) {
|
||||||
|
action.setVirtualKeyboardConfigMode(true);
|
||||||
|
}
|
||||||
|
controller.navigate(action);
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
controller.navigate(action);
|
controller.navigate(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import com.zane.smapiinstaller.R;
|
||||||
import com.zane.smapiinstaller.constant.DialogAction;
|
import com.zane.smapiinstaller.constant.DialogAction;
|
||||||
import com.zane.smapiinstaller.logic.CommonLogic;
|
import com.zane.smapiinstaller.logic.CommonLogic;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
@ -356,4 +357,16 @@ public class DialogUtils {
|
||||||
materialDialog.show();
|
materialDialog.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void showListItemsDialog(View view, int title, List<String> items, BiConsumer<MaterialDialog, Integer> callback) {
|
||||||
|
CommonLogic.runOnUiThread(CommonLogic.getActivityFromView(view), (activity) -> {
|
||||||
|
MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null);
|
||||||
|
materialDialog = DialogListExtKt.listItems(materialDialog, null, items, null, false, (dialog, position, text) -> {
|
||||||
|
callback.accept(dialog, position);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
DialogUtils.setCurrentDialog(materialDialog);
|
||||||
|
materialDialog.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,12 @@ import android.os.Environment;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
import com.fasterxml.jackson.core.type.TypeReference;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.hash.Hashing;
|
import com.google.common.hash.Hashing;
|
||||||
import com.google.common.io.ByteStreams;
|
import com.google.common.io.ByteStreams;
|
||||||
import com.google.common.io.CharStreams;
|
import com.google.common.io.CharStreams;
|
||||||
|
import com.google.common.io.Files;
|
||||||
import com.hjq.language.LanguagesManager;
|
import com.hjq.language.LanguagesManager;
|
||||||
|
|
||||||
import org.apache.commons.io.input.BOMInputStream;
|
import org.apache.commons.io.input.BOMInputStream;
|
||||||
|
@ -21,6 +24,10 @@ import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件工具类
|
* 文件工具类
|
||||||
|
@ -36,7 +43,7 @@ public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
|
||||||
*/
|
*/
|
||||||
public static String getFileText(File file) {
|
public static String getFileText(File file) {
|
||||||
try {
|
try {
|
||||||
InputStream inputStream = new FileInputStream(file);
|
InputStream inputStream = new BOMInputStream(new FileInputStream(file));
|
||||||
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
|
||||||
return CharStreams.toString(reader);
|
return CharStreams.toString(reader);
|
||||||
}
|
}
|
||||||
|
@ -314,4 +321,12 @@ public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
|
||||||
public static String getStadewValleyBasePath() {
|
public static String getStadewValleyBasePath() {
|
||||||
return Environment.getExternalStorageDirectory().getAbsolutePath();
|
return Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<String> listAll(String basePath, Predicate<File> filter) {
|
||||||
|
return Lists.newArrayList(
|
||||||
|
Iterables.transform(
|
||||||
|
Iterables.filter(Files.fileTraverser().breadthFirst(new File(basePath)), filter::test),
|
||||||
|
File::getAbsolutePath)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
android:name="com.zane.smapiinstaller.ui.config.ConfigEditFragment"
|
android:name="com.zane.smapiinstaller.ui.config.ConfigEditFragment"
|
||||||
android:label="@string/menu_config_edit" >
|
android:label="@string/menu_config_edit" >
|
||||||
<argument android:name="configPath" app:argType="string"/>
|
<argument android:name="configPath" app:argType="string"/>
|
||||||
|
<argument android:name="virtualKeyboardConfigMode" android:defaultValue="false" app:argType="boolean"/>
|
||||||
<argument android:name="editable" android:defaultValue="true" app:argType="boolean"/>
|
<argument android:name="editable" android:defaultValue="true" app:argType="boolean"/>
|
||||||
</fragment>
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
|
|
|
@ -30,4 +30,8 @@
|
||||||
<item>日期(正序)</item>
|
<item>日期(正序)</item>
|
||||||
<item>日期(倒序)</item>
|
<item>日期(倒序)</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string-array name="vk_config_mode">
|
||||||
|
<item>圖形</item>
|
||||||
|
<item>文本</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -30,4 +30,8 @@
|
||||||
<item>日期(正序)</item>
|
<item>日期(正序)</item>
|
||||||
<item>日期(倒序)</item>
|
<item>日期(倒序)</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string-array name="vk_config_mode">
|
||||||
|
<item>图形</item>
|
||||||
|
<item>文本</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
|
@ -35,4 +35,8 @@
|
||||||
<item>1078428449</item>
|
<item>1078428449</item>
|
||||||
<item>980882763</item>
|
<item>980882763</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string-array name="vk_config_mode">
|
||||||
|
<item>Graphics</item>
|
||||||
|
<item>Text</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
|
@ -10,7 +10,7 @@ buildscript {
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.0.2'
|
classpath 'com.android.tools.build:gradle:4.0.2'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"
|
||||||
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.0"
|
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.1"
|
||||||
classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0'
|
classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
|
Loading…
Reference in New Issue