commit
f55b33ccf1
|
@ -12,8 +12,8 @@ android {
|
|||
applicationId "com.zane.smapiinstaller"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 28
|
||||
versionCode 46
|
||||
versionName "1.5.5"
|
||||
versionCode 48
|
||||
versionName "1.5.7"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
multiDexEnabled true
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": 21,
|
||||
"version": 23,
|
||||
"contents": [
|
||||
{
|
||||
"type": "COMPAT",
|
||||
|
@ -14,16 +14,16 @@
|
|||
"name": "SMAPI for Galaxy Store",
|
||||
"assetPath": "compat/samsung_138/",
|
||||
"description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.6.1",
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_16.zip",
|
||||
"hash": "20cf2ce515dcf05596d523387b244c9e14c235387db61545e7067835e5856626"
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_17.zip",
|
||||
"hash": "ac6cff4a1decb19fc01da7314e79483f2a77d34523665370d62f8bf69dcf09dc"
|
||||
},
|
||||
{
|
||||
"type": "COMPAT",
|
||||
"name": "SMAPI for Amazon Store",
|
||||
"assetPath": "compat/amazon_138/",
|
||||
"description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.6.1",
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_amazon_138_6.zip",
|
||||
"hash": "f487f8f14fcdd0ee31ca4e3b731e6e9114bc4b43a50c930f651a939e927eeb5d"
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_amazon_138_7.zip",
|
||||
"hash": "8a63e326ab122df5157a6c70c6cac8b8669ec81701f687746b80b7a860578dbb"
|
||||
},
|
||||
{
|
||||
"type": "LOCALE",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": 21,
|
||||
"version": 23,
|
||||
"contents": [
|
||||
{
|
||||
"type": "COMPAT",
|
||||
|
@ -14,16 +14,16 @@
|
|||
"name": "SMAPI for Galaxy Store",
|
||||
"assetPath": "compat/samsung_138/",
|
||||
"description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.6.1",
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_16.zip",
|
||||
"hash": "20cf2ce515dcf05596d523387b244c9e14c235387db61545e7067835e5856626"
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_17.zip",
|
||||
"hash": "ac6cff4a1decb19fc01da7314e79483f2a77d34523665370d62f8bf69dcf09dc"
|
||||
},
|
||||
{
|
||||
"type": "COMPAT",
|
||||
"name": "SMAPI for Amazon Store",
|
||||
"assetPath": "compat/amazon_138/",
|
||||
"description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.6.1",
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_amazon_138_6.zip",
|
||||
"hash": "f487f8f14fcdd0ee31ca4e3b731e6e9114bc4b43a50c930f651a939e927eeb5d"
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_amazon_138_7.zip",
|
||||
"hash": "8a63e326ab122df5157a6c70c6cac8b8669ec81701f687746b80b7a860578dbb"
|
||||
},
|
||||
{
|
||||
"type": "LOCALE",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": 21,
|
||||
"version": 23,
|
||||
"contents": [
|
||||
{
|
||||
"type": "COMPAT",
|
||||
|
@ -14,16 +14,16 @@
|
|||
"name": "SMAPI untuk Galaxy Store",
|
||||
"assetPath": "compat/samsung_138/",
|
||||
"description": "Paket kompatibilitas SMAPI untuk versi 1.4.4.138 - terbaru, SMAPI 3.6.1",
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_16.zip",
|
||||
"hash": "20cf2ce515dcf05596d523387b244c9e14c235387db61545e7067835e5856626"
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_17.zip",
|
||||
"hash": "ac6cff4a1decb19fc01da7314e79483f2a77d34523665370d62f8bf69dcf09dc"
|
||||
},
|
||||
{
|
||||
"type": "COMPAT",
|
||||
"name": "SMAPI untuk Amazon Store",
|
||||
"assetPath": "compat/amazon_138/",
|
||||
"description": "Paket kompatibilitas SMAPI untuk versi 1.4.4.138 - terbaru, SMAPI 3.6.1",
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_amazon_138_6.zip",
|
||||
"hash": "f487f8f14fcdd0ee31ca4e3b731e6e9114bc4b43a50c930f651a939e927eeb5d"
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_amazon_138_7.zip",
|
||||
"hash": "8a63e326ab122df5157a6c70c6cac8b8669ec81701f687746b80b7a860578dbb"
|
||||
},
|
||||
{
|
||||
"type": "LOCAL",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": 21,
|
||||
"version": 23,
|
||||
"contents": [
|
||||
{
|
||||
"type": "COMPAT",
|
||||
|
@ -14,16 +14,16 @@
|
|||
"name": "SMAPI三星商店兼容包",
|
||||
"assetPath": "compat/samsung_138/",
|
||||
"description": "SMAPI三星商店兼容包, 适用版本1.4.4.138至今, SMAPI 3.6.1",
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_16.zip",
|
||||
"hash": "20cf2ce515dcf05596d523387b244c9e14c235387db61545e7067835e5856626"
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_17.zip",
|
||||
"hash": "ac6cff4a1decb19fc01da7314e79483f2a77d34523665370d62f8bf69dcf09dc"
|
||||
},
|
||||
{
|
||||
"type": "COMPAT",
|
||||
"name": "SMAPI亚马逊商店兼容包",
|
||||
"assetPath": "compat/amazon_138/",
|
||||
"description": "SMAPI亚马逊商店兼容包, 适用版本1.4.4.138至今, SMAPI 3.6.1",
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_amazon_138_6.zip",
|
||||
"hash": "f487f8f14fcdd0ee31ca4e3b731e6e9114bc4b43a50c930f651a939e927eeb5d"
|
||||
"url": "http://zaneyork.cn/download/compat/smapi_amazon_138_7.zip",
|
||||
"hash": "8a63e326ab122df5157a6c70c6cac8b8669ec81701f687746b80b7a860578dbb"
|
||||
},
|
||||
{
|
||||
"type": "LOCALE",
|
||||
|
|
|
@ -26,6 +26,7 @@ import com.zane.smapiinstaller.constant.DialogAction;
|
|||
import com.zane.smapiinstaller.dto.AppUpdateCheckResultDto;
|
||||
import com.zane.smapiinstaller.entity.AppConfig;
|
||||
import com.zane.smapiinstaller.entity.FrameworkConfig;
|
||||
import com.zane.smapiinstaller.logic.ActivityResultHandler;
|
||||
import com.zane.smapiinstaller.logic.CommonLogic;
|
||||
import com.zane.smapiinstaller.logic.ConfigManager;
|
||||
import com.zane.smapiinstaller.logic.GameLauncher;
|
||||
|
@ -42,6 +43,7 @@ import java.io.File;
|
|||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
@ -97,6 +99,12 @@ public class MainActivity extends AppCompatActivity {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
ActivityResultHandler.triggerListener(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package com.zane.smapiinstaller.logic;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import java9.util.function.BiConsumer;
|
||||
|
||||
public class ActivityResultHandler {
|
||||
public static int REQUEST_CODE_APP_INSTALL = 1001;
|
||||
|
||||
public static ConcurrentHashMap<Integer, BiConsumer<Integer, Intent>> listenerMap = new ConcurrentHashMap<>();
|
||||
|
||||
public static void registerListener(int requestCode, BiConsumer<Integer, Intent> listener) {
|
||||
listenerMap.put(requestCode, listener);
|
||||
}
|
||||
|
||||
public static void triggerListener(int requestCode, int resultCode, Intent data) {
|
||||
BiConsumer<Integer, Intent> biConsumer = listenerMap.get(requestCode);
|
||||
if(biConsumer != null) {
|
||||
biConsumer.accept(resultCode, data);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import android.content.pm.PackageManager;
|
|||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.apksig.ApkSigner;
|
||||
|
@ -19,11 +20,14 @@ import com.google.common.collect.Iterables;
|
|||
import com.google.common.hash.Hashing;
|
||||
import com.google.common.io.Files;
|
||||
import com.zane.smapiinstaller.BuildConfig;
|
||||
import com.zane.smapiinstaller.MainActivity;
|
||||
import com.zane.smapiinstaller.R;
|
||||
import com.zane.smapiinstaller.constant.Constants;
|
||||
import com.zane.smapiinstaller.constant.DialogAction;
|
||||
import com.zane.smapiinstaller.constant.ManifestPatchConstants;
|
||||
import com.zane.smapiinstaller.entity.ApkFilesManifest;
|
||||
import com.zane.smapiinstaller.entity.ManifestEntry;
|
||||
import com.zane.smapiinstaller.utils.DialogUtils;
|
||||
import com.zane.smapiinstaller.utils.FileUtils;
|
||||
import com.zane.smapiinstaller.utils.ZipUtils;
|
||||
|
||||
|
@ -131,8 +135,7 @@ public class ApkPatcher {
|
|||
errorMessage.set(context.getString(R.string.error_directory_exists_with_same_filename, contentFolder.getAbsolutePath()));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
extract(0);
|
||||
}
|
||||
ZipUtils.removeEntries(sourceDir, "assets/Content", distFile.getAbsolutePath(), (progress) -> emitProgress((int) (progress * 0.05)));
|
||||
|
@ -209,11 +212,9 @@ public class ApkPatcher {
|
|||
errorMessage.set(StringUtils.stripToEmpty(errorMessage.get()) + "\n" + errorMsg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if(StringUtils.equals(crc, entry.getPatchedCrc())){
|
||||
} else if (StringUtils.equals(crc, entry.getPatchedCrc())) {
|
||||
bytes = originBytes;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
String errorMsg = context.getString(R.string.error_patch_crc_incorrect, entry.getTargetPath(), crc);
|
||||
errorMessage.set(StringUtils.stripToEmpty(errorMessage.get()) + "\n" + errorMsg);
|
||||
return null;
|
||||
|
@ -402,6 +403,20 @@ public class ApkPatcher {
|
|||
* @param apkPath 安装包路径
|
||||
*/
|
||||
public void install(String apkPath) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
boolean haveInstallPermission = context.getPackageManager().canRequestPackageInstalls();
|
||||
if (!haveInstallPermission) {
|
||||
DialogUtils.showConfirmDialog(MainActivity.instance, R.string.confirm, R.string.request_unknown_source_permission, ((dialog, dialogAction) -> {
|
||||
if(dialogAction == DialogAction.POSITIVE) {
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
|
||||
ActivityResultHandler.registerListener(ActivityResultHandler.REQUEST_CODE_APP_INSTALL, (resultCode, data) -> this.install(apkPath));
|
||||
MainActivity.instance.startActivityForResult(intent, ActivityResultHandler.REQUEST_CODE_APP_INSTALL);
|
||||
}
|
||||
}));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(fromFile(new File(apkPath)), "application/vnd.android.package-archive");
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.view.ViewGroup;
|
|||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.zane.smapiinstaller.MobileNavigationDirections;
|
||||
import com.zane.smapiinstaller.R;
|
||||
import com.zane.smapiinstaller.constant.Constants;
|
||||
import com.zane.smapiinstaller.constant.DialogAction;
|
||||
|
@ -175,7 +176,7 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
|||
File file = new File(modPath, "config.json");
|
||||
if(file.exists()) {
|
||||
NavController controller = Navigation.findNavController(itemView);
|
||||
ConfigFragmentDirections.ActionNavConfigToConfigEditFragment action = ConfigFragmentDirections.actionNavConfigToConfigEditFragment(file.getAbsolutePath());
|
||||
MobileNavigationDirections.ActionNavAnyToConfigEditFragment action = ConfigFragmentDirections.actionNavAnyToConfigEditFragment(file.getAbsolutePath());
|
||||
controller.navigate(action);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.view.LayoutInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.zane.smapiinstaller.MobileNavigationDirections;
|
||||
import com.zane.smapiinstaller.R;
|
||||
import com.zane.smapiinstaller.constant.Constants;
|
||||
import com.zane.smapiinstaller.entity.HelpItemList;
|
||||
|
@ -60,7 +61,7 @@ public class HelpFragment extends Fragment {
|
|||
NavController controller = Navigation.findNavController(view);
|
||||
File logFile = new File(Environment.getExternalStorageDirectory(), Constants.LOG_PATH);
|
||||
if(logFile.exists()) {
|
||||
HelpFragmentDirections.ActionNavHelpToConfigEditFragment action = HelpFragmentDirections.actionNavHelpToConfigEditFragment(logFile.getAbsolutePath());
|
||||
MobileNavigationDirections.ActionNavAnyToConfigEditFragment action = HelpFragmentDirections.actionNavAnyToConfigEditFragment(logFile.getAbsolutePath());
|
||||
action.setEditable(false);
|
||||
controller.navigate(action);
|
||||
}
|
||||
|
|
|
@ -67,6 +67,13 @@ public class DialogUtils {
|
|||
materialDialog.show();
|
||||
});
|
||||
}
|
||||
public static void showAlertDialog(Activity context, int title, String message) {
|
||||
CommonLogic.runOnUiThread(context, (activity) -> {
|
||||
MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null).message(null, message, null).positiveButton(R.string.ok, null, null);
|
||||
DialogUtils.setCurrentDialog(materialDialog);
|
||||
materialDialog.show();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示警告对话框
|
||||
|
@ -83,6 +90,14 @@ public class DialogUtils {
|
|||
});
|
||||
}
|
||||
|
||||
public static void showAlertDialog(Activity context, int title, int message) {
|
||||
CommonLogic.runOnUiThread(context, (activity) -> {
|
||||
MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null).message(message, null, null).positiveButton(R.string.ok, null, null);
|
||||
DialogUtils.setCurrentDialog(materialDialog);
|
||||
materialDialog.show();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示确认对话框
|
||||
*
|
||||
|
@ -104,6 +119,19 @@ public class DialogUtils {
|
|||
materialDialog.show();
|
||||
});
|
||||
}
|
||||
public static void showConfirmDialog(Activity context, int title, int message, BiConsumer<MaterialDialog, DialogAction> callback) {
|
||||
CommonLogic.runOnUiThread(context, (activity) -> {
|
||||
MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null).message(message, null, null).positiveButton(R.string.confirm, null, dialog -> {
|
||||
callback.accept(dialog, DialogAction.POSITIVE);
|
||||
return null;
|
||||
}).negativeButton(R.string.cancel, null, dialog -> {
|
||||
callback.accept(dialog, DialogAction.NEGATIVE);
|
||||
return null;
|
||||
});
|
||||
DialogUtils.setCurrentDialog(materialDialog);
|
||||
materialDialog.show();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示确认对话框
|
||||
|
@ -178,6 +206,20 @@ public class DialogUtils {
|
|||
});
|
||||
return reference;
|
||||
}
|
||||
public static AtomicReference<ProgressDialog> showProgressDialog(Activity context, int title, String message) {
|
||||
AtomicReference<ProgressDialog> reference = new AtomicReference<>();
|
||||
CommonLogic.runOnUiThread(context, (activity) -> {
|
||||
ProgressDialog dialog = new ProgressDialog(activity);
|
||||
DialogUtils.setCurrentDialog(dialog);
|
||||
dialog.setMessage(message);
|
||||
dialog.setCancelable(false);
|
||||
dialog.setMax(100);
|
||||
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||
dialog.show();
|
||||
reference.set(dialog);
|
||||
});
|
||||
return reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解散指定对话框
|
||||
|
@ -221,6 +263,20 @@ public class DialogUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static void dismissDialog(Activity activity, ProgressDialog dialog) {
|
||||
if (activity != null && !activity.isFinishing()) {
|
||||
activity.runOnUiThread(() -> {
|
||||
if (dialog != null) {
|
||||
try {
|
||||
dialog.dismiss();
|
||||
} catch (Exception e) {
|
||||
Crashes.trackError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解散当前对话框
|
||||
*/
|
||||
|
|
|
@ -31,24 +31,12 @@
|
|||
android:name="com.zane.smapiinstaller.ui.config.ConfigFragment"
|
||||
android:label="@string/menu_config"
|
||||
tools:layout="@layout/fragment_config">
|
||||
<action
|
||||
android:id="@+id/action_nav_config_to_config_edit_fragment"
|
||||
app:destination="@id/config_edit_fragment">
|
||||
<argument android:name="configPath" app:argType="string"/>
|
||||
<argument android:name="editable" android:defaultValue="true" app:argType="boolean"/>
|
||||
</action>
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/nav_help"
|
||||
android:name="com.zane.smapiinstaller.ui.help.HelpFragment"
|
||||
android:label="@string/menu_help"
|
||||
tools:layout="@layout/fragment_help">
|
||||
<action
|
||||
android:id="@+id/action_nav_help_to_config_edit_fragment"
|
||||
app:destination="@id/config_edit_fragment" >
|
||||
<argument android:name="configPath" app:argType="string"/>
|
||||
<argument android:name="editable" android:defaultValue="true" app:argType="boolean"/>
|
||||
</action>
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/nav_download"
|
||||
|
@ -60,7 +48,6 @@
|
|||
android:name="com.zane.smapiinstaller.ui.about.AboutFragment"
|
||||
android:label="@string/menu_about"
|
||||
tools:layout="@layout/fragment_about" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_mod_update"
|
||||
android:name="com.zane.smapiinstaller.ui.update.ModUpdateFragment"
|
||||
|
@ -71,6 +58,12 @@
|
|||
android:defaultValue="{}"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<action
|
||||
android:id="@+id/action_nav_any_to_config_edit_fragment"
|
||||
app:destination="@id/config_edit_fragment">
|
||||
<argument android:name="configPath" app:argType="string"/>
|
||||
<argument android:name="editable" android:defaultValue="true" app:argType="boolean"/>
|
||||
</action>
|
||||
<action
|
||||
android:id="@+id/action_nav_any_to_mod_update_fragment"
|
||||
app:destination="@id/nav_mod_update" >
|
||||
|
|
|
@ -81,4 +81,5 @@
|
|||
<string name="error_directory_exists_with_same_filename">%1$s不是一個文件夾, 請手動刪除該文件</string>
|
||||
<string name="error_patch_crc_incorrect">增量更新%1$s失敗: CRC (%2$s))</string>
|
||||
<string name="settings_rewrite_in_parallel">多線程重寫</string>
|
||||
<string name="request_unknown_source_permission">需要开启未知源权限以安装Mod框架,是否前往设置开启?</string>
|
||||
</resources>
|
||||
|
|
|
@ -81,4 +81,5 @@
|
|||
<string name="error_directory_exists_with_same_filename">%1$s不是一个文件夹, 请手动删除该文件</string>
|
||||
<string name="error_patch_crc_incorrect">增量更新%1$s失败: CRC (%2$s))</string>
|
||||
<string name="settings_rewrite_in_parallel">多线程重写</string>
|
||||
<string name="request_unknown_source_permission">需要开启未知源权限以安装Mod框架,是否前往设置开启?</string>
|
||||
</resources>
|
||||
|
|
|
@ -85,4 +85,5 @@
|
|||
<string name="error_directory_exists_with_same_filename">%1$s is not a directory, please delete it manually.</string>
|
||||
<string name="error_patch_crc_incorrect">Patch %1$s failed: CRC (%2$s))</string>
|
||||
<string name="settings_rewrite_in_parallel">Rewrite in Parallel</string>
|
||||
<string name="request_unknown_source_permission">Needs to switch unknown source permission on to install mod framework, open settings?</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue