1.Compatibility fix, add save load error validate logic

2.Layout adjust
3.Minor fix
4.Disabled MonoMod for Android K and L by default
This commit is contained in:
ZaneYork 2020-04-26 11:43:53 +08:00
parent 91818a3f25
commit 303f754ee6
34 changed files with 108 additions and 132 deletions

View File

@ -12,8 +12,8 @@ android {
applicationId "com.zane.smapiinstaller"
minSdkVersion 19
targetSdkVersion 28
versionCode 36
versionName "1.4.5"
versionCode 37
versionName "1.4.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true

View File

@ -1,5 +1,5 @@
{
"version": 13,
"version": 14,
"contents": [
{
"type": "COMPAT",
@ -13,9 +13,9 @@
"type": "COMPAT",
"name": "SMAPI for Galaxy Store",
"assetPath": "compat/samsung_138/",
"description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.4.1.6",
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_8.zip",
"hash": "9def0e6f711c46e50cd962d10aa0ccf6014026a7cc544be42922ac9b49172a38"
"description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.4.1.7",
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_9.zip",
"hash": "be1908c4e456526e25e41536dff50888143eb3fa1b24ca17499d51f72c456f66"
},
{
"type": "LOCALE",

View File

@ -1,5 +1,5 @@
{
"version": 13,
"version": 14,
"contents": [
{
"type": "COMPAT",
@ -13,9 +13,9 @@
"type": "COMPAT",
"name": "SMAPI for Galaxy Store",
"assetPath": "compat/samsung_138/",
"description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.4.1.6",
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_8.zip",
"hash": "9def0e6f711c46e50cd962d10aa0ccf6014026a7cc544be42922ac9b49172a38"
"description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.4.1.7",
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_9.zip",
"hash": "be1908c4e456526e25e41536dff50888143eb3fa1b24ca17499d51f72c456f66"
},
{
"type": "LOCALE",

View File

@ -1,5 +1,5 @@
{
"version": 13,
"version": 14,
"contents": [
{
"type": "COMPAT",
@ -13,9 +13,9 @@
"type": "COMPAT",
"name": "SMAPI三星商店兼容包",
"assetPath": "compat/samsung_138/",
"description": "SMAPI三星商店兼容包 适用版本1.4.4.138至今, SMAPI 3.4.1.6",
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_8.zip",
"hash": "9def0e6f711c46e50cd962d10aa0ccf6014026a7cc544be42922ac9b49172a38"
"description": "SMAPI三星商店兼容包 适用版本1.4.4.138至今, SMAPI 3.4.1.7",
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_9.zip",
"hash": "be1908c4e456526e25e41536dff50888143eb3fa1b24ca17499d51f72c456f66"
},
{
"type": "LOCALE",

View File

@ -1,3 +1,6 @@
{
"warn.invalid-content-removed": "Invalid content was removed to prevent a crash (see the SMAPI console for info)."
"warn.invalid-content-removed": "Invalid content was removed to prevent a crash (see the SMAPI console for info).",
"warn.save-broken": "Load save failed, your save file may be broken.You can swap to previous day's save, or restore save files manually with save backups.Backup provided by SMAPI was located at StardewValley/smapi-internal/save-backups",
"btn.swap": "Swap",
"btn.back": "Back"
}

View File

@ -1,3 +1,6 @@
{
"warn.invalid-content-removed": "非法内容已移除以防游戏闪退查看SMAPI控制台获得更多信息"
"warn.invalid-content-removed": "非法内容已移除以防游戏闪退查看SMAPI控制台获得更多信息",
"warn.save-broken": "无法加载该存档,存档可能已损坏.你可以切换到前一日的存档,或者手动恢复到备份的存档.SMAPI提供的备份文件位于: StardewValley/smapi-internal/save-backups",
"btn.swap": "切换",
"btn.back": "返回"
}

View File

@ -31,7 +31,7 @@ import com.zane.smapiinstaller.logic.ConfigManager;
import com.zane.smapiinstaller.logic.GameLauncher;
import com.zane.smapiinstaller.logic.ModAssetsManager;
import com.zane.smapiinstaller.utils.DialogUtils;
import com.zane.smapiinstaller.utils.JSONUtil;
import com.zane.smapiinstaller.utils.JsonUtil;
import com.zane.smapiinstaller.utils.JsonCallback;
import com.zane.smapiinstaller.utils.TranslateUtil;
@ -343,7 +343,7 @@ public class MainActivity extends AppCompatActivity {
}
try {
NavController controller = Navigation.findNavController(this, R.id.nav_host_fragment);
controller.navigate(MobileNavigationDirections.actionNavAnyToModUpdateFragment(JSONUtil.toJson(list)));
controller.navigate(MobileNavigationDirections.actionNavAnyToModUpdateFragment(JsonUtil.toJson(list)));
} catch (Exception e) {
Crashes.trackError(e);
}

View File

@ -63,7 +63,7 @@ public class Constants {
/**
* SMAPI版本
*/
public static final String SMAPI_VERSION = "3.4.1.6";
public static final String SMAPI_VERSION = "3.4.1.7";
/**
* 平台

View File

@ -1,6 +1,7 @@
package com.zane.smapiinstaller.entity;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@ -12,6 +13,8 @@ import lombok.Data;
@Data
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY, getterVisibility= JsonAutoDetect.Visibility.NONE)
public class FrameworkConfig {
@JsonIgnore
private transient boolean initial;
/**
* 详细日志
*/

View File

@ -22,6 +22,7 @@ public class ConfigManager {
}
if(config == null) {
config = new FrameworkConfig();
config.setInitial(true);
}
}

View File

@ -25,7 +25,7 @@ import com.zane.smapiinstaller.dto.ModUpdateCheckResponseDto;
import com.zane.smapiinstaller.entity.ModManifestEntry;
import com.zane.smapiinstaller.utils.DialogUtils;
import com.zane.smapiinstaller.utils.FileUtils;
import com.zane.smapiinstaller.utils.JSONUtil;
import com.zane.smapiinstaller.utils.JsonUtil;
import com.zane.smapiinstaller.utils.JsonCallback;
import com.zane.smapiinstaller.utils.VersionUtil;
@ -319,7 +319,7 @@ public class ModAssetsManager {
try {
ModUpdateCheckRequestDto requestDto = new ModUpdateCheckRequestDto(list, new ModUpdateCheckRequestDto.SemanticVersion(gamePackageInfo.versionName));
OkGo.<List<ModUpdateCheckResponseDto>>post(Constants.UPDATE_CHECK_SERVICE_URL)
.upJson(JSONUtil.toJson(requestDto))
.upJson(JsonUtil.toJson(requestDto))
.execute(new JsonCallback<List<ModUpdateCheckResponseDto>>(new TypeReference<List<ModUpdateCheckResponseDto>>() {
}) {
@Override

View File

@ -1,5 +0,0 @@
package com.zane.smapiinstaller.logic;
public class SaveValidator {
}

View File

@ -8,7 +8,7 @@ import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.model.Response;
import com.zane.smapiinstaller.entity.UpdatableList;
import com.zane.smapiinstaller.utils.FileUtils;
import com.zane.smapiinstaller.utils.JSONUtil;
import com.zane.smapiinstaller.utils.JsonUtil;
import org.apache.commons.lang3.StringUtils;
@ -60,7 +60,7 @@ public class UpdatableListManager<T extends UpdatableList> implements Listenable
@Override
public void onSuccess(Response<String> response) {
UpdatableList content = JSONUtil.fromJson(response.body(), tClass);
UpdatableList content = JsonUtil.fromJson(response.body(), tClass);
if(content != null && updatableList.getVersion() < content.getVersion()) {
FileUtils.writeAssetJson(root.getContext(), finalFilename, content);
updatableList = content;

View File

@ -50,22 +50,22 @@ public class AboutFragment extends Fragment {
CommonLogic.openInPlayStore(this.getActivity());
}
private void openPlayStore(String url) {
Intent intent = new Intent("android.intent.action.VIEW");
intent.setData(Uri.parse(url));
intent.setPackage("com.android.vending");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
CommonLogic.doOnNonNull(this.getActivity(), (activity) -> activity.startActivity(intent));
}
@OnClick({R.id.button_qq_group_1, R.id.button_qq_group_2})
void joinQQ(Button which) {
@OnClick(R.id.button_qq_group_1)
void joinQQ() {
String baseUrl = "mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D";
if (which.getId() == R.id.button_qq_group_1) {
CommonLogic.doOnNonNull(this.getContext(), (context) -> CommonLogic.openUrl(context, baseUrl + "AAflCLHiWw1haM1obu_f-CpGsETxXc6b"));
} else {
CommonLogic.doOnNonNull(this.getContext(), (context) -> CommonLogic.openUrl(context, baseUrl + "kshK7BavcS2jXZ6exDvezc18ksLB8YsM"));
}
DialogUtils.showListItemsDialog(imgHeart, R.string.button_qq_group_text, R.array.qq_group_list, (dialog, position) -> {
switch (position){
case 0:
CommonLogic.doOnNonNull(this.getContext(), (context) -> CommonLogic.openUrl(context, baseUrl + "AAflCLHiWw1haM1obu_f-CpGsETxXc6b"));
break;
case 1:
CommonLogic.doOnNonNull(this.getContext(), (context) -> CommonLogic.openUrl(context, baseUrl + "kshK7BavcS2jXZ6exDvezc18ksLB8YsM"));
break;
default:
CommonLogic.doOnNonNull(this.getContext(), (context) -> CommonLogic.openUrl(context, baseUrl + "zqsWYGBuAxPx0n9RI_ONs-7NA1Mm48QY"));
break;
}
});
}
@OnClick(R.id.button_donation)

View File

@ -17,7 +17,7 @@ import com.zane.smapiinstaller.constant.DialogAction;
import com.zane.smapiinstaller.logic.CommonLogic;
import com.zane.smapiinstaller.utils.DialogUtils;
import com.zane.smapiinstaller.utils.FileUtils;
import com.zane.smapiinstaller.utils.JSONUtil;
import com.zane.smapiinstaller.utils.JsonUtil;
import java.io.File;
import java.io.FileOutputStream;
@ -96,7 +96,7 @@ public class ConfigEditFragment extends Fragment {
@OnClick(R.id.button_config_save)
void onConfigSave() {
try {
JSONUtil.checkJson(editText.getText().toString());
JsonUtil.checkJson(editText.getText().toString());
FileOutputStream outputStream = new FileOutputStream(configPath);
try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream)) {
outputStreamWriter.write(editText.getText().toString());

View File

@ -39,6 +39,7 @@ import butterknife.OnClick;
/**
* {@link RecyclerView.Adapter} that can display a {@link DownloadableContent}
*
* @author Zane
*/
public class DownloadableContentAdapter extends RecyclerView.Adapter<DownloadableContentAdapter.ViewHolder> {
@ -193,14 +194,18 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter<Downloadabl
}
private void unpackLogic(Context context, File downloadedFile, ModManifestEntry finalModManifestEntry) {
if (StringUtils.equals(downloadableContent.getType(), DownloadableContentTypes.LOCALE)) {
if (finalModManifestEntry != null) {
ZipUtil.unpack(downloadedFile, new File(finalModManifestEntry.getAssetPath()));
try {
if (StringUtils.equals(downloadableContent.getType(), DownloadableContentTypes.LOCALE)) {
if (finalModManifestEntry != null) {
ZipUtil.unpack(downloadedFile, new File(finalModManifestEntry.getAssetPath()));
}
} else {
ZipUtil.unpack(downloadedFile, new File(context.getFilesDir(), downloadableContent.getAssetPath()));
}
} else {
ZipUtil.unpack(downloadedFile, new File(context.getFilesDir(), downloadableContent.getAssetPath()));
DialogUtils.showAlertDialog(itemView, R.string.info, R.string.download_unpack_success);
} catch (Exception e) {
DialogUtils.showAlertDialog(itemView, R.string.error, e.getLocalizedMessage());
}
DialogUtils.showAlertDialog(itemView, R.string.info, R.string.download_unpack_success);
}
}
}

View File

@ -7,6 +7,7 @@ import android.os.Environment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.google.common.io.Files;
@ -17,6 +18,7 @@ import com.zane.smapiinstaller.constant.Constants;
import com.zane.smapiinstaller.constant.DialogAction;
import com.zane.smapiinstaller.logic.ApkPatcher;
import com.zane.smapiinstaller.logic.CommonLogic;
import com.zane.smapiinstaller.logic.ConfigManager;
import com.zane.smapiinstaller.logic.ModAssetsManager;
import com.zane.smapiinstaller.utils.DialogUtils;
@ -47,6 +49,9 @@ public class InstallFragment extends Fragment {
private View root;
@BindView(R.id.button_install)
Button installButton;
@BindView(R.id.text_latest_running)
TextView textLatestRunning;
@ -98,6 +103,14 @@ public class InstallFragment extends Fragment {
dialog = dialogHolder.get();
} while (dialog == null);
ApkPatcher patcher = new ApkPatcher(context);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
ConfigManager configManager = new ConfigManager();
if(configManager.getConfig().isInitial()) {
configManager.getConfig().setInitial(false);
configManager.getConfig().setDisableMonoMod(true);
configManager.flushConfig();
}
}
ProgressDialog finalDialog = dialog;
patcher.registerProgressListener((progress) -> DialogUtils.setProgressDialogState(root, finalDialog, null, progress));
DialogUtils.setProgressDialogState(root, dialog, R.string.extracting_package, null);
@ -120,7 +133,7 @@ public class InstallFragment extends Fragment {
if (target == R.string.menu_download) {
DialogUtils.showConfirmDialog(root, R.string.error, StringUtils.firstNonBlank(patcher.getErrorMessage().get(), context.getString(R.string.failed_to_patch_game)), R.string.menu_download, R.string.cancel, (d, which) -> {
if (which == DialogAction.POSITIVE) {
NavController controller = Navigation.findNavController(root);
NavController controller = Navigation.findNavController(installButton);
controller.navigate(InstallFragmentDirections.actionNavInstallToNavDownload());
}
});

View File

@ -10,7 +10,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.dto.ModUpdateCheckResponseDto;
import com.zane.smapiinstaller.logic.CommonLogic;
import com.zane.smapiinstaller.utils.JSONUtil;
import com.zane.smapiinstaller.utils.JsonUtil;
import java.util.List;
@ -45,7 +45,7 @@ public class ModUpdateFragment extends Fragment {
CommonLogic.doOnNonNull(this.getArguments(), arguments -> {
String updateInfoListJson = ModUpdateFragmentArgs.fromBundle(arguments).getUpdateInfoListJson();
List<ModUpdateCheckResponseDto> updateInfos = JSONUtil.fromJson(updateInfoListJson, new TypeReference<List<ModUpdateCheckResponseDto>>() {
List<ModUpdateCheckResponseDto> updateInfos = JsonUtil.fromJson(updateInfoListJson, new TypeReference<List<ModUpdateCheckResponseDto>>() {
});
ModUpdateAdapter adapter = new ModUpdateAdapter(updateInfos);
recyclerView.setAdapter(adapter);

View File

@ -92,7 +92,7 @@ public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
try {
InputStream inputStream = new FileInputStream(file);
try (InputStreamReader reader = new InputStreamReader(new BOMInputStream(inputStream), StandardCharsets.UTF_8)) {
return JSONUtil.fromJson(CharStreams.toString(reader), type);
return JsonUtil.fromJson(CharStreams.toString(reader), type);
}
} catch (Exception ignored) {
}
@ -110,7 +110,7 @@ public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
try {
InputStream inputStream = new FileInputStream(file);
try (InputStreamReader reader = new InputStreamReader(new BOMInputStream(inputStream), StandardCharsets.UTF_8)) {
return JSONUtil.fromJson(CharStreams.toString(reader), tClass);
return JsonUtil.fromJson(CharStreams.toString(reader), tClass);
}
} catch (Exception ignored) {
}
@ -129,7 +129,7 @@ public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
File file = new File(context.getFilesDir(), tmpFilename);
FileOutputStream outputStream = new FileOutputStream(file);
try (OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
writer.write(JSONUtil.toJson(content));
writer.write(JsonUtil.toJson(content));
} finally {
File distFile = new File(context.getFilesDir(), filename);
if(distFile.exists()) {
@ -156,7 +156,7 @@ public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
File fileTmp = new File(file.getParent(), tmpFilename);
FileOutputStream outputStream = new FileOutputStream(fileTmp);
try (OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
writer.write(JSONUtil.toJson(content));
writer.write(JsonUtil.toJson(content));
} finally {
if(file.exists()) {
org.zeroturnaround.zip.commons.FileUtils.forceDelete(file);
@ -179,7 +179,7 @@ public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
try {
InputStream inputStream = getLocalAsset(context, filename);
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
return JSONUtil.fromJson(CharStreams.toString(reader), tClass);
return JsonUtil.fromJson(CharStreams.toString(reader), tClass);
}
} catch (IOException ignored) {
}
@ -190,7 +190,7 @@ public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
try {
InputStream inputStream = getLocaledLocalAsset(context, filename);
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
return JSONUtil.fromJson(CharStreams.toString(reader), tClass);
return JsonUtil.fromJson(CharStreams.toString(reader), tClass);
}
} catch (IOException ignored) {
}
@ -209,7 +209,7 @@ public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
try {
InputStream inputStream = getLocalAsset(context, filename);
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
return JSONUtil.fromJson(CharStreams.toString(reader), type);
return JsonUtil.fromJson(CharStreams.toString(reader), type);
}
} catch (IOException ignored) {
}

View File

@ -41,10 +41,10 @@ public abstract class JsonCallback<T> extends AbsCallback<T> {
}
T data = null;
if (type != null) {
data = JSONUtil.fromJson(body.string(), type);
data = JsonUtil.fromJson(body.string(), type);
}
if (clazz != null) {
data = JSONUtil.fromJson(body.string(), clazz);
data = JsonUtil.fromJson(body.string(), clazz);
}
return data;
}

View File

@ -12,7 +12,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
* JSON工具类
* @author Zane
*/
public class JSONUtil {
public class JsonUtil {
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
// 允许未定义的属性

View File

@ -54,7 +54,7 @@ public class TranslateUtil {
OkGo.<String>get(String.format(Constants.TRANSLATE_SERVICE_URL_YOUDAO, queryText)).execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
YouDaoTranslationDto translationDto = JSONUtil.fromJson(response.body(), YouDaoTranslationDto.class);
YouDaoTranslationDto translationDto = JsonUtil.fromJson(response.body(), YouDaoTranslationDto.class);
if (translationDto != null && translationDto.getErrorCode() == 0) {
List<List<YouDaoTranslationDto.Entry>> lists = translationDto.getTranslateResult();
List<TranslationResult> translations = new ArrayList<>(lists.size());
@ -83,7 +83,7 @@ public class TranslateUtil {
OkGo.<String>get(String.format(Constants.TRANSLATE_SERVICE_URL_GOOGLE, locale, queryText)).execute(new StringCallback() {
@Override
public void onSuccess(Response<String> response) {
GoogleTranslationDto translationDto = JSONUtil.fromJson(response.body(), GoogleTranslationDto.class);
GoogleTranslationDto translationDto = JsonUtil.fromJson(response.body(), GoogleTranslationDto.class);
if(translationDto != null) {
List<String> sourceText = Splitter.on("%0A").splitToList(queryText);
List<TranslationResult> translations = new ArrayList<>(sourceText.size());

View File

@ -18,7 +18,7 @@ public class KeyStoreFileManager {
static {
// Add the bouncycastle version of the BC provider so that the implementation classes returned from the keystore
// are all from the spongycastle libs.
// are all from the bouncycastle libs.
Security.addProvider(SECURITY_PROVIDER);
}

View File

@ -33,59 +33,7 @@
style="@style/Widget.AppCompat.Button.Borderless"
android:gravity="center"
android:textSize="24sp"
android:text="@string/button_qq_group_1_text" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img_qq_2"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@drawable/tencentqq"
android:contentDescription="@string/icon_desc" />
<Button
android:id="@+id/button_qq_group_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/img_qq_2"
app:layout_constraintEnd_toEndOf="parent"
style="@style/Widget.AppCompat.Button.Borderless"
android:gravity="center"
android:textSize="24sp"
android:text="@string/button_qq_group_2_text" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/img_tieba"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@drawable/global"
android:contentDescription="@string/icon_desc" />
<Button
android:id="@+id/button_tieba"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/img_tieba"
app:layout_constraintEnd_toEndOf="parent"
style="@style/Widget.AppCompat.Button.Borderless"
android:gravity="center"
android:textSize="24sp"
android:text="@string/button_tieba_sdvandroid" />
android:text="@string/button_qq_group_text" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout

View File

@ -61,7 +61,7 @@
<string name="settings_verbose_logging">Registro detallado</string>
<string name="signing_package">Firmando paquete deinstalación</string>
<string name="smapi_game_name">SMAPI Stardew Valley</string>
<string name="smapi_version">Versión SMAPI: 3.4.1.6</string>
<string name="smapi_version">Versión SMAPI: 3.4.1.7</string>
<string name="text_install_tip1">Nota: Requiere la versión del juego 1.4.5.138 o superior</string>
<string name="text_install_tip2">El cuerpo del juego debe instalarse durante la actualización o instalación</string>
<string name="unpacking_smapi_files">Desempacando</string>

View File

@ -61,7 +61,7 @@
<string name="settings_verbose_logging">Journalisation détaillée</string>
<string name="signing_package">Signature</string>
<string name="smapi_game_name">SMAPI Stardew Valley</string>
<string name="smapi_version">Version SMAPI: 3.4.1.6</string>
<string name="smapi_version">Version SMAPI: 3.4.1.7</string>
<string name="text_install_tip1">Remarques: La version du jeu 1.4.5.138 ou ultérieure est requise.</string>
<string name="text_install_tip2">Le jeu de base est requis lors de la mise à jour / installation.</string>
<string name="unpacking_smapi_files">Déballage</string>

View File

@ -61,7 +61,7 @@
<string name="settings_verbose_logging">Catatan Terperinci</string>
<string name="signing_package">Menandatangani</string>
<string name="smapi_game_name">SMAPI Stardew Valley</string>
<string name="smapi_version">Versi SMAPI: 3.4.1.6</string>
<string name="smapi_version">Versi SMAPI: 3.4.1.7</string>
<string name="text_install_tip1">Catatan: Dibutuhkan Stardew Valley versi 1.4.5.138 atau yang lebih baru.</string>
<string name="text_install_tip2">Permainan dasar diperlukan saat memperbarui/menginstal.</string>
<string name="unpacking_smapi_files">Membongkar</string>

View File

@ -61,7 +61,7 @@
<string name="settings_verbose_logging">자세한 로그</string>
<string name="signing_package">설치 패키지 서명</string>
<string name="smapi_game_name">SMAPI Stardew Valley</string>
<string name="smapi_version">SMAPI버전: 3.4.1.6</string>
<string name="smapi_version">SMAPI버전: 3.4.1.7</string>
<string name="text_install_tip1">참고 : 게임 버전 1.4.5.138 이상이 필요합니다</string>
<string name="text_install_tip2">업데이트 또는 설치 중에 게임 본체를 설치해야합니다</string>
<string name="unpacking_smapi_files">포장 풀기</string>

View File

@ -61,7 +61,7 @@
<string name="settings_verbose_logging">Log detalhado</string>
<string name="signing_package">Assinatura</string>
<string name="smapi_game_name">SMAPI Stardew Valley</string>
<string name="smapi_version">Versão SMAPI: 3.4.1.6</string>
<string name="smapi_version">Versão SMAPI: 3.4.1.7</string>
<string name="text_install_tip1">Notas: É necessária a versão do jogo 1.4.5.138 ou posterior.</string>
<string name="text_install_tip2">O jogo base é necessário ao atualizar / instalar.</string>
<string name="unpacking_smapi_files">Desembalar</string>

View File

@ -61,7 +61,7 @@
<string name="settings_verbose_logging">การบันทึกอย่างละเอียด</string>
<string name="signing_package">การลงชื่อ</string>
<string name="smapi_game_name">SMAPI Stardew Valley</string>
<string name="smapi_version">เวอร์ชั่น SMAPI: 3.4.1.6</string>
<string name="smapi_version">เวอร์ชั่น SMAPI: 3.4.1.7</string>
<string name="text_install_tip1">หมายเหตุ: จำเป็นต้องใช้เวอร์ชั่นเกม 1.4.5.138 หรือใหม่กว่า</string>
<string name="text_install_tip2">จำเป็นต้องมีเกมพื้นฐานเมื่อทำการอัพเดต / ติดตั้ง</string>
<string name="unpacking_smapi_files">แกะกล่อง</string>

View File

@ -60,7 +60,7 @@
<string name="settings_verbose_logging">詳細日誌</string>
<string name="signing_package">正在簽名安裝包</string>
<string name="smapi_game_name">SMAPI 星露谷物語</string>
<string name="smapi_version">SMAPI版本: 3.4.1.6</string>
<string name="smapi_version">SMAPI版本: 3.4.1.7</string>
<string name="text_install_tip1">注意:需要 1.4.5.138 以上遊戲版本</string>
<string name="text_install_tip2">更新或安裝期間需要安裝遊戲</string>
<string name="unpacking_smapi_files">正在解包</string>
@ -72,7 +72,7 @@
<string name="parser">格式化</string>
<string name="mod_version_update_checking">正在檢查 MOD 更新</string>
<string name="smapi_version_runing">最近執行:%s</string>
<string name="button_tieba_sdvandroid">貼吧:星露谷安卓</string>
<string name="settings_disable_mono_mod">停用 MonoMod</string>
<string name="settings_set_max_log_size">最大日誌檔案大小</string>
<string name="button_qq_group_text">QQ群</string>
</resources>

View File

@ -60,7 +60,7 @@
<string name="settings_verbose_logging">详细日志</string>
<string name="signing_package">正在签名安装包</string>
<string name="smapi_game_name">SMAPI星露谷物语</string>
<string name="smapi_version">SMAPI版本: 3.4.1.6</string>
<string name="smapi_version">SMAPI版本: 3.4.1.7</string>
<string name="text_install_tip1">注意需要不低于1.4.5.138版本的游戏本体</string>
<string name="text_install_tip2">更新或安装期间需要安装游戏本体</string>
<string name="unpacking_smapi_files">正在解包</string>
@ -72,7 +72,7 @@
<string name="parser">格式化</string>
<string name="mod_version_update_checking">正在检查MOD更新</string>
<string name="smapi_version_runing">最近运行: %s</string>
<string name="button_tieba_sdvandroid">贴吧: 星露谷安卓</string>
<string name="settings_disable_mono_mod">禁用MonoMod</string>
<string name="settings_set_max_log_size">最大日志大小</string>
<string name="button_qq_group_text">QQ群</string>
</resources>

View File

@ -30,4 +30,9 @@
<item>by Date(asc)</item>
<item>by Date(desc)</item>
</string-array>
<string-array name="qq_group_list">
<item>860453392</item>
<item>1078428449</item>
<item>980882763</item>
</string-array>
</resources>

View File

@ -60,7 +60,7 @@
<string name="settings_verbose_logging">Verbose Logging</string>
<string name="signing_package">Signing</string>
<string name="smapi_game_name">SMAPI Stardew Valley</string>
<string name="smapi_version">SMAPI Version: 3.4.1.6</string>
<string name="smapi_version">SMAPI Version: 3.4.1.7</string>
<string name="text_install_tip1">Notes: Game version 1.4.5.138 or later is required.</string>
<string name="text_install_tip2">The base game is required when updating/installing.</string>
<string name="unpacking_smapi_files">Unpacking</string>
@ -76,7 +76,7 @@
<string name="parser">Parser</string>
<string name="mod_version_update_checking">Checking for mod updates</string>
<string name="smapi_version_runing">Latest running: %s</string>
<string name="button_tieba_sdvandroid">Tieba: SDV Android</string>
<string name="settings_disable_mono_mod">Disable MonoMod</string>
<string name="settings_set_max_log_size">Max Log Size</string>
<string name="button_qq_group_text">QQ Group</string>
</resources>