1.Full multi-language support

2.Bug fix
This commit is contained in:
ZaneYork 2020-03-17 15:52:10 +08:00
parent ff28b20fda
commit c32e8994c8
26 changed files with 364 additions and 46 deletions

View File

@ -9,8 +9,8 @@ android {
applicationId "com.zane.smapiinstaller"
minSdkVersion 19
targetSdkVersion 28
versionCode 13
versionName "1.3.0"
versionCode 14
versionName "1.3.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
@ -69,6 +69,7 @@ dependencies {
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.10.3'
implementation 'com.github.didikee:AndroidDonate:0.1.0'
implementation 'com.hjq:language:3.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'

View File

@ -142,3 +142,4 @@
-dontwarn org.spongycastle.jce.provider.X509LDAPCertStoreSpi
-dontwarn org.spongycastle.x509.util.LDAPStoreHelper
-keep class org.slf4j.**
-keep class com.hjq.language.** {*;}

View File

@ -1,5 +1,5 @@
{
"version": 4,
"version": 5,
"contents": [
{
"type": "COMPAT",
@ -11,8 +11,8 @@
},
{
"type": "LOCALE",
"name": "中文汉化v2.5.1",
"description": "简体中文语言包感谢Wabi-Sabi提供",
"name": "Chinese Locale v2.5.1",
"description": "Chinese simplified locale pack, thanks Wabi-Sabi",
"url": "http://zaneyork.cn/download/locale/locale_pack_zh_2.5.1.zip",
"hash": "4924ba7022c5604e7bc46ee2aad27d4f285c299a3939f3d2817afc10e2e73d77"
}

View File

@ -0,0 +1,20 @@
{
"version": 5,
"contents": [
{
"type": "COMPAT",
"name": "SMAPI for 1.4.5.137",
"assetPath": "compat/137/",
"description": "SMAPI compat package for game 1.4.4.128 - 1.4.5.137, SMAPI 3.3.2.0",
"url": "http://zaneyork.cn/download/compat/smapi_137.zip",
"hash": "bd16e8e4cb52d636e24c6a2d2309b66a60e492d2b97c1b8f6a519c04ac42ebdc"
},
{
"type": "LOCALE",
"name": "Chinese Locale v2.5.1",
"description": "Chinese simplified locale pack, thanks Wabi-Sabi",
"url": "http://zaneyork.cn/download/locale/locale_pack_zh_2.5.1.zip",
"hash": "4924ba7022c5604e7bc46ee2aad27d4f285c299a3939f3d2817afc10e2e73d77"
}
]
}

View File

@ -0,0 +1,20 @@
{
"version": 5,
"contents": [
{
"type": "COMPAT",
"name": "SMAPI for 1.4.5.137",
"assetPath": "compat/137/",
"description": "SMAPI兼容包, 适用版本1.4.4.128 - 1.4.5.137, SMAPI 3.3.2.0",
"url": "http://zaneyork.cn/download/compat/smapi_137.zip",
"hash": "bd16e8e4cb52d636e24c6a2d2309b66a60e492d2b97c1b8f6a519c04ac42ebdc"
},
{
"type": "LOCALE",
"name": "中文汉化v2.5.1",
"description": "简体中文语言包感谢Wabi-Sabi提供",
"url": "http://zaneyork.cn/download/locale/locale_pack_zh_2.5.1.zip",
"hash": "4924ba7022c5604e7bc46ee2aad27d4f285c299a3939f3d2817afc10e2e73d77"
}
]
}

View File

@ -1,30 +1,30 @@
{
"version": 0,
"version": 1,
"items": [
{
"title": "Mod安装一般流程",
"title": "Mod Install General Procedure",
"author": "ZaneYork",
"content": "1.前往<a href=\"https://smapi.io/mods\">兼容性查询</a>网站确认目标Mod的兼容性以及最新版本下载地址<br>2.下载Mod到手机<br>3.通过压缩文件管理器解压Mod文件包到手机内置存储的StardewValley/Mods目录下<br>4.点击安装器提供的启动按钮确认新增Mod之后的环境是否正常并启动游戏"
"content": "1.Query <a href=\"https://smapi.io/mods\">Compat</a> website for mod compatibility and latest download url<br>2.Download mod to your phone<br>3.Extract mod zip pack to internal storage of StardewValley/Mods directory<br>4.Press launch button provided by installer to make sure mod environment is satisfied and launch game"
},
{
"title": "Mod兼容网的一些相关信息",
"title": "Mod Compat Website Instructions",
"author": "凪白みと的小狐狸",
"content": "<a href=\"https://smapi.io/mods\">这里</a>有很多mod但是不提供下载只是告诉你他能不能用了有绿红四种颜色绿色部分mod说明当前最新版smapi和最新版游戏可以用这是电脑的手机基本一致但有例外并有n网链接提供下载第二个格子。黄色部分说明这个mod有问题作者也已经弃坑了但是他是开源的有其他大佬为他更新n网链接不能用了倒数第二个格子倒数第一是符号#提供了非官方的下载需要注册注册不了的挂梯子试试。灰色部分的mod是凉了但后继有人一般在倒数第二个格子里会有类似功能的mod也有没有的可以选择使用那个差不多的。红色是彻底凉凉了作者弃坑还不开源除了原作者没人能拉他一把所以没有链接还是放弃换别的吧。"
"content": "<a href=\"https://smapi.io/mods\">There</a> are many mods, but not directly url available for download, just to tell you if it is compatible. There are four colors: green, yellow, gray, and red. The green indicates that mod satisfied with the latest version of smapi and the latest version of the game (this is for PC, The mobile is basically the same, but some of them are not), and there are nexus links to provide downloads (the second column). The yellow part indicates that there is a problem with this mod. The author may not update it right now, but it is open source. Some other developer have updated unofficial version for it. The nexus link is not available. The penultimate column provides the unofficial version unofficial version. The mod in the gray part is broken, but there is no fix for it. Generally, there will be mods with similar functions in the penultimate column (may not). You can choose to use the another one. Red is completely abandoned, so there is no link, try another instead."
},
{
"title": "Mod不兼容反馈",
"title": "Mod Compatibility Feedback",
"author": "ZaneYork",
"content": "1.前往<a href=\"https://smapi.io/mods\">兼容性查询</a>网站确认目标Mod的兼容性<br>2.查阅<a href=\"https://docs.qq.com/sheet/DWmhYWVdIQ3RncFNB?c=C83A0BJ0\">安卓端兼容性报告表</a>确认Mod兼容状态<br>3.如果问题未提交,填写<a href=\"https://docs.qq.com/form/edit/DWlJZc0paV2xxR2JL\">数据收集表</a>反馈问题"
"content": "1.Lookup <a href=\"https://smapi.io/mods\">compat</a> website for compatibility<br>2.Query<a href=\"https://docs.qq.com/sheet/DWmhYWVdIQ3RncFNB?c=C83A0BJ0\">Android Compatibility Report</a> for mod compatibility<br>3.If none of them was reported, fill in this <a href=\"https://docs.qq.com/form/edit/DWlJZc0paV2xxR2JL\">form</a> to report the issue"
},
{
"title": "部分常用框架包下载链接",
"title": "Some of Most Used Framework Mods",
"author": "ZaneYork",
"content": "<a href=\"https://www.nexusmods.com/stardewvalley/mods/1915?tab=files\">Content Patcher</a>: CP前置大部分美化包(非xnb替换类)需要的前置Mod<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/1348?tab=files\">Space Core</a>: SC前置被Json Assets等Mod依赖的框架<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/1720?tab=files\">Json Assets</a>: JA前置大部分新增物品类Mod需要的前置Mod<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/4970?tab=files\">Producer Framework Mod</a>: PFM前置大部分新增制作配方类Mod需要的前置Mod"
"content": "<a href=\"https://www.nexusmods.com/stardewvalley/mods/1915?tab=files\">Content Patcher</a>: Most of the content packs(not single xnb file) needs it<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/1348?tab=files\">Space Core</a>: Json Assets needs it<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/1720?tab=files\">Json Assets</a>: Most of the content pack adding new items to game needs it<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/4970?tab=files\">Producer Framework Mod</a>: Most of the content pack adding new receipt needs it"
},
{
"title": "CustomLocalization简称为CL的作用",
"title": "CustomLocalization's feature",
"author": "alone06101",
"content": "①加载Content里面的xnb文件进入到游戏中。<br>注意Content里面的xnb文件位置必须与游戏安装包里的文件位置相一致才可以(不存在的位置可以自行新建)。<br>②可以通过加载Content里面的语言包增加游戏语言。"
"content": "①Load xnb files from it's Content folder to game.<br>Notice: xnb file in Content should has the same directory structure with game's(create it if not exist)<br>②Add new locale(such as Chinese) to the game"
}
]
}

View File

@ -0,0 +1,30 @@
{
"version": 1,
"items": [
{
"title": "Mod Install General Procedure",
"author": "ZaneYork",
"content": "1.Query <a href=\"https://smapi.io/mods\">Compat</a> website for mod compatibility and latest download url<br>2.Download mod to your phone<br>3.Extract mod zip pack to internal storage of StardewValley/Mods directory<br>4.Press launch button provided by installer to make sure mod environment is satisfied and launch game"
},
{
"title": "Mod Compat Website Instructions",
"author": "凪白みと的小狐狸",
"content": "<a href=\"https://smapi.io/mods\">There</a> lists many mods, to tell you if it is compatible. The list has four background colors: green, yellow, gray, and red:<br>Green indicates that mod is satisfied with the latest version of SMAPI and the latest version of the game (this is for PC, the mobile is basically the same, but some of them are not), and the second column provides download links of nexus.<br>Yellow part indicates that there is a problem with this mod. The author may not update it right now, but it is open source. Some developer have updated unofficial version for it. The nexus link is not available, penultimate column provides the unofficial version unofficial version.<br>Gray indicated that the mod is broken, but there is no fix for it. Generally, there will be mods with similar functions in the penultimate column (may not). You can choose to use the another one.<br>Red indicated that the mod is completely abandoned, so there is no link, try another instead."
},
{
"title": "Mod Compatibility Feedback",
"author": "ZaneYork",
"content": "1.Lookup <a href=\"https://smapi.io/mods\">compat</a> website for compatibility<br>2.Query<a href=\"https://docs.qq.com/sheet/DWmhYWVdIQ3RncFNB?c=C83A0BJ0\">Android Compatibility Report</a> for mod compatibility<br>3.If none of them was reported, fill in this <a href=\"https://docs.qq.com/form/edit/DWlJZc0paV2xxR2JL\">form</a> to report the issue"
},
{
"title": "Some of Most Used Framework Mods",
"author": "ZaneYork",
"content": "<a href=\"https://www.nexusmods.com/stardewvalley/mods/1915?tab=files\">Content Patcher</a>: Most of the content packs(not single xnb file) needs it<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/1348?tab=files\">Space Core</a>: Json Assets needs it<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/1720?tab=files\">Json Assets</a>: Most of the content pack adding new items to game needs it<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/4970?tab=files\">Producer Framework Mod</a>: Most of the content pack adding new receipt needs it"
},
{
"title": "CustomLocalization's feature",
"author": "alone06101",
"content": "①Load xnb files from it's Content folder to game.<br>Notice: xnb file in Content should has the same directory structure with game's(create it if not exist)<br>②Add new locale(such as Chinese) to the game"
}
]
}

View File

@ -0,0 +1,30 @@
{
"version": 1,
"items": [
{
"title": "Mod安装一般流程",
"author": "ZaneYork",
"content": "1.前往<a href=\"https://smapi.io/mods\">兼容性查询</a>网站确认目标Mod的兼容性以及最新版本下载地址<br>2.下载Mod到手机<br>3.通过压缩文件管理器解压Mod文件包到手机内置存储的StardewValley/Mods目录下<br>4.点击安装器提供的启动按钮确认新增Mod之后的环境是否正常并启动游戏"
},
{
"title": "Mod兼容网的一些相关信息",
"author": "凪白みと的小狐狸",
"content": "<a href=\"https://smapi.io/mods\">这里</a>有很多mod但是不提供下载只是告诉你他能不能用了有绿红四种颜色<br>绿色部分mod说明当前最新版smapi和最新版游戏可以用这是电脑的手机基本一致但有例外并有n网链接提供下载第二个格子。<br>黄色部分说明这个mod有问题作者也已经弃坑了但是他是开源的有其他大佬为他更新n网链接不能用了倒数第二个格子倒数第一是符号#)提供了非官方的下载(需要注册,注册不了的挂梯子试试)。<br>灰色部分的mod是凉了但后继有人一般在倒数第二个格子里会有类似功能的mod也有没有的可以选择使用那个差不多的。<br>红色是彻底凉凉了,作者弃坑,还不开源,除了原作者没人能拉他一把,所以没有链接,还是放弃换别的吧。"
},
{
"title": "Mod不兼容反馈",
"author": "ZaneYork",
"content": "1.前往<a href=\"https://smapi.io/mods\">兼容性查询</a>网站确认目标Mod的兼容性<br>2.查阅<a href=\"https://docs.qq.com/sheet/DWmhYWVdIQ3RncFNB?c=C83A0BJ0\">安卓端兼容性报告表</a>确认Mod兼容状态<br>3.如果问题未提交,填写<a href=\"https://docs.qq.com/form/edit/DWlJZc0paV2xxR2JL\">数据收集表</a>反馈问题"
},
{
"title": "部分常用框架包下载链接",
"author": "ZaneYork",
"content": "<a href=\"https://www.nexusmods.com/stardewvalley/mods/1915?tab=files\">Content Patcher</a>: CP前置大部分美化包(非xnb替换类)需要的前置Mod<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/1348?tab=files\">Space Core</a>: SC前置被Json Assets等Mod依赖的框架<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/1720?tab=files\">Json Assets</a>: JA前置大部分新增物品类Mod需要的前置Mod<br><a href=\"https://www.nexusmods.com/stardewvalley/mods/4970?tab=files\">Producer Framework Mod</a>: PFM前置大部分新增制作配方类Mod需要的前置Mod"
},
{
"title": "CustomLocalization简称为CL的作用",
"author": "alone06101",
"content": "①加载Content里面的xnb文件进入到游戏中。<br>注意Content里面的xnb文件位置必须与游戏安装包里的文件位置相一致才可以(不存在的位置可以自行新建)。<br>②可以通过加载Content里面的语言包增加游戏语言。"
}
]
}

View File

@ -1,13 +1,17 @@
package com.zane.smapiinstaller;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.view.Menu;
import android.view.MenuItem;
import com.afollestad.materialdialogs.MaterialDialog;
import com.google.android.material.navigation.NavigationView;
import com.hjq.language.LanguagesManager;
import com.microsoft.appcenter.AppCenter;
import com.microsoft.appcenter.analytics.Analytics;
import com.microsoft.appcenter.crashes.Crashes;
@ -20,6 +24,7 @@ import com.zane.smapiinstaller.utils.DialogUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
@ -148,6 +153,33 @@ public class MainActivity extends AppCompatActivity {
}
});
return true;
case R.id.settings_language:
DialogUtils.setCurrentDialog(new MaterialDialog.Builder(this).title(R.string.settings_set_language).items(R.array.languages).itemsCallback((dialog, itemView, position, text) -> {
boolean restart;
switch (position) {
case 0:
restart = LanguagesManager.setSystemLanguage(this);
break;
case 1:
restart = LanguagesManager.setAppLanguage(this, Locale.ENGLISH);
break;
case 2:
restart = LanguagesManager.setAppLanguage(this, Locale.SIMPLIFIED_CHINESE);
break;
case 3:
restart = LanguagesManager.setAppLanguage(this, Locale.TRADITIONAL_CHINESE);
break;
default:
return;
}
if (restart) {
// 我们可以充分运用 Activity 跳转动画在跳转的时候设置一个渐变的效果
startActivity(new Intent(this, MainActivity.class));
overridePendingTransition(R.anim.fragment_fade_enter, R.anim.fragment_fade_exit);
finish();
}
}).show());
return true;
default:
return super.onOptionsItemSelected(item);
}
@ -161,4 +193,17 @@ public class MainActivity extends AppCompatActivity {
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
@Override
protected void attachBaseContext(Context newBase) {
// 国际化适配绑定语种
super.attachBaseContext(LanguagesManager.attach(newBase));
}
@Override
protected void onDestroy() {
DialogUtils.dismissDialog();
super.onDestroy();
}
}

View File

@ -1,13 +1,28 @@
package com.zane.smapiinstaller;
import android.app.Application;
import android.content.Context;
import com.hjq.language.LanguagesManager;
import com.lzy.okgo.OkGo;
import com.zane.smapiinstaller.utils.GzipRequestInterceptor;
import okhttp3.OkHttpClient;
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
OkGo.getInstance().init(this);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(new GzipRequestInterceptor())//开启Gzip压缩
.build();
OkGo.getInstance().setOkHttpClient(okHttpClient).init(this);
LanguagesManager.init(this);
}
@Override
protected void attachBaseContext(Context base) {
// 国际化适配绑定语种
super.attachBaseContext(LanguagesManager.attach(base));
}
}

View File

@ -12,14 +12,13 @@ import android.os.Environment;
import android.util.Log;
import android.view.View;
import com.afollestad.materialdialogs.MaterialDialog;
import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.io.ByteStreams;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.entity.ApkFilesManifest;
import com.zane.smapiinstaller.entity.ManifestEntry;
import com.zane.smapiinstaller.utils.FileUtils;
import org.zeroturnaround.zip.ZipUtil;
@ -30,7 +29,6 @@ import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import pxb.android.axml.AxmlReader;
import pxb.android.axml.AxmlVisitor;
@ -106,7 +104,7 @@ public class CommonLogic {
for (File directory : compatFolder.listFiles(File::isDirectory)) {
File manifestFile = new File(directory, "apk_files_manifest.json");
if (manifestFile.exists()) {
ApkFilesManifest manifest = com.zane.smapiinstaller.utils.FileUtils.getFileJson(manifestFile, ApkFilesManifest.class);
ApkFilesManifest manifest = FileUtils.getFileJson(manifestFile, ApkFilesManifest.class);
if (manifest != null) {
apkFilesManifests.add(manifest);
}
@ -125,7 +123,7 @@ public class CommonLogic {
* @return 操作是否成功
*/
public static boolean unpackSmapiFiles(Context context, String apkPath, boolean checkMode) {
List<ManifestEntry> manifestEntries = com.zane.smapiinstaller.utils.FileUtils.getAssetJson(context, "smapi_files_manifest.json", new TypeReference<List<ManifestEntry>>() { });
List<ManifestEntry> manifestEntries = FileUtils.getAssetJson(context, "smapi_files_manifest.json", new TypeReference<List<ManifestEntry>>() { });
if (manifestEntries == null)
return false;
File basePath = new File(Environment.getExternalStorageDirectory() + "/StardewValley/");

View File

@ -3,6 +3,7 @@ package com.zane.smapiinstaller.logic;
import android.view.View;
import com.google.common.base.Predicate;
import com.hjq.language.LanguagesManager;
import com.lzy.okgo.OkGo;
import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.model.Response;
@ -10,6 +11,8 @@ import com.zane.smapiinstaller.entity.UpdatableList;
import com.zane.smapiinstaller.utils.FileUtils;
import com.zane.smapiinstaller.utils.JSONUtil;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.List;
@ -31,15 +34,31 @@ public class UpdatableListManager<T extends UpdatableList> {
* @param updateUrl 更新地址
*/
public UpdatableListManager(View root, String filename, Class<T> tClass, String updateUrl) {
updatableList = FileUtils.getAssetJson(root.getContext(), filename, tClass);
updatableList = FileUtils.getLocaledAssetJson(root.getContext(), filename, tClass);
if(!updateChecked) {
updateChecked = true;
OkGo.<String>get(updateUrl).execute(new StringCallback(){
String languageSuffix = '.' + LanguagesManager.getAppLanguage(root.getContext()).getLanguage();
updateList(root, tClass, updateUrl, filename, languageSuffix);
}
}
private void updateList(View root, Class<T> tClass, String updateUrl, String filename, String languageSuffix) {
String finalUpdateUrl = updateUrl + languageSuffix;
String finalFilename = filename + languageSuffix;
OkGo.<String>get(finalUpdateUrl).execute(new StringCallback(){
@Override
public void onError(Response<String> response) {
if(StringUtils.isNoneBlank(languageSuffix)) {
updateList(root, tClass, updateUrl, filename, "");
}
super.onError(response);
}
@Override
public void onSuccess(Response<String> response) {
UpdatableList content = JSONUtil.fromJson(response.body(), tClass);
if(content != null && updatableList.getVersion() < content.getVersion()) {
FileUtils.writeAssetJson(root.getContext(), filename, content);
FileUtils.writeAssetJson(root.getContext(), finalFilename, content);
updatableList = content;
for (Predicate<T> listener : onChangedListener) {
listener.apply(getList());
@ -48,7 +67,6 @@ public class UpdatableListManager<T extends UpdatableList> {
}
});
}
}
/**
* @return 列表

View File

@ -22,6 +22,7 @@ import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.logic.CommonLogic;
import com.zane.smapiinstaller.utils.DialogUtils;
import java.time.Duration;
@ -69,7 +70,7 @@ public class AboutFragment extends Fragment {
@OnClick(R.id.button_donation) void donation() {
Context context = this.getContext();
new MaterialDialog.Builder(context).title(R.string.button_donation_text).items(R.array.donation_methods).itemsCallback((dialog, itemView, position, text) -> {
DialogUtils.setCurrentDialog(new MaterialDialog.Builder(context).title(R.string.button_donation_text).items(R.array.donation_methods).itemsCallback((dialog, itemView, position, text) -> {
switch (position){
case 0:
boolean hasInstalledAlipayClient = AlipayDonate.hasInstalledAlipayClient(context);
@ -99,6 +100,6 @@ public class AboutFragment extends Fragment {
}
break;
}
}).show();
}).show());
}
}

View File

@ -64,6 +64,7 @@ public class InstallFragment extends Fragment {
}
}).showListener(dialogInterface -> {
final MaterialDialog dialog = (MaterialDialog) dialogInterface;
DialogUtils.setCurrentDialog(dialog);
if (task != null) {
task.interrupt();
}

View File

@ -6,17 +6,20 @@ import android.text.InputType;
import android.view.View;
import com.afollestad.materialdialogs.MaterialDialog;
import com.microsoft.appcenter.crashes.Crashes;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.logic.CommonLogic;
import java.util.concurrent.atomic.AtomicReference;
import androidx.drawerlayout.widget.DrawerLayout;
/**
* 对话框相关工具类
*/
public class DialogUtils {
private static Dialog currentDialog = null;
public static void setCurrentDialog(Dialog currentDialog) {
DialogUtils.currentDialog = currentDialog;
}
/**
* 设置进度条状态
*
@ -45,7 +48,7 @@ public class DialogUtils {
public static void showAlertDialog(View view, int title, String message) {
Activity activity = CommonLogic.getActivityFromView(view);
if (activity != null && !activity.isFinishing()) {
activity.runOnUiThread(() -> new MaterialDialog.Builder(activity).title(title).content(message).positiveText(R.string.ok).show());
activity.runOnUiThread(() -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(activity).title(title).content(message).positiveText(R.string.ok).show()));
}
}
@ -59,7 +62,7 @@ public class DialogUtils {
public static void showAlertDialog(View view, int title, int message) {
Activity activity = CommonLogic.getActivityFromView(view);
if (activity != null && !activity.isFinishing()) {
activity.runOnUiThread(() -> new MaterialDialog.Builder(activity).title(title).content(message).positiveText(R.string.ok).show());
activity.runOnUiThread(() -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(activity).title(title).content(message).positiveText(R.string.ok).show()));
}
}
@ -74,7 +77,7 @@ public class DialogUtils {
public static void showConfirmDialog(View view, int title, int message, MaterialDialog.SingleButtonCallback callback) {
Activity activity = CommonLogic.getActivityFromView(view);
if (activity != null && !activity.isFinishing()) {
activity.runOnUiThread(() -> new MaterialDialog.Builder(activity).title(title).content(message).positiveText(R.string.confirm).negativeText(R.string.cancel).onAny(callback).show());
activity.runOnUiThread(() -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(activity).title(title).content(message).positiveText(R.string.confirm).negativeText(R.string.cancel).onAny(callback).show()));
}
}
@ -89,7 +92,7 @@ public class DialogUtils {
public static void showConfirmDialog(View view, int title, String message, MaterialDialog.SingleButtonCallback callback) {
Activity activity = CommonLogic.getActivityFromView(view);
if (activity != null && !activity.isFinishing()) {
activity.runOnUiThread(() -> new MaterialDialog.Builder(activity).title(title).content(message).positiveText(R.string.confirm).negativeText(R.string.cancel).onAny(callback).show());
activity.runOnUiThread(() -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(activity).title(title).content(message).positiveText(R.string.confirm).negativeText(R.string.cancel).onAny(callback).show()));
}
}
@ -112,6 +115,7 @@ public class DialogUtils {
.progress(false, 100, true)
.cancelable(false)
.show();
currentDialog = dialog;
reference.set(dialog);
});
}
@ -122,19 +126,35 @@ public class DialogUtils {
Activity activity = CommonLogic.getActivityFromView(view);
if (activity != null && !activity.isFinishing()) {
if (dialog != null && !dialog.isCancelled()) {
try {
dialog.dismiss();
}
catch (Exception e) {
Crashes.trackError(e);
}
}
}
}
public static void dismissDialog() {
if (currentDialog != null && currentDialog.isShowing()) {
try {
currentDialog.dismiss();
}
catch (Exception e) {
Crashes.trackError(e);
}
}
}
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)
activity.runOnUiThread(() -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(activity)
.title(title)
.content(content)
.inputType(InputType.TYPE_CLASS_TEXT)
.input(hint, prefill, callback)
.show()
.show())
);
}
}

View File

@ -8,6 +8,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.hash.Hashing;
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
import com.hjq.language.LanguagesManager;
import org.apache.commons.io.input.BOMInputStream;
import org.apache.commons.lang3.StringUtils;
@ -21,6 +22,7 @@ import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
/**
* 文件工具类
@ -57,6 +59,29 @@ public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
return context.getAssets().open(filename);
}
/**
* 尝试获取本地化后的资源文件
* @param context context
* @param filename 文件名
* @return 输入流
* @throws IOException 异常
*/
public static InputStream getLocaledLocalAsset(Context context, String filename) throws IOException {
try {
String language = LanguagesManager.getAppLanguage(context).getLanguage();
String localedFilename = filename + '.' + language;
File file = new File(context.getFilesDir(), localedFilename);
if (file.exists()) {
return new BOMInputStream(new FileInputStream(file));
}
return context.getAssets().open(localedFilename);
}
catch (IOException e) {
Log.d("LOCALE", "No locale asset found", e);
}
return getLocalAsset(context, filename);
}
/**
* 读取JSON文件
* @param file 文件
@ -162,6 +187,17 @@ public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
return null;
}
public static <T> T getLocaledAssetJson(Context context, String filename, Class<T> tClass) {
try {
InputStream inputStream = getLocaledLocalAsset(context, filename);
try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
return JSONUtil.fromJson(CharStreams.toString(reader), tClass);
}
} catch (IOException ignored) {
}
return null;
}
/**
* 读取JSON资源
* @param context context

View File

@ -0,0 +1,49 @@
package com.zane.smapiinstaller.utils;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.BufferedSink;
import okio.GzipSink;
import okio.Okio;
public class GzipRequestInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
return chain.proceed(originalRequest);
}
Request compressedRequest = originalRequest.newBuilder()
.header("Content-Encoding", "gzip")
.method(originalRequest.method(), gzip(originalRequest.body()))
.build();
return chain.proceed(compressedRequest);
}
private RequestBody gzip(final RequestBody body) {
return new RequestBody() {
@Override
public MediaType contentType() {
return body.contentType();
}
@Override
public long contentLength() {
return -1; // 无法提前知道压缩后的数据大小
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
body.writeTo(gzipSink);
gzipSink.close();
}
};
}
}

View File

@ -24,4 +24,9 @@
android:orderInCategory="103"
android:title="@string/settings_set_mod_path"
app:showAsAction="never" />
<item
android:id="@+id/settings_language"
android:orderInCategory="104"
android:title="@string/settings_set_language"
app:showAsAction="never" />
</menu>

View File

@ -6,4 +6,10 @@
<item>QQ</item>
<item>紅包碼</item>
</string-array>
<string-array name="languages">
<item>自動</item>
<item>English</item>
<item>简体中文</item>
<item>繁體中文</item>
</string-array>
</resources>

View File

@ -63,4 +63,5 @@
<string name="input">輸入</string>
<string name="input_mods_path">請輸入Mods路徑</string>
<string name="error_illegal_path">請輸入一個有效的路徑</string>
<string name="settings_set_language">語言</string>
</resources>

View File

@ -6,4 +6,10 @@
<item>QQ</item>
<item>紅包碼</item>
</string-array>
<string-array name="languages">
<item>自動</item>
<item>English</item>
<item>简体中文</item>
<item>繁體中文</item>
</string-array>
</resources>

View File

@ -63,4 +63,5 @@
<string name="input">輸入</string>
<string name="input_mods_path">請輸入Mods路徑</string>
<string name="error_illegal_path">請輸入一個有效的路徑</string>
<string name="settings_set_language">語言</string>
</resources>

View File

@ -6,4 +6,10 @@
<item>QQ</item>
<item>红包码</item>
</string-array>
<string-array name="languages">
<item>自动</item>
<item>English</item>
<item>简体中文</item>
<item>繁體中文</item>
</string-array>
</resources>

View File

@ -63,4 +63,5 @@
<string name="input">输入</string>
<string name="input_mods_path">请输入Mods路径</string>
<string name="error_illegal_path">请输入一个有效的路径</string>
<string name="settings_set_language">语言</string>
</resources>

View File

@ -6,4 +6,10 @@
<item>QQ</item>
<item>Red Packet Code</item>
</string-array>
<string-array name="languages">
<item>Auto</item>
<item>English</item>
<item>简体中文</item>
<item>繁體中文</item>
</string-array>
</resources>

View File

@ -67,4 +67,5 @@
<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>
<string name="settings_set_language">Language</string>
</resources>