1.Mod disable/enable feature
2.Mods location switch setting 3.Bug fix
This commit is contained in:
parent
006196ae42
commit
ff28b20fda
|
@ -9,8 +9,8 @@ android {
|
|||
applicationId "com.zane.smapiinstaller"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 28
|
||||
versionCode 12
|
||||
versionName "1.2.3"
|
||||
versionCode 13
|
||||
versionName "1.3.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
multiDexEnabled true
|
||||
|
|
Binary file not shown.
|
@ -3,6 +3,7 @@ package com.zane.smapiinstaller;
|
|||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
|
@ -14,6 +15,11 @@ import com.zane.smapiinstaller.constant.Constants;
|
|||
import com.zane.smapiinstaller.entity.FrameworkConfig;
|
||||
import com.zane.smapiinstaller.logic.ConfigManager;
|
||||
import com.zane.smapiinstaller.logic.GameLauncher;
|
||||
import com.zane.smapiinstaller.utils.DialogUtils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
@ -57,7 +63,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
initView();
|
||||
} else {
|
||||
requestPermissions();
|
||||
this.finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,6 +108,7 @@ public class MainActivity extends AppCompatActivity {
|
|||
menu.findItem(R.id.settings_verbose_logging).setChecked(config.isVerboseLogging());
|
||||
menu.findItem(R.id.settings_check_for_updates).setChecked(config.isCheckForUpdates());
|
||||
menu.findItem(R.id.settings_developer_mode).setChecked(config.isDeveloperMode());
|
||||
Constants.MOD_PATH = config.getModsPath();
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
|
@ -125,6 +132,22 @@ public class MainActivity extends AppCompatActivity {
|
|||
case R.id.settings_developer_mode:
|
||||
config.setDeveloperMode(item.isChecked());
|
||||
break;
|
||||
case R.id.settings_set_mod_path:
|
||||
DialogUtils.showInputDialog(this, R.string.input, R.string.input_mods_path, Constants.MOD_PATH, Constants.MOD_PATH, (dialog, input) -> {
|
||||
if(StringUtils.isNoneBlank(input)) {
|
||||
String pathString = input.toString();
|
||||
File file = new File(Environment.getExternalStorageDirectory(), pathString);
|
||||
if(file.exists() && file.isDirectory()) {
|
||||
Constants.MOD_PATH = pathString;
|
||||
config.setModsPath(pathString);
|
||||
manager.flushConfig();
|
||||
}
|
||||
else {
|
||||
DialogUtils.showAlertDialog(drawer, R.string.error, R.string.error_illegal_path);
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ public class Constants {
|
|||
/**
|
||||
* Mod安装路径
|
||||
*/
|
||||
public static final String MOD_PATH = "StardewValley/Mods";
|
||||
public static String MOD_PATH = "StardewValley/Mods";
|
||||
/**
|
||||
* 日志路径
|
||||
*/
|
||||
|
|
|
@ -27,4 +27,10 @@ public class FrameworkConfig {
|
|||
*/
|
||||
@JsonProperty("DeveloperMode")
|
||||
private boolean DeveloperMode = false;
|
||||
|
||||
/**
|
||||
* Mod存放位置
|
||||
*/
|
||||
@JsonProperty("ModsPath")
|
||||
private String ModsPath = "StardewValley/Mods";
|
||||
}
|
||||
|
|
|
@ -84,6 +84,15 @@ public class ModAssetsManager {
|
|||
* @return Mod信息列表
|
||||
*/
|
||||
public static List<ModManifestEntry> findAllInstalledMods() {
|
||||
return findAllInstalledMods(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找全部已识别Mod
|
||||
* @param ignoreDisabledMod 是否忽略禁用的mod
|
||||
* @return Mod信息列表
|
||||
*/
|
||||
public static List<ModManifestEntry> findAllInstalledMods(boolean ignoreDisabledMod) {
|
||||
ConcurrentLinkedQueue<File> files = Queues.newConcurrentLinkedQueue();
|
||||
files.add(new File(Environment.getExternalStorageDirectory(), Constants.MOD_PATH));
|
||||
List<ModManifestEntry> mods = new ArrayList<>(30);
|
||||
|
@ -98,6 +107,9 @@ public class ModAssetsManager {
|
|||
ModManifestEntry manifest = FileUtils.getFileJson(file, ModManifestEntry.class);
|
||||
foundManifest = true;
|
||||
if (manifest != null && StringUtils.isNoneBlank(manifest.getUniqueID())) {
|
||||
if(ignoreDisabledMod && StringUtils.startsWith(file.getParentFile().getName(), ".")) {
|
||||
break;
|
||||
}
|
||||
manifest.setAssetPath(file.getParentFile().getAbsolutePath());
|
||||
mods.add(manifest);
|
||||
}
|
||||
|
@ -161,7 +173,7 @@ public class ModAssetsManager {
|
|||
* @param returnCallback 回调函数
|
||||
*/
|
||||
public void checkModEnvironment(Consumer<Boolean> returnCallback) {
|
||||
ImmutableListMultimap<String, ModManifestEntry> installedModMap = Multimaps.index(findAllInstalledMods(), ModManifestEntry::getUniqueID);
|
||||
ImmutableListMultimap<String, ModManifestEntry> installedModMap = Multimaps.index(findAllInstalledMods(true), ModManifestEntry::getUniqueID);
|
||||
checkDuplicateMod(installedModMap, (isConfirm) -> {
|
||||
if (isConfirm)
|
||||
checkUnsatisfiedDependencies(installedModMap, (isConfirm2) -> {
|
||||
|
|
|
@ -1,25 +1,16 @@
|
|||
package com.zane.smapiinstaller.ui.config;
|
||||
|
||||
import android.os.FileObserver;
|
||||
import android.view.View;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.zane.smapiinstaller.entity.ModManifestEntry;
|
||||
import com.zane.smapiinstaller.logic.ModAssetsManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
|
@ -48,6 +39,15 @@ class ConfigViewModel extends ViewModel {
|
|||
return modList;
|
||||
}
|
||||
|
||||
public Integer findFirst(Predicate<ModManifestEntry> predicate) {
|
||||
for (int i = 0; i < modList.size(); i++) {
|
||||
if(predicate.apply(modList.get(i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Integer> removeAll(Predicate<ModManifestEntry> predicate) {
|
||||
List<Integer> deletedId = new ArrayList<>();
|
||||
for (int i = modList.size() - 1; i >=0 ; i--) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.zane.smapiinstaller.ui.config;
|
||||
|
||||
import android.graphics.Paint;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -10,9 +11,9 @@ import com.afollestad.materialdialogs.DialogAction;
|
|||
import com.zane.smapiinstaller.R;
|
||||
import com.zane.smapiinstaller.entity.ModManifestEntry;
|
||||
import com.zane.smapiinstaller.utils.DialogUtils;
|
||||
import com.zane.smapiinstaller.utils.FileUtils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.zeroturnaround.zip.commons.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -64,6 +65,7 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
|||
else {
|
||||
configModButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
setStrike();
|
||||
}
|
||||
@BindView(R.id.button_config_mod)
|
||||
Button configModButton;
|
||||
|
@ -75,6 +77,17 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
|||
super(itemView);
|
||||
ButterKnife.bind(this, itemView);
|
||||
}
|
||||
|
||||
private void setStrike() {
|
||||
File file = new File(modPath);
|
||||
if(StringUtils.startsWith(file.getName(), ".")) {
|
||||
modName.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
}
|
||||
else {
|
||||
modName.getPaint().setFlags(modName.getPaint().getFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.button_remove_mod) void removeMod() {
|
||||
DialogUtils.showConfirmDialog(itemView, R.string.confirm, R.string.confirm_delete_content, (dialog, which)->{
|
||||
if (which == DialogAction.POSITIVE) {
|
||||
|
@ -93,6 +106,37 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
|||
}
|
||||
});
|
||||
}
|
||||
@OnClick(R.id.button_disable_mod) void disableMod() {
|
||||
File file = new File(modPath);
|
||||
if(file.exists() && file.isDirectory()) {
|
||||
if(StringUtils.startsWith(file.getName(), ".")) {
|
||||
File newFile = new File(file.getParent(), StringUtils.stripStart(file.getName(), "."));
|
||||
moveMod(file, newFile);
|
||||
}
|
||||
else {
|
||||
DialogUtils.showConfirmDialog(itemView, R.string.confirm, R.string.confirm_disable_mod, (dialog, which)-> {
|
||||
if(which == DialogAction.POSITIVE) {
|
||||
File newFile = new File(file.getParent(), "." + file.getName());
|
||||
moveMod(file, newFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void moveMod(File file, File newFile) {
|
||||
try {
|
||||
FileUtils.moveDirectory(file, newFile);
|
||||
Integer idx = model.findFirst(mod -> StringUtils.equalsIgnoreCase(mod.getAssetPath(), modPath));
|
||||
if (idx != null) {
|
||||
model.getModList().get(idx).setAssetPath(newFile.getAbsolutePath());
|
||||
notifyItemChanged(idx);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
DialogUtils.showAlertDialog(itemView, R.string.error, e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.button_config_mod) void configMod() {
|
||||
File file = new File(modPath, "config.json");
|
||||
if(file.exists()) {
|
||||
|
|
|
@ -23,10 +23,10 @@ import com.zane.smapiinstaller.entity.DownloadableContent;
|
|||
import com.zane.smapiinstaller.entity.ModManifestEntry;
|
||||
import com.zane.smapiinstaller.logic.ModAssetsManager;
|
||||
import com.zane.smapiinstaller.utils.DialogUtils;
|
||||
import com.zane.smapiinstaller.utils.FileUtils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.zeroturnaround.zip.ZipUtil;
|
||||
import org.zeroturnaround.zip.commons.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -152,9 +152,7 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter<Downloadabl
|
|||
public void onError(Response<File> response) {
|
||||
super.onError(response);
|
||||
MaterialDialog dialog = dialogRef.get();
|
||||
if (dialog != null && !dialog.isCancelled()) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
DialogUtils.dismissDialog(itemView, dialog);
|
||||
downloading.set(false);
|
||||
DialogUtils.showAlertDialog(itemView, R.string.error, R.string.error_failed_to_download);
|
||||
}
|
||||
|
@ -172,9 +170,7 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter<Downloadabl
|
|||
@Override
|
||||
public void onSuccess(Response<File> response) {
|
||||
MaterialDialog dialog = dialogRef.get();
|
||||
if (dialog != null && !dialog.isCancelled()) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
DialogUtils.dismissDialog(itemView, dialog);
|
||||
downloading.set(false);
|
||||
File downloadedFile = response.body();
|
||||
String hash = com.zane.smapiinstaller.utils.FileUtils.getFileHash(downloadedFile);
|
||||
|
|
|
@ -105,9 +105,7 @@ public class InstallFragment extends Fragment {
|
|||
DialogUtils.showAlertDialog(root, R.string.error, e.getLocalizedMessage());
|
||||
}
|
||||
finally {
|
||||
if (!dialog.isCancelled()) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
DialogUtils.dismissDialog(root, dialog);
|
||||
}
|
||||
});
|
||||
task.start();
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.zane.smapiinstaller.utils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.text.InputType;
|
||||
import android.view.View;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
@ -9,12 +11,15 @@ import com.zane.smapiinstaller.logic.CommonLogic;
|
|||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
|
||||
/**
|
||||
* 对话框相关工具类
|
||||
*/
|
||||
public class DialogUtils {
|
||||
/**
|
||||
* 设置进度条状态
|
||||
*
|
||||
* @param view context容器
|
||||
* @param dialog 对话框
|
||||
* @param message 消息
|
||||
|
@ -32,6 +37,7 @@ public class DialogUtils {
|
|||
|
||||
/**
|
||||
* 显示警告对话框
|
||||
*
|
||||
* @param view context容器
|
||||
* @param title 标题
|
||||
* @param message 消息
|
||||
|
@ -45,8 +51,9 @@ public class DialogUtils {
|
|||
|
||||
/**
|
||||
* 显示警告对话框
|
||||
* @param view context容器
|
||||
* @param title 标题
|
||||
*
|
||||
* @param view context容器
|
||||
* @param title 标题
|
||||
* @param message 消息
|
||||
*/
|
||||
public static void showAlertDialog(View view, int title, int message) {
|
||||
|
@ -58,6 +65,7 @@ public class DialogUtils {
|
|||
|
||||
/**
|
||||
* 显示确认对话框
|
||||
*
|
||||
* @param view context容器
|
||||
* @param title 标题
|
||||
* @param message 消息
|
||||
|
@ -72,6 +80,7 @@ public class DialogUtils {
|
|||
|
||||
/**
|
||||
* 显示确认对话框
|
||||
*
|
||||
* @param view context容器
|
||||
* @param title 标题
|
||||
* @param message 消息
|
||||
|
@ -86,6 +95,7 @@ public class DialogUtils {
|
|||
|
||||
/**
|
||||
* 显示进度条
|
||||
*
|
||||
* @param view context容器
|
||||
* @param title 标题
|
||||
* @param message 消息
|
||||
|
@ -107,4 +117,25 @@ public class DialogUtils {
|
|||
}
|
||||
return reference;
|
||||
}
|
||||
|
||||
public static void dismissDialog(View view, MaterialDialog dialog) {
|
||||
Activity activity = CommonLogic.getActivityFromView(view);
|
||||
if (activity != null && !activity.isFinishing()) {
|
||||
if (dialog != null && !dialog.isCancelled()) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void showInputDialog(Activity activity, int title, int content, String hint, String prefill, MaterialDialog.InputCallback callback) {
|
||||
if (activity != null && !activity.isFinishing()) {
|
||||
activity.runOnUiThread(() -> new MaterialDialog.Builder(activity)
|
||||
.title(title)
|
||||
.content(content)
|
||||
.inputType(InputType.TYPE_CLASS_TEXT)
|
||||
.input(hint, prefill, callback)
|
||||
.show()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import java.nio.charset.StandardCharsets;
|
|||
/**
|
||||
* 文件工具类
|
||||
*/
|
||||
public class FileUtils {
|
||||
public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
|
||||
/**
|
||||
* 读取文本文件
|
||||
* @param file 文件
|
||||
|
|
|
@ -12,13 +12,30 @@
|
|||
android:divider="@drawable/horizontal_divider"
|
||||
android:showDividers="middle"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/text_view_mod_name"
|
||||
android:gravity="start"
|
||||
android:textSize="20sp"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/text_view_mod_name"
|
||||
android:gravity="start"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/button_disable_mod"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_width="0px"
|
||||
android:layout_height="wrap_content"/>
|
||||
<Button
|
||||
android:id="@+id/button_disable_mod"
|
||||
app:layout_constraintStart_toEndOf="@id/text_view_mod_name"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:background="@android:drawable/ic_menu_view" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<TextView
|
||||
android:id="@+id/text_view_mod_description"
|
||||
android:gravity="start"
|
||||
|
|
|
@ -19,4 +19,9 @@
|
|||
android:title="@string/settings_developer_mode"
|
||||
app:showAsAction="never" />
|
||||
</group>
|
||||
<item
|
||||
android:id="@+id/settings_set_mod_path"
|
||||
android:orderInCategory="103"
|
||||
android:title="@string/settings_set_mod_path"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
|
|
|
@ -54,8 +54,13 @@
|
|||
<string name="button_donation_text">捐贈</string>
|
||||
<string name="button_qq_group_2_text">QQ群②: 1078428449</string>
|
||||
<string name="button_gplay" >谷歌商店详情</string>
|
||||
<string name="smapi_version">SMAPI版本: 3.3.2.2</string>
|
||||
<string name="smapi_version">SMAPI版本: 3.3.2.3</string>
|
||||
<string name="settings_verbose_logging">詳細日誌</string>
|
||||
<string name="settings_check_for_updates">檢查更新</string>
|
||||
<string name="settings_developer_mode">開發者模式</string>
|
||||
<string name="confirm_disable_mod">確定禁用該內容?</string>
|
||||
<string name="settings_set_mod_path">設置Mods位置</string>
|
||||
<string name="input">輸入</string>
|
||||
<string name="input_mods_path">請輸入Mods路徑</string>
|
||||
<string name="error_illegal_path">請輸入一個有效的路徑</string>
|
||||
</resources>
|
||||
|
|
|
@ -54,8 +54,13 @@
|
|||
<string name="button_donation_text">捐贈</string>
|
||||
<string name="button_qq_group_2_text">QQ群②: 1078428449</string>
|
||||
<string name="button_gplay" >谷歌商店详情</string>
|
||||
<string name="smapi_version">SMAPI版本: 3.3.2.2</string>
|
||||
<string name="smapi_version">SMAPI版本: 3.3.2.3</string>
|
||||
<string name="settings_verbose_logging">詳細日誌</string>
|
||||
<string name="settings_developer_mode">開發者模式</string>
|
||||
<string name="settings_check_for_updates">檢查更新</string>
|
||||
<string name="confirm_disable_mod">確定禁用該內容?</string>
|
||||
<string name="settings_set_mod_path">設置Mods位置</string>
|
||||
<string name="input">輸入</string>
|
||||
<string name="input_mods_path">請輸入Mods路徑</string>
|
||||
<string name="error_illegal_path">請輸入一個有效的路徑</string>
|
||||
</resources>
|
||||
|
|
|
@ -54,8 +54,13 @@
|
|||
<string name="button_qq_group_2_text">QQ群②: 1078428449</string>
|
||||
<string name="error_depends_on_mod_version">%1$s依赖%2$s %3$s版本,请先更新它</string>
|
||||
<string name="button_gplay">谷歌商店详情</string>
|
||||
<string name="smapi_version">SMAPI版本: 3.3.2.2</string>
|
||||
<string name="smapi_version">SMAPI版本: 3.3.2.3</string>
|
||||
<string name="settings_verbose_logging">详细日志</string>
|
||||
<string name="settings_developer_mode">开发者模式</string>
|
||||
<string name="settings_check_for_updates">检查更新</string>
|
||||
<string name="confirm_disable_mod">确定禁用该内容?</string>
|
||||
<string name="settings_set_mod_path">设置Mods位置</string>
|
||||
<string name="input">输入</string>
|
||||
<string name="input_mods_path">请输入Mods路径</string>
|
||||
<string name="error_illegal_path">请输入一个有效的路径</string>
|
||||
</resources>
|
||||
|
|
|
@ -58,8 +58,13 @@
|
|||
<string name="button_donation_text">Donation</string>
|
||||
<string name="toast_redpacket_message" translatable="false">红包码已复制\n支付宝首页搜索“9188262” 立即领红包</string>
|
||||
<string name="button_gplay">View in Play Store</string>
|
||||
<string name="smapi_version">SMAPI Version: 3.3.2.2</string>
|
||||
<string name="smapi_version">SMAPI Version: 3.3.2.3</string>
|
||||
<string name="settings_verbose_logging">Verbose Logging</string>
|
||||
<string name="settings_check_for_updates">Check For Updates</string>
|
||||
<string name="settings_developer_mode">Developer Mode</string>
|
||||
<string name="confirm_disable_mod">Are you sure to disable it?</string>
|
||||
<string name="settings_set_mod_path">Set Mods Path</string>
|
||||
<string name="input">Input</string>
|
||||
<string name="input_mods_path">Please input mods path</string>
|
||||
<string name="error_illegal_path">Please input a valid path</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue