parent
ff28b20fda
commit
c32e8994c8
|
@ -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'
|
||||
|
|
|
@ -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.** {*;}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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里面的语言包增加游戏语言。"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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/");
|
||||
|
|
|
@ -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,23 +34,38 @@ 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(){
|
||||
@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);
|
||||
updatableList = content;
|
||||
for (Predicate<T> listener : onChangedListener) {
|
||||
listener.apply(getList());
|
||||
}
|
||||
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(), finalFilename, content);
|
||||
updatableList = content;
|
||||
for (Predicate<T> listener : onChangedListener) {
|
||||
listener.apply(getList());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ public class InstallFragment extends Fragment {
|
|||
}
|
||||
}).showListener(dialogInterface -> {
|
||||
final MaterialDialog dialog = (MaterialDialog) dialogInterface;
|
||||
DialogUtils.setCurrentDialog(dialog);
|
||||
if (task != null) {
|
||||
task.interrupt();
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
dialog.dismiss();
|
||||
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())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue