parent
cf9ceb67fb
commit
3569afb695
|
@ -12,8 +12,8 @@ android {
|
|||
applicationId "com.zane.smapiinstaller"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 30
|
||||
versionCode 69
|
||||
versionName "3.7.6.7"
|
||||
versionCode 70
|
||||
versionName "3.7.6.8"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
multiDexEnabled true
|
||||
|
@ -22,11 +22,11 @@ android {
|
|||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
shrinkResources false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
debug {
|
||||
minifyEnabled false
|
||||
minifyEnabled true
|
||||
shrinkResources false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
|
|
@ -119,13 +119,12 @@
|
|||
}
|
||||
|
||||
# For Jackson
|
||||
-keepattributes Signature
|
||||
-keepattributes *Annotation*
|
||||
-keep class sun.misc.Unsafe { *; }
|
||||
-dontwarn org.codehaus.jackson.**
|
||||
-keepattributes *Annotation*,EnclosingMethod,Signature
|
||||
-keepnames class com.fasterxml.jackson.** { *; }
|
||||
-dontwarn com.fasterxml.jackson.databind.**
|
||||
-keep class org.codehaus.jackson.** { *;}
|
||||
-keep class com.fasterxml.jackson.** { *; }
|
||||
-keep class org.codehaus.** { *; }
|
||||
-keepclassmembers public final enum org.codehaus.jackson.annotate.JsonAutoDetect$Visibility {
|
||||
public static final org.codehaus.jackson.annotate.JsonAutoDetect$Visibility *; }
|
||||
|
||||
#okhttp
|
||||
-dontwarn okhttp3.**
|
||||
|
@ -139,9 +138,13 @@
|
|||
-keep class pxb.android.** { *; }
|
||||
-keep class net.fornwall.apksigner.** { *; }
|
||||
-keep class com.android.apksig.** { *; }
|
||||
|
||||
#Warning:org.bouncycastle.jce.provider.X509LDAPCertStoreSpi: can't find referenced class javax.naming.NamingEnumeration
|
||||
-dontwarn javax.naming.**
|
||||
-keep class org.bouncycastle.** {*;}
|
||||
-keep class org.bouncycastle.jcajce.provider.** { *; }
|
||||
-keep class org.bouncycastle.jce.provider.** { *; }
|
||||
#-keep class org.bouncycastle.** {*;}
|
||||
|
||||
-keep class org.slf4j.**
|
||||
-keep class com.hjq.language.** {*;}
|
||||
-keep class net.jpountz.** {*;}
|
||||
|
@ -158,3 +161,28 @@ public static java.lang.String TABLENAME;
|
|||
-dontwarn net.sqlcipher.database.**
|
||||
# If you do NOT use RxJava:
|
||||
-dontwarn rx.**
|
||||
|
||||
-keep class com.sun.org.apache.xml.internal.utils.PrefixResolver
|
||||
-keep class java.rmi.Remote
|
||||
-keep class java.rmi.server.*
|
||||
-keep class javax.annotation.processing.AbstractProcessor
|
||||
-keep class javax.el.*
|
||||
-keep class javax.servlet.http.*
|
||||
-keep class javax.servlet.jsp.el.VariableResolver
|
||||
-keep class javax.servlet.jsp.*
|
||||
-keep class javax.servlet.jsp.tagext.*
|
||||
-keep class javax.servlet.*
|
||||
-keep class javax.swing.JTree
|
||||
-keep class javax.swing.tree.TreeNode
|
||||
-keep class lombok.core.configuration.ConfigurationKey
|
||||
-keep class org.apache.tools.ant.Task
|
||||
-keep class org.apache.tools.ant.taskdefs.MatchingTask
|
||||
-keep class org.apache.xml.utils.PrefixResolver
|
||||
-keep class org.jaxen.dom.*
|
||||
-keep class org.jaxen.dom4j.Dom4jXPath
|
||||
-keep class org.jaxen.jdom.JDOMXPath
|
||||
-keep class org.jaxen.*
|
||||
-keep class org.jdom.output.XMLOutputter
|
||||
-keep class org.python.core.PyObject
|
||||
-keep class org.python.util.PythonInterpreter
|
||||
-keep class org.zeroturnaround.javarebel.ClassEventListener
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -101,9 +101,16 @@
|
|||
"assetPath": "apk/System.Xml.dll",
|
||||
"origin": 0
|
||||
},
|
||||
{
|
||||
"targetPath": "smapi-internal/BmFont.dll",
|
||||
"assetPath": "assemblies/BmFont.dll",
|
||||
"isXALZ": true,
|
||||
"origin": 1
|
||||
},
|
||||
{
|
||||
"targetPath": "smapi-internal/xTile.dll",
|
||||
"assetPath": "apk/xTile.dll",
|
||||
"origin": 0
|
||||
"assetPath": "assemblies/xTile.dll",
|
||||
"isXALZ": true,
|
||||
"origin": 1
|
||||
}
|
||||
]
|
|
@ -62,18 +62,28 @@ public class Constants {
|
|||
/**
|
||||
* 文本文件打开大小阈值
|
||||
*/
|
||||
public static int TEXT_FILE_OPEN_SIZE_LIMIT = 16 * 1024 * 1024;
|
||||
public static final int TEXT_FILE_OPEN_SIZE_LIMIT = 16 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* SMAPI版本
|
||||
*/
|
||||
public static final String SMAPI_VERSION = "3.7.6";
|
||||
|
||||
/**
|
||||
* Mono Android 10 起始版本号
|
||||
*/
|
||||
public static final int MONO_10_VERSION_CODE = 148;
|
||||
|
||||
/**
|
||||
* 应用名称
|
||||
*/
|
||||
public static String PATCHED_APP_NAME = null;
|
||||
|
||||
/**
|
||||
* Manifest中使用的路径分隔符
|
||||
*/
|
||||
public static final String FILE_SEPARATOR = "/";
|
||||
|
||||
/**
|
||||
* 平台
|
||||
*/
|
||||
|
|
|
@ -89,12 +89,9 @@ public class ApkPatcher {
|
|||
/**
|
||||
* 依次扫描package_names.json文件对应的包名,抽取找到的第一个游戏APK到SMAPI Installer路径
|
||||
*
|
||||
* @param advancedStage 0: 初始化,1: 高级安装,-1: 普通安装
|
||||
* @return 抽取后的APK文件路径,如果抽取失败返回null
|
||||
*/
|
||||
public String extract() {
|
||||
return extract(-1);
|
||||
}
|
||||
|
||||
public String extract(int advancedStage) {
|
||||
emitProgress(0);
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
|
@ -169,12 +166,9 @@ public class ApkPatcher {
|
|||
* 将指定APK文件重新打包,添加SMAPI,修改AndroidManifest.xml,同时验证版本是否正确
|
||||
*
|
||||
* @param apkPath APK文件路径
|
||||
* @param isAdvanced 是否高级模式
|
||||
* @return 是否成功打包
|
||||
*/
|
||||
public boolean patch(String apkPath) {
|
||||
return patch(apkPath, false);
|
||||
}
|
||||
|
||||
public boolean patch(String apkPath, boolean isAdvanced) {
|
||||
if (apkPath == null) {
|
||||
return false;
|
||||
|
@ -230,15 +224,15 @@ public class ApkPatcher {
|
|||
if (entry.isAdvanced() && !isAdvanced) {
|
||||
return null;
|
||||
}
|
||||
if (entry.getTargetPath().endsWith("/") && entry.getAssetPath().contains("*")) {
|
||||
String path = StringUtils.substringBeforeLast(entry.getAssetPath(), "/");
|
||||
String pattern = StringUtils.substringAfterLast(entry.getAssetPath(), "/");
|
||||
if (entry.getTargetPath().endsWith(Constants.FILE_SEPARATOR) && entry.getAssetPath().contains("*")) {
|
||||
String path = StringUtils.substringBeforeLast(entry.getAssetPath(), Constants.FILE_SEPARATOR);
|
||||
String pattern = StringUtils.substringAfterLast(entry.getAssetPath(), Constants.FILE_SEPARATOR);
|
||||
try {
|
||||
if (entry.getOrigin() == 1) {
|
||||
ArrayList<ZipUtils.ZipEntrySource> list = new ArrayList<>();
|
||||
ZipUtil.iterate(apkFile, (in, zipEntry) -> {
|
||||
String entryPath = StringUtils.substringBeforeLast(zipEntry.getName(), "/");
|
||||
String filename = StringUtils.substringAfterLast(zipEntry.getName(), "/");
|
||||
String entryPath = StringUtils.substringBeforeLast(zipEntry.getName(), Constants.FILE_SEPARATOR);
|
||||
String filename = StringUtils.substringAfterLast(zipEntry.getName(), Constants.FILE_SEPARATOR);
|
||||
if (entryPath.equals(path) && StringUtils.wildCardMatch(filename, pattern)) {
|
||||
byte[] bytes = ByteStreams.toByteArray(in);
|
||||
ZipUtils.ZipEntrySource source;
|
||||
|
@ -256,7 +250,7 @@ public class ApkPatcher {
|
|||
.filter(filename -> StringUtils.wildCardMatch(filename, pattern))
|
||||
.map(filename -> new ZipUtils.ZipEntrySource(entry.getTargetPath() + filename, entry.getCompression(), () -> {
|
||||
try {
|
||||
return FileUtils.getLocalAsset(context, path + "/" + filename);
|
||||
return FileUtils.getLocalAsset(context, path + Constants.FILE_SEPARATOR + filename);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
return null;
|
||||
|
@ -342,7 +336,7 @@ public class ApkPatcher {
|
|||
}
|
||||
case "name":
|
||||
if (strObj.contains(ManifestPatchConstants.PATTERN_MAIN_ACTIVITY)) {
|
||||
if (versionCode.get() > 147) {
|
||||
if (versionCode.get() > Constants.MONO_10_VERSION_CODE) {
|
||||
attr.obj = strObj.replaceFirst("\\w+\\.MainActivity", "crc648e5438a58262f792.SMainActivity");
|
||||
} else {
|
||||
attr.obj = strObj.replaceFirst("\\w+\\.MainActivity", "md5723872fa9a204f7f942686e9ed9d0b7d.SMainActivity");
|
||||
|
|
|
@ -40,9 +40,7 @@ import org.zeroturnaround.zip.ZipUtil;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
|
@ -204,8 +202,8 @@ public class CommonLogic {
|
|||
* @param context context
|
||||
* @param apkPath 安装包路径
|
||||
* @param checkMode 是否为校验模式
|
||||
* @param packageName
|
||||
* @param versionCode
|
||||
* @param packageName 包名
|
||||
* @param versionCode 版本号
|
||||
* @return 操作是否成功
|
||||
*/
|
||||
public static boolean unpackSmapiFiles(Context context, String apkPath, boolean checkMode, String packageName, long versionCode) {
|
||||
|
@ -254,56 +252,10 @@ public class CommonLogic {
|
|||
File targetFile = new File(basePath, entry.getTargetPath());
|
||||
switch (entry.getOrigin()) {
|
||||
case 0:
|
||||
if(entry.isExternal() && apkFilesManifest != null){
|
||||
byte[] bytes = FileUtils.getAssetBytes(context, apkFilesManifest.getBasePath() + entry.getAssetPath());
|
||||
try (FileOutputStream outputStream = new FileOutputStream(targetFile)) {
|
||||
outputStream.write(bytes);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (entry.getTargetPath().endsWith("/") && entry.getAssetPath().contains("*")) {
|
||||
String path = StringUtils.substring(entry.getAssetPath(), 0, StringUtils.lastIndexOf(entry.getAssetPath(), "/"));
|
||||
String pattern = StringUtils.substringAfterLast(entry.getAssetPath(), "/");
|
||||
try {
|
||||
Stream.of(context.getAssets().list(path))
|
||||
.filter(filename -> StringUtils.wildCardMatch(filename, pattern))
|
||||
.forEach(filename -> {
|
||||
unpackFile(context, checkMode, path + "/" + filename, new File(basePath, entry.getTargetPath() + filename));
|
||||
});
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
} else {
|
||||
unpackFile(context, checkMode, entry.getAssetPath(), targetFile);
|
||||
}
|
||||
}
|
||||
unpackFromInstaller(context, checkMode, apkFilesManifest, basePath, entry, targetFile);
|
||||
break;
|
||||
case 1:
|
||||
if (!checkMode || !targetFile.exists()) {
|
||||
if(entry.isXALZ()){
|
||||
byte[] bytes = ZipUtil.unpackEntry(new File(apkPath), entry.getAssetPath());
|
||||
if (entry.isXALZ()) {
|
||||
bytes = ZipUtils.decompressXALZ(bytes);
|
||||
}
|
||||
FileOutputStream stream = null;
|
||||
try {
|
||||
stream = FileUtils.openOutputStream(targetFile);
|
||||
stream.write(bytes);
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
finally {
|
||||
if(stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ZipUtil.unpackEntry(new File(apkPath), entry.getAssetPath(), targetFile);
|
||||
}
|
||||
}
|
||||
unpackFromApk(apkPath, checkMode, entry, targetFile);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -312,6 +264,48 @@ public class CommonLogic {
|
|||
return true;
|
||||
}
|
||||
|
||||
private static void unpackFromApk(String apkPath, boolean checkMode, ManifestEntry entry, File targetFile) {
|
||||
if (!checkMode || !targetFile.exists()) {
|
||||
if(entry.isXALZ()){
|
||||
byte[] bytes = ZipUtil.unpackEntry(new File(apkPath), entry.getAssetPath());
|
||||
if (entry.isXALZ()) {
|
||||
bytes = ZipUtils.decompressXALZ(bytes);
|
||||
}
|
||||
try (FileOutputStream stream = FileUtils.openOutputStream(targetFile)) {
|
||||
stream.write(bytes);
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
ZipUtil.unpackEntry(new File(apkPath), entry.getAssetPath(), targetFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void unpackFromInstaller(Context context, boolean checkMode, ApkFilesManifest apkFilesManifest, File basePath, ManifestEntry entry, File targetFile) {
|
||||
if(entry.isExternal() && apkFilesManifest != null){
|
||||
byte[] bytes = FileUtils.getAssetBytes(context, apkFilesManifest.getBasePath() + entry.getAssetPath());
|
||||
try (FileOutputStream outputStream = new FileOutputStream(targetFile)) {
|
||||
outputStream.write(bytes);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (entry.getTargetPath().endsWith("/") && entry.getAssetPath().contains("*")) {
|
||||
String path = StringUtils.substring(entry.getAssetPath(), 0, StringUtils.lastIndexOf(entry.getAssetPath(), "/"));
|
||||
String pattern = StringUtils.substringAfterLast(entry.getAssetPath(), "/");
|
||||
try {
|
||||
Stream.of(context.getAssets().list(path))
|
||||
.filter(filename -> StringUtils.wildCardMatch(filename, pattern))
|
||||
.forEach(filename -> unpackFile(context, checkMode, path + "/" + filename, new File(basePath, entry.getTargetPath() + filename)));
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
} else {
|
||||
unpackFile(context, checkMode, entry.getAssetPath(), targetFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void filterManifest(List<ApkFilesManifest> manifests, String packageName, long versionCode){
|
||||
Iterables.removeIf(manifests, manifest -> {
|
||||
if (manifest == null) {
|
||||
|
@ -325,10 +319,7 @@ public class CommonLogic {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
if (manifest.getTargetPackageName() != null && packageName != null && !manifest.getTargetPackageName().contains(packageName)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return manifest.getTargetPackageName() != null && packageName != null && !manifest.getTargetPackageName().contains(packageName);
|
||||
});
|
||||
}
|
||||
private static void unpackFile(Context context, boolean checkMode, String assertPath, File targetFile) {
|
||||
|
@ -398,7 +389,6 @@ public class CommonLogic {
|
|||
try {
|
||||
PackageManager manager = activity.getPackageManager();
|
||||
PackageInfo info = manager.getPackageInfo(activity.getPackageName(), 0);
|
||||
String version = info.versionName;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
return info.getLongVersionCode();
|
||||
}
|
||||
|
|
|
@ -10,9 +10,7 @@ import android.view.View;
|
|||
import com.microsoft.appcenter.crashes.Crashes;
|
||||
import com.zane.smapiinstaller.R;
|
||||
import com.zane.smapiinstaller.constant.Constants;
|
||||
import com.zane.smapiinstaller.constant.ManifestPatchConstants;
|
||||
import com.zane.smapiinstaller.utils.DialogUtils;
|
||||
import com.zane.smapiinstaller.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* 游戏启动器
|
||||
|
|
|
@ -4,7 +4,6 @@ import java.util.List;
|
|||
import java.util.function.Function;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import pxb.android.axml.NodeVisitor;
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,7 +44,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
|
@ -260,13 +259,7 @@ public class ModAssetsManager {
|
|||
DialogUtils.showConfirmDialog(root, R.string.error,
|
||||
root.getContext().getString(R.string.duplicate_mod_found, Joiner.on(";").join(list)),
|
||||
R.string.continue_text, R.string.abort,
|
||||
((dialog, which) -> {
|
||||
if (which == DialogAction.POSITIVE) {
|
||||
returnCallback.accept(true);
|
||||
} else {
|
||||
returnCallback.accept(false);
|
||||
}
|
||||
}));
|
||||
((dialog, which) -> returnCallback.accept(which == DialogAction.POSITIVE)));
|
||||
} else {
|
||||
returnCallback.accept(true);
|
||||
}
|
||||
|
@ -466,10 +459,7 @@ public class ModAssetsManager {
|
|||
if (StringUtils.isBlank(dependency.getMinimumVersion())) {
|
||||
return false;
|
||||
}
|
||||
if (VersionUtil.compareVersion(version, dependency.getMinimumVersion()) < 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return VersionUtil.compareVersion(version, dependency.getMinimumVersion()) < 0;
|
||||
}
|
||||
|
||||
private Tuple2<String, String> checkContentPackDependencyError(ModManifestEntry mod, ImmutableListMultimap<String, ModManifestEntry> installedModMap) {
|
||||
|
|
|
@ -17,6 +17,8 @@ import com.zane.smapiinstaller.databinding.FragmentAboutBinding;
|
|||
import com.zane.smapiinstaller.logic.CommonLogic;
|
||||
import com.zane.smapiinstaller.utils.DialogUtils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
/**
|
||||
|
@ -27,7 +29,7 @@ public class AboutFragment extends Fragment {
|
|||
private FragmentAboutBinding binding;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(@NotNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
binding = FragmentAboutBinding.inflate(inflater, container, false);
|
||||
binding.buttonRelease.setOnClickListener(v -> release());
|
||||
|
|
|
@ -77,9 +77,7 @@ public class ConfigEditFragment extends Fragment {
|
|||
File file = new File(configPath);
|
||||
if (file.exists() && file.length() < Constants.TEXT_FILE_OPEN_SIZE_LIMIT) {
|
||||
initAssetWebView();
|
||||
binding.scrollView.post(() -> {
|
||||
CommonLogic.doOnNonNull(this.getContext(), (context -> onScrollViewRendered(file, context)));
|
||||
});
|
||||
binding.scrollView.post(() -> CommonLogic.doOnNonNull(this.getContext(), (context -> onScrollViewRendered(file, context))));
|
||||
} else {
|
||||
DialogUtils.showConfirmDialog(binding.getRoot(), R.string.error, this.getString(R.string.text_too_large), R.string.open_with, R.string.cancel, ((dialog, which) -> {
|
||||
if (which == DialogAction.POSITIVE) {
|
||||
|
|
|
@ -32,7 +32,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
* @author Zane
|
||||
*/
|
||||
public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.ViewHolder> {
|
||||
private ConfigViewModel model;
|
||||
private final ConfigViewModel model;
|
||||
private List<ModManifestEntry> modList;
|
||||
|
||||
public ModManifestAdapter(ConfigViewModel model, List<ModManifestEntry> modList) {
|
||||
|
@ -66,7 +66,7 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
|||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private ModListItemBinding binding;
|
||||
private final ModListItemBinding binding;
|
||||
private ModManifestEntry modInfo;
|
||||
private List<String> configList;
|
||||
|
||||
|
@ -181,9 +181,7 @@ public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.
|
|||
if (configList.size() > 0) {
|
||||
if (configList.size() > 1) {
|
||||
List<String> selections = configList.stream().map(path -> StringUtils.removeStart(path, modInfo.getAssetPath())).collect(Collectors.toList());
|
||||
DialogUtils.showListItemsDialog(itemView, R.string.menu_config_edit, selections, (materialDialog, index) -> {
|
||||
navigateToConfigEditor(configList.get(index));
|
||||
});
|
||||
DialogUtils.showListItemsDialog(itemView, R.string.menu_config_edit, selections, (materialDialog, index) -> navigateToConfigEditor(configList.get(index)));
|
||||
} else {
|
||||
navigateToConfigEditor(configList.get(0));
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter<Downloadabl
|
|||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private DownloadContentItemBinding binding;
|
||||
private final DownloadContentItemBinding binding;
|
||||
|
||||
private final AtomicBoolean downloading = new AtomicBoolean(false);
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ public class HelpItemAdapter extends RecyclerView.Adapter<HelpItemAdapter.ViewHo
|
|||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private HelpListItemBinding binding;
|
||||
private final HelpListItemBinding binding;
|
||||
|
||||
public ViewHolder(View view) {
|
||||
super(view);
|
||||
|
|
|
@ -15,7 +15,7 @@ import androidx.fragment.app.Fragment;
|
|||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
|
||||
class MainTabPagerAdapter extends FragmentStateAdapter {
|
||||
private Fragment fragment;
|
||||
private final Fragment fragment;
|
||||
|
||||
public MainTabPagerAdapter(Fragment fragment) {
|
||||
super(fragment);
|
||||
|
|
|
@ -47,11 +47,7 @@ public class MainTabsFragment extends Fragment {
|
|||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
super.onPageSelected(position);
|
||||
if (position >= 3) {
|
||||
MainActivity.instance.setFloatingBarVisibility(false);
|
||||
} else {
|
||||
MainActivity.instance.setFloatingBarVisibility(true);
|
||||
}
|
||||
MainActivity.instance.setFloatingBarVisibility(position < 3);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public class ModUpdateAdapter extends RecyclerView.Adapter<ModUpdateAdapter.View
|
|||
|
||||
private final ImmutableListMultimap<String, ModManifestEntry> installedModMap;
|
||||
|
||||
private List<ModUpdateCheckResponseDto> updateInfoList;
|
||||
private final List<ModUpdateCheckResponseDto> updateInfoList;
|
||||
|
||||
public ModUpdateAdapter(List<ModUpdateCheckResponseDto> items) {
|
||||
updateInfoList = items;
|
||||
|
@ -56,7 +56,7 @@ public class ModUpdateAdapter extends RecyclerView.Adapter<ModUpdateAdapter.View
|
|||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
public ModUpdateCheckResponseDto updateInfo;
|
||||
private UpdatableModListItemBinding binding;
|
||||
private final UpdatableModListItemBinding binding;
|
||||
|
||||
public void setUpdateInfo(ModUpdateCheckResponseDto updateInfo) {
|
||||
this.updateInfo = updateInfo;
|
||||
|
|
|
@ -12,6 +12,8 @@ import com.zane.smapiinstaller.dto.ModUpdateCheckResponseDto;
|
|||
import com.zane.smapiinstaller.logic.CommonLogic;
|
||||
import com.zane.smapiinstaller.utils.JsonUtil;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
@ -35,7 +37,7 @@ public class ModUpdateFragment extends Fragment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
public View onCreateView(@NotNull LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
binding = FragmentModUpdateListBinding.inflate(inflater, container, false);
|
||||
// Set the adapter
|
||||
|
|
|
@ -24,10 +24,8 @@ import java.io.InputStream;
|
|||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 文件工具类
|
||||
|
|
|
@ -7,9 +7,9 @@ import java.math.BigInteger;
|
|||
*/
|
||||
public class MathUtils {
|
||||
|
||||
private static int INT_MAX_BIT_VALUE = 31;
|
||||
private static final int INT_MAX_BIT_VALUE = 31;
|
||||
|
||||
private static int LONG_MAX_BIT_VALUE = 63;
|
||||
private static final int LONG_MAX_BIT_VALUE = 63;
|
||||
|
||||
/**
|
||||
* Returns the value of the {@code long} argument;
|
||||
|
|
|
@ -56,7 +56,7 @@ public class VersionUtil {
|
|||
* @return 是否为空版本段
|
||||
*/
|
||||
private static boolean isZero(List<String> versionSections) {
|
||||
return !versionSections.stream().anyMatch(version -> {
|
||||
return versionSections.stream().noneMatch(version -> {
|
||||
try {
|
||||
int i = Integer.parseInt(version);
|
||||
if (i == 0) {
|
||||
|
|
|
@ -32,8 +32,10 @@ import lombok.EqualsAndHashCode;
|
|||
*/
|
||||
public class ZipUtils {
|
||||
|
||||
private final static String FILE_HEADER_XALZ = "XALZ";
|
||||
|
||||
public static byte[] decompressXALZ(byte[] bytes) {
|
||||
if ("XALZ".equals(new String(ByteUtils.subArray(bytes, 0, 4), StandardCharsets.ISO_8859_1))) {
|
||||
if (FILE_HEADER_XALZ.equals(new String(ByteUtils.subArray(bytes, 0, 4), StandardCharsets.ISO_8859_1))) {
|
||||
byte[] length = ByteUtils.subArray(bytes, 8, 12);
|
||||
int len = (length[0] & 0xff) | ((length[1] & 0xff) << 8) | ((length[2] & 0xff) << 16) | ((length[3] & 0xff) << 24);
|
||||
bytes = LZ4Factory.fastestJavaInstance().fastDecompressor().decompress(bytes, 12, len);
|
||||
|
|
|
@ -7,27 +7,19 @@ import android.text.Editable;
|
|||
*/
|
||||
public abstract class TextChangedWatcher implements android.text.TextWatcher {
|
||||
/**
|
||||
* Do nothing
|
||||
* @param s origin string
|
||||
* @param start modify position
|
||||
* @param count modify count
|
||||
* @param after modified string
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
|
||||
/**
|
||||
* Text changed event
|
||||
* @param s modified string
|
||||
* @param start modify position
|
||||
* @param count modify count
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public abstract void onTextChanged(CharSequence s, int start, int before, int count);
|
||||
|
||||
/**
|
||||
* Do nothing
|
||||
* @param s target view
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {}
|
||||
|
|
Loading…
Reference in New Issue