code clean up
This commit is contained in:
parent
ca28902c0a
commit
5743e50e04
|
@ -10,8 +10,8 @@ android {
|
|||
applicationId "com.zane.smapiinstaller"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 28
|
||||
versionCode 27
|
||||
versionName "1.3.10"
|
||||
versionCode 28
|
||||
versionName "1.3.11"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
multiDexEnabled true
|
||||
|
|
Binary file not shown.
|
@ -45,6 +45,9 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private AppBarConfiguration mAppBarConfiguration;
|
||||
|
|
|
@ -16,6 +16,9 @@ import androidx.multidex.MultiDex;
|
|||
import lombok.Getter;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
@Getter
|
||||
public class MainApplication extends Application {
|
||||
private DaoSession daoSession;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.zane.smapiinstaller.constant;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class AppConfigKey {
|
||||
public static final String ACTIVE_TRANSLATOR = "ActiveTranslator";
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.zane.smapiinstaller.constant;
|
|||
|
||||
/**
|
||||
* 常量
|
||||
* @author Zane
|
||||
*/
|
||||
public class Constants {
|
||||
/**
|
||||
|
@ -53,4 +54,19 @@ public class Constants {
|
|||
* Google翻译服务
|
||||
*/
|
||||
public static final String TRANSLATE_SERVICE_URL_GOOGLE = "http://translate.google.cn/translate_a/single?client=gtx&dt=t&dj=1&ie=UTF-8&sl=auto&tl=%s&q=%s";
|
||||
|
||||
/**
|
||||
* 文本文件打开大小阈值
|
||||
*/
|
||||
public static int TEXT_FILE_OPEN_SIZE_LIMIT = 16 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* SMAPI版本
|
||||
*/
|
||||
public static final String SMAPI_VERSION = "3.4.1.1";
|
||||
|
||||
/**
|
||||
* 平台
|
||||
*/
|
||||
public static final String PLATFORM = "Android";
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.zane.smapiinstaller.constant;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class DownloadableContentTypes {
|
||||
public static final String LOCALE = "LOCALE";
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.zane.smapiinstaller.constant;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class ManifestPatchConstants {
|
||||
public static final String APP_NAME = "Stardew Valley";
|
||||
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package com.zane.smapiinstaller.entity;
|
||||
package com.zane.smapiinstaller.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
@Data
|
||||
public class GoogleTranslationDto {
|
||||
private List<Entry> sentences;
|
|
@ -1,4 +1,4 @@
|
|||
package com.zane.smapiinstaller.entity;
|
||||
package com.zane.smapiinstaller.dto;
|
||||
|
||||
import org.greenrobot.greendao.annotation.Entity;
|
||||
import org.greenrobot.greendao.annotation.Id;
|
||||
|
@ -6,6 +6,9 @@ import org.greenrobot.greendao.annotation.Index;
|
|||
|
||||
import org.greenrobot.greendao.annotation.Generated;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
@Entity(indexes = {@Index(value = "origin, locale, translator asc", unique = true)})
|
||||
public class TranslationResult {
|
||||
@Id(autoincrement = true) private Long id;
|
|
@ -1,9 +1,12 @@
|
|||
package com.zane.smapiinstaller.entity;
|
||||
package com.zane.smapiinstaller.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
@Data
|
||||
public class YouDaoTranslationDto {
|
||||
private String type;
|
|
@ -7,6 +7,7 @@ import lombok.Data;
|
|||
|
||||
/**
|
||||
* SMAPI所需处理的文件清单
|
||||
* @author Zane
|
||||
*/
|
||||
@Data
|
||||
public class ApkFilesManifest {
|
||||
|
|
|
@ -5,6 +5,9 @@ import org.greenrobot.greendao.annotation.Id;
|
|||
import org.greenrobot.greendao.annotation.Unique;
|
||||
import org.greenrobot.greendao.annotation.Generated;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
@Entity
|
||||
public class AppConfig {
|
||||
@Id(autoincrement = true) private Long id;
|
||||
|
|
|
@ -4,6 +4,7 @@ import lombok.Data;
|
|||
|
||||
/**
|
||||
* 可下载内容包
|
||||
* @author Zane
|
||||
*/
|
||||
@Data
|
||||
public class DownloadableContent {
|
||||
|
|
|
@ -7,6 +7,7 @@ import lombok.EqualsAndHashCode;
|
|||
|
||||
/**
|
||||
* 可下载内容列表
|
||||
* @author Zane
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package com.zane.smapiinstaller.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* SMAPI的配置
|
||||
* @author Zane
|
||||
*/
|
||||
@Data
|
||||
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY, getterVisibility= JsonAutoDetect.Visibility.NONE)
|
||||
|
|
|
@ -7,6 +7,7 @@ import lombok.EqualsAndHashCode;
|
|||
|
||||
/**
|
||||
* 帮助内容列表
|
||||
* @author Zane
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
|
|
|
@ -4,6 +4,7 @@ import lombok.Data;
|
|||
|
||||
/**
|
||||
* 文件映射关系
|
||||
* @author Zane
|
||||
*/
|
||||
@Data
|
||||
public class ManifestEntry {
|
||||
|
|
|
@ -2,12 +2,14 @@ package com.zane.smapiinstaller.entity;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Mod信息
|
||||
* @author Zane
|
||||
*/
|
||||
@Data
|
||||
@JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY, getterVisibility= JsonAutoDetect.Visibility.NONE)
|
||||
|
@ -36,6 +38,10 @@ public class ModManifestEntry {
|
|||
* 依赖
|
||||
*/
|
||||
private Set<ModManifestEntry> Dependencies;
|
||||
/**
|
||||
* MOD更新源
|
||||
*/
|
||||
private List<String> UpdateKeys;
|
||||
/**
|
||||
* 资源包类型
|
||||
*/
|
||||
|
|
|
@ -4,6 +4,7 @@ import lombok.Data;
|
|||
|
||||
/**
|
||||
* 可更新列表
|
||||
* @author Zane
|
||||
*/
|
||||
@Data
|
||||
public class UpdatableList {
|
||||
|
|
|
@ -53,6 +53,9 @@ import androidx.core.content.FileProvider;
|
|||
import java9.util.stream.StreamSupport;
|
||||
import pxb.android.axml.NodeVisitor;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class ApkPatcher {
|
||||
|
||||
private static final String PASSWORD = "android";
|
||||
|
@ -61,13 +64,13 @@ public class ApkPatcher {
|
|||
|
||||
private static final String TAG = "PATCHER";
|
||||
|
||||
private AtomicReference<String> errorMessage = new AtomicReference<>();
|
||||
private final AtomicReference<String> errorMessage = new AtomicReference<>();
|
||||
|
||||
private AtomicInteger switchAction = new AtomicInteger();
|
||||
private final AtomicInteger switchAction = new AtomicInteger();
|
||||
|
||||
private List<Consumer<Integer>> progressListener = new ArrayList<>();
|
||||
private final List<Consumer<Integer>> progressListener = new ArrayList<>();
|
||||
|
||||
private Stopwatch stopwatch = Stopwatch.createUnstarted();
|
||||
private final Stopwatch stopwatch = Stopwatch.createUnstarted();
|
||||
|
||||
public ApkPatcher(Context context) {
|
||||
this.context = context;
|
||||
|
@ -160,9 +163,8 @@ public class ApkPatcher {
|
|||
int baseProgress = 10;
|
||||
stopwatch.reset();
|
||||
stopwatch.start();
|
||||
ZipUtils.addOrReplaceEntries(apkPath, entries, patchedFilename, (progress)->{
|
||||
emitProgress((int) (baseProgress + (progress / 100.0) * 35));
|
||||
});
|
||||
ZipUtils.addOrReplaceEntries(apkPath, entries, patchedFilename,
|
||||
(progress) -> emitProgress((int) (baseProgress + (progress / 100.0) * 35)));
|
||||
stopwatch.stop();
|
||||
emitProgress(45);
|
||||
FileUtils.forceDelete(file);
|
||||
|
@ -275,12 +277,12 @@ public class ApkPatcher {
|
|||
stopwatch.reset();
|
||||
Thread thread = new Thread(() -> {
|
||||
stopwatch.start();
|
||||
while (true){
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(20);
|
||||
long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
|
||||
double progress = elapsed * 0.98 / zipOpElapsed;
|
||||
if(progress < 1.0) {
|
||||
if (progress < 1.0) {
|
||||
emitProgress((int) (49 + 40 * progress));
|
||||
}
|
||||
} catch (InterruptedException ignored) {
|
||||
|
@ -290,7 +292,7 @@ public class ApkPatcher {
|
|||
});
|
||||
thread.start();
|
||||
signer.sign();
|
||||
if(thread.isAlive() && !thread.isInterrupted()) {
|
||||
if (thread.isAlive() && !thread.isInterrupted()) {
|
||||
thread.interrupt();
|
||||
}
|
||||
FileUtils.forceDelete(new File(apkPath));
|
||||
|
|
|
@ -13,7 +13,6 @@ import android.util.Log;
|
|||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
@ -21,7 +20,6 @@ import com.google.common.base.Predicate;
|
|||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.zane.smapiinstaller.MainApplication;
|
||||
import com.zane.smapiinstaller.R;
|
||||
import com.zane.smapiinstaller.entity.ApkFilesManifest;
|
||||
import com.zane.smapiinstaller.entity.ManifestEntry;
|
||||
import com.zane.smapiinstaller.utils.FileUtils;
|
||||
|
@ -44,6 +42,7 @@ import pxb.android.axml.NodeVisitor;
|
|||
|
||||
/**
|
||||
* 通用逻辑
|
||||
* @author Zane
|
||||
*/
|
||||
public class CommonLogic {
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.io.File;
|
|||
|
||||
/**
|
||||
* 配置管理器
|
||||
* @author Zane
|
||||
*/
|
||||
public class ConfigManager {
|
||||
private FrameworkConfig config;
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.zane.smapiinstaller.utils.DialogUtils;
|
|||
|
||||
/**
|
||||
* 游戏启动器
|
||||
* @author Zane
|
||||
*/
|
||||
public class GameLauncher {
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package com.zane.smapiinstaller.logic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import java9.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public interface ListenableObject<T> {
|
||||
/**
|
||||
* 返回一个当前已注册的监听器列表
|
||||
* @return 监听器列表
|
||||
*/
|
||||
List<Predicate<T>> getOnChangedListenerList();
|
||||
/**
|
||||
* 注册数据变化监听器
|
||||
*
|
||||
* @param onChanged 回调
|
||||
*/
|
||||
default void registerOnChangeListener(Predicate<T> onChanged) {
|
||||
getOnChangedListenerList().add(onChanged);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起数据变化事件
|
||||
* @param data 数据
|
||||
*/
|
||||
default void emitDataChangeEvent(T data) {
|
||||
for (Predicate<T> listener : getOnChangedListenerList()) {
|
||||
if(listener.test(data)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,6 @@ import com.google.common.base.Joiner;
|
|||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.Queues;
|
||||
|
@ -31,6 +30,10 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import java9.util.Objects;
|
||||
import java9.util.stream.Collectors;
|
||||
import java9.util.stream.StreamSupport;
|
||||
|
||||
import androidx.core.util.Consumer;
|
||||
|
||||
/**
|
||||
|
@ -48,6 +51,7 @@ public class ModAssetsManager {
|
|||
|
||||
/**
|
||||
* 查找第一个匹配的Mod
|
||||
*
|
||||
* @param filter 过滤规则
|
||||
* @return Mod信息
|
||||
*/
|
||||
|
@ -81,6 +85,7 @@ public class ModAssetsManager {
|
|||
|
||||
/**
|
||||
* 查找全部已识别Mod
|
||||
*
|
||||
* @return Mod信息列表
|
||||
*/
|
||||
public static List<ModManifestEntry> findAllInstalledMods() {
|
||||
|
@ -89,6 +94,7 @@ public class ModAssetsManager {
|
|||
|
||||
/**
|
||||
* 查找全部已识别Mod
|
||||
*
|
||||
* @param ignoreDisabledMod 是否忽略禁用的mod
|
||||
* @return Mod信息列表
|
||||
*/
|
||||
|
@ -101,13 +107,13 @@ public class ModAssetsManager {
|
|||
if (currentFile != null && currentFile.exists()) {
|
||||
boolean foundManifest = false;
|
||||
File[] listFiles = currentFile.listFiles(File::isFile);
|
||||
if(listFiles != null) {
|
||||
if (listFiles != null) {
|
||||
for (File file : listFiles) {
|
||||
if (StringUtils.equalsIgnoreCase(file.getName(), "manifest.json")) {
|
||||
ModManifestEntry manifest = FileUtils.getFileJson(file, ModManifestEntry.class);
|
||||
foundManifest = true;
|
||||
if (manifest != null && StringUtils.isNoneBlank(manifest.getUniqueID())) {
|
||||
if(ignoreDisabledMod && StringUtils.startsWith(file.getParentFile().getName(), ".")) {
|
||||
if (ignoreDisabledMod && StringUtils.startsWith(file.getParentFile().getName(), ".")) {
|
||||
break;
|
||||
}
|
||||
manifest.setAssetPath(file.getParentFile().getAbsolutePath());
|
||||
|
@ -120,7 +126,7 @@ public class ModAssetsManager {
|
|||
}
|
||||
if (!foundManifest) {
|
||||
File[] listDirectories = currentFile.listFiles(File::isDirectory);
|
||||
if(listDirectories != null) {
|
||||
if (listDirectories != null) {
|
||||
files.addAll(Lists.newArrayList(listDirectories));
|
||||
}
|
||||
}
|
||||
|
@ -131,11 +137,13 @@ public class ModAssetsManager {
|
|||
|
||||
/**
|
||||
* 安装默认Mod
|
||||
*
|
||||
* @return 是否安装成功
|
||||
*/
|
||||
public boolean installDefaultMods() {
|
||||
Activity context = CommonLogic.getActivityFromView(root);
|
||||
List<ModManifestEntry> modManifestEntries = FileUtils.getAssetJson(context, "mods_manifest.json", new TypeReference<List<ModManifestEntry>>() { });
|
||||
List<ModManifestEntry> modManifestEntries = FileUtils.getAssetJson(context, "mods_manifest.json", new TypeReference<List<ModManifestEntry>>() {
|
||||
});
|
||||
if (modManifestEntries == null) {
|
||||
return false;
|
||||
}
|
||||
|
@ -172,6 +180,7 @@ public class ModAssetsManager {
|
|||
|
||||
/**
|
||||
* 检查Mod环境
|
||||
*
|
||||
* @param returnCallback 回调函数
|
||||
*/
|
||||
public void checkModEnvironment(Consumer<Boolean> returnCallback) {
|
||||
|
@ -193,6 +202,7 @@ public class ModAssetsManager {
|
|||
|
||||
/**
|
||||
* 检查是否有重复Mod
|
||||
*
|
||||
* @param installedModMap 已安装Mod集合
|
||||
* @param returnCallback 回调函数
|
||||
*/
|
||||
|
@ -205,7 +215,7 @@ public class ModAssetsManager {
|
|||
list.add(Joiner.on(",").join(Lists.transform(installedMods, item -> FileUtils.toPrettyPath(item.getAssetPath()))));
|
||||
}
|
||||
}
|
||||
if (list.size() > 0) {
|
||||
if (!list.isEmpty()) {
|
||||
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,
|
||||
|
@ -216,56 +226,23 @@ public class ModAssetsManager {
|
|||
returnCallback.accept(false);
|
||||
}
|
||||
}));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
returnCallback.accept(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有依赖关系缺失
|
||||
*
|
||||
* @param installedModMap 已安装Mod集合
|
||||
* @param returnCallback 回调函数
|
||||
*/
|
||||
private void checkUnsatisfiedDependencies(ImmutableListMultimap<String, ModManifestEntry> installedModMap, Consumer<Boolean> returnCallback) {
|
||||
Iterable<String> dependencyErrors = Iterables.filter(Iterables.transform(installedModMap.values(), mod -> {
|
||||
if (mod.getDependencies() != null) {
|
||||
ArrayList<ModManifestEntry> unsatisfiedDependencies = Lists.newArrayList(Iterables.filter(mod.getDependencies(), dependency -> {
|
||||
if(dependency.getIsRequired() != null && !dependency.getIsRequired()) {
|
||||
return false;
|
||||
}
|
||||
ImmutableList<ModManifestEntry> entries = installedModMap.get(dependency.getUniqueID());
|
||||
if(entries.size() == 0) {
|
||||
for (String key : installedModMap.keySet()) {
|
||||
if(StringUtils.equalsIgnoreCase(key, dependency.getUniqueID())) {
|
||||
dependency.setUniqueID(key);
|
||||
entries = installedModMap.get(dependency.getUniqueID());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entries.size() != 1) {
|
||||
return true;
|
||||
}
|
||||
String version = entries.get(0).getVersion();
|
||||
if (StringUtils.isBlank(version)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.isBlank(dependency.getMinimumVersion())) {
|
||||
return false;
|
||||
}
|
||||
if (VersionUtil.compareVersion(version, dependency.getMinimumVersion()) < 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
if (unsatisfiedDependencies.size() > 0) {
|
||||
return root.getContext().getString(R.string.error_depends_on_mod, mod.getUniqueID(), Joiner.on(",").join(Lists.transform(unsatisfiedDependencies, ModManifestEntry::getUniqueID)));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}), item -> item != null);
|
||||
if (dependencyErrors.iterator().hasNext()) {
|
||||
List<String> dependencyErrors = StreamSupport.stream(installedModMap.values())
|
||||
.map(mod -> checkModDependencyError(mod, installedModMap))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
if (dependencyErrors.size() > 0) {
|
||||
DialogUtils.showConfirmDialog(root, R.string.error,
|
||||
Joiner.on(";").join(dependencyErrors),
|
||||
R.string.continue_text, R.string.abort,
|
||||
|
@ -276,51 +253,22 @@ public class ModAssetsManager {
|
|||
returnCallback.accept(false);
|
||||
}
|
||||
}));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
returnCallback.accept(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否有资源包依赖Mod没有安装
|
||||
*
|
||||
* @param installedModMap 已安装Mod集合
|
||||
* @param returnCallback 回调函数
|
||||
*/
|
||||
private void checkContentpacks(ImmutableListMultimap<String, ModManifestEntry> installedModMap, Consumer<Boolean> returnCallback) {
|
||||
Iterable<String> dependencyErrors = Iterables.filter(Iterables.transform(installedModMap.values(), mod -> {
|
||||
ModManifestEntry dependency = mod.getContentPackFor();
|
||||
if (dependency != null) {
|
||||
if(dependency.getIsRequired() != null && !dependency.getIsRequired()) {
|
||||
return null;
|
||||
}
|
||||
ImmutableList<ModManifestEntry> entries = installedModMap.get(dependency.getUniqueID());
|
||||
if(entries.size() == 0) {
|
||||
for (String key : installedModMap.keySet()) {
|
||||
if(StringUtils.equalsIgnoreCase(key, dependency.getUniqueID())) {
|
||||
dependency.setUniqueID(key);
|
||||
entries = installedModMap.get(dependency.getUniqueID());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entries.size() != 1) {
|
||||
return root.getContext().getString(R.string.error_depends_on_mod, mod.getUniqueID(), dependency.getUniqueID());
|
||||
}
|
||||
String version = entries.get(0).getVersion();
|
||||
if (!StringUtils.isBlank(version)) {
|
||||
if (StringUtils.isBlank(dependency.getMinimumVersion())) {
|
||||
return null;
|
||||
}
|
||||
if (VersionUtil.compareVersion(version, dependency.getMinimumVersion()) < 0) {
|
||||
return root.getContext().getString(R.string.error_depends_on_mod_version, mod.getUniqueID(), dependency.getUniqueID(), dependency.getMinimumVersion());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}), item -> item != null);
|
||||
if (dependencyErrors.iterator().hasNext()) {
|
||||
List<String> dependencyErrors = StreamSupport.stream(installedModMap.values())
|
||||
.map(mod -> checkContentPackDependencyError(mod, installedModMap))
|
||||
.filter(Objects::nonNull).collect(Collectors.toList());
|
||||
if (!dependencyErrors.isEmpty()) {
|
||||
DialogUtils.showConfirmDialog(root, R.string.error,
|
||||
Joiner.on(";").join(dependencyErrors),
|
||||
R.string.continue_text, R.string.abort,
|
||||
|
@ -331,9 +279,83 @@ public class ModAssetsManager {
|
|||
returnCallback.accept(false);
|
||||
}
|
||||
}));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
returnCallback.accept(true);
|
||||
}
|
||||
}
|
||||
|
||||
private String checkModDependencyError(ModManifestEntry mod, ImmutableListMultimap<String, ModManifestEntry> installedModMap) {
|
||||
if (mod.getDependencies() != null) {
|
||||
List<ModManifestEntry> unsatisfiedDependencies = StreamSupport.stream(mod.getDependencies())
|
||||
.filter(dependency -> isDependencyIsExist(dependency, installedModMap))
|
||||
.collect(Collectors.toList());
|
||||
if (unsatisfiedDependencies.size() > 0) {
|
||||
return root.getContext().getString(R.string.error_depends_on_mod, mod.getUniqueID(), Joiner.on(",").join(Lists.transform(unsatisfiedDependencies, ModManifestEntry::getUniqueID)));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isDependencyIsExist(ModManifestEntry dependency, ImmutableListMultimap<String, ModManifestEntry> installedModMap) {
|
||||
if (dependency.getIsRequired() != null && !dependency.getIsRequired()) {
|
||||
return false;
|
||||
}
|
||||
ImmutableList<ModManifestEntry> entries = installedModMap.get(dependency.getUniqueID());
|
||||
if (entries.size() == 0) {
|
||||
for (String key : installedModMap.keySet()) {
|
||||
if (StringUtils.equalsIgnoreCase(key, dependency.getUniqueID())) {
|
||||
dependency.setUniqueID(key);
|
||||
entries = installedModMap.get(dependency.getUniqueID());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entries.size() != 1) {
|
||||
return true;
|
||||
}
|
||||
String version = entries.get(0).getVersion();
|
||||
if (StringUtils.isBlank(version)) {
|
||||
return true;
|
||||
}
|
||||
if (StringUtils.isBlank(dependency.getMinimumVersion())) {
|
||||
return false;
|
||||
}
|
||||
if (VersionUtil.compareVersion(version, dependency.getMinimumVersion()) < 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String checkContentPackDependencyError(ModManifestEntry mod, ImmutableListMultimap<String, ModManifestEntry> installedModMap) {
|
||||
ModManifestEntry dependency = mod.getContentPackFor();
|
||||
if (dependency != null) {
|
||||
if (dependency.getIsRequired() != null && !dependency.getIsRequired()) {
|
||||
return null;
|
||||
}
|
||||
ImmutableList<ModManifestEntry> entries = installedModMap.get(dependency.getUniqueID());
|
||||
if (entries.size() == 0) {
|
||||
for (String key : installedModMap.keySet()) {
|
||||
if (StringUtils.equalsIgnoreCase(key, dependency.getUniqueID())) {
|
||||
dependency.setUniqueID(key);
|
||||
entries = installedModMap.get(dependency.getUniqueID());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entries.size() != 1) {
|
||||
return root.getContext().getString(R.string.error_depends_on_mod, mod.getUniqueID(), dependency.getUniqueID());
|
||||
}
|
||||
String version = entries.get(0).getVersion();
|
||||
if (!StringUtils.isBlank(version)) {
|
||||
if (StringUtils.isBlank(dependency.getMinimumVersion())) {
|
||||
return null;
|
||||
}
|
||||
if (VersionUtil.compareVersion(version, dependency.getMinimumVersion()) < 0) {
|
||||
return root.getContext().getString(R.string.error_depends_on_mod_version, mod.getUniqueID(), dependency.getUniqueID(), dependency.getMinimumVersion());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,6 @@ package com.zane.smapiinstaller.logic;
|
|||
|
||||
import android.view.View;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ClassToInstanceMap;
|
||||
import com.google.common.collect.MutableClassToInstanceMap;
|
||||
import com.hjq.language.LanguagesManager;
|
||||
import com.lzy.okgo.OkGo;
|
||||
import com.lzy.okgo.callback.StringCallback;
|
||||
|
@ -19,16 +16,19 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import java9.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* 在线列表更新管理器
|
||||
* @author Zane
|
||||
* @param <T> 列表类型
|
||||
*/
|
||||
public class UpdatableListManager<T extends UpdatableList> {
|
||||
private static ConcurrentHashMap<Class<?>, Boolean> updateChecked = new ConcurrentHashMap<>();
|
||||
public class UpdatableListManager<T extends UpdatableList> implements ListenableObject<T> {
|
||||
private static final ConcurrentHashMap<Class<?>, Boolean> updateChecked = new ConcurrentHashMap<>();
|
||||
|
||||
private static UpdatableList updatableList = null;
|
||||
|
||||
private List<Predicate<T>> onChangedListener = new ArrayList<>();
|
||||
private final List<Predicate<T>> onChangedListener = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @param root context容器
|
||||
|
@ -64,9 +64,7 @@ public class UpdatableListManager<T extends UpdatableList> {
|
|||
if(content != null && updatableList.getVersion() < content.getVersion()) {
|
||||
FileUtils.writeAssetJson(root.getContext(), finalFilename, content);
|
||||
updatableList = content;
|
||||
for (Predicate<T> listener : onChangedListener) {
|
||||
listener.apply(getList());
|
||||
}
|
||||
emitDataChangeEvent(getList());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -79,11 +77,8 @@ public class UpdatableListManager<T extends UpdatableList> {
|
|||
return (T) updatableList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册列表变化监听器
|
||||
* @param onChanged 回调
|
||||
*/
|
||||
public void registerListChangeListener(Predicate<T> onChanged) {
|
||||
this.onChangedListener.add(onChanged);
|
||||
@Override
|
||||
public List<Predicate<T>> getOnChangedListenerList() {
|
||||
return onChangedListener;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,6 @@ import android.os.Bundle;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
@ -27,7 +24,11 @@ import androidx.fragment.app.Fragment;
|
|||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import java9.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class AboutFragment extends Fragment {
|
||||
|
||||
@BindView(R.id.img_heart)
|
||||
|
@ -40,22 +41,23 @@ public class AboutFragment extends Fragment {
|
|||
ButterKnife.bind(this, root);
|
||||
return root;
|
||||
}
|
||||
@OnClick(R.id.button_release) void release() {
|
||||
|
||||
@OnClick(R.id.button_release)
|
||||
void release() {
|
||||
CommonLogic.openUrl(this.getContext(), "https://github.com/ZaneYork/SMAPI-Android-Installer/releases");
|
||||
}
|
||||
@OnClick(R.id.button_gplay) void gplay() {
|
||||
try
|
||||
{
|
||||
|
||||
@OnClick(R.id.button_gplay)
|
||||
void gplay() {
|
||||
try {
|
||||
this.openPlayStore("market://details?id=" + this.getActivity().getPackageName());
|
||||
}
|
||||
catch (ActivityNotFoundException ex)
|
||||
{
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
CommonLogic.openUrl(this.getContext(), "https://play.google.com/store/apps/details?id=" + this.getActivity().getPackageName());
|
||||
}
|
||||
|
||||
}
|
||||
private void openPlayStore(String url)
|
||||
{
|
||||
|
||||
private void openPlayStore(String url) {
|
||||
Intent intent = new Intent("android.intent.action.VIEW");
|
||||
intent.setData(Uri.parse(url));
|
||||
intent.setPackage("com.android.vending");
|
||||
|
@ -63,55 +65,61 @@ public class AboutFragment extends Fragment {
|
|||
this.getActivity().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, R.id.button_qq_group_2})
|
||||
void joinQQ(Button which) {
|
||||
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) {
|
||||
if (which.getId() == R.id.button_qq_group_1) {
|
||||
CommonLogic.openUrl(this.getContext(), baseUrl + "AAflCLHiWw1haM1obu_f-CpGsETxXc6b");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
CommonLogic.openUrl(this.getContext(), baseUrl + "kshK7BavcS2jXZ6exDvezc18ksLB8YsM");
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.button_donation) void donation(View view) {
|
||||
@OnClick(R.id.button_donation)
|
||||
void donation() {
|
||||
Context context = this.getContext();
|
||||
DialogUtils.setCurrentDialog(new MaterialDialog.Builder(context).title(R.string.button_donation_text).items(R.array.donation_methods).itemsCallback((dialog, itemView, position, text) -> {
|
||||
CommonLogic.showAnimation(imgHeart, R.anim.heart_beat, (animation)->{
|
||||
switch (position){
|
||||
case 0:
|
||||
boolean hasInstalledAlipayClient = AlipayDonate.hasInstalledAlipayClient(context);
|
||||
if (hasInstalledAlipayClient) {
|
||||
AlipayDonate.startAlipayClient(this.getActivity(), "fkx13570v1pp2xenyrx4y3f");
|
||||
}
|
||||
else {
|
||||
CommonLogic.openUrl(context, "http://dl.zaneyork.cn/alipay.png");
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
CommonLogic.openUrl(context, "http://dl.zaneyork.cn/wechat.png");
|
||||
break;
|
||||
case 2:
|
||||
CommonLogic.openUrl(context, "http://dl.zaneyork.cn/qqpay.png");
|
||||
break;
|
||||
case 3:
|
||||
hasInstalledAlipayClient = AlipayDonate.hasInstalledAlipayClient(context);
|
||||
if (hasInstalledAlipayClient) {
|
||||
if (CommonLogic.copyToClipboard(context, Constants.RED_PACKET_CODE)) {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
Intent intent = packageManager.getLaunchIntentForPackage("com.eg.android.AlipayGphone");
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
Toast.makeText(context, R.string.toast_redpacket_message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
CommonLogic.openUrl(context, "http://zaneyork.cn/download/list.html");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
DialogUtils.setCurrentDialog(new MaterialDialog.Builder(context)
|
||||
.title(R.string.button_donation_text)
|
||||
.items(R.array.donation_methods)
|
||||
.itemsCallback((dialog, itemView, position, text) ->
|
||||
CommonLogic.showAnimation(imgHeart, R.anim.heart_beat, (animation) -> {
|
||||
listSelectLogic(context, position);
|
||||
})).show());
|
||||
}
|
||||
|
||||
private void listSelectLogic(Context context, int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
boolean hasInstalledAlipayClient = AlipayDonate.hasInstalledAlipayClient(context);
|
||||
if (hasInstalledAlipayClient) {
|
||||
AlipayDonate.startAlipayClient(this.getActivity(), "fkx13570v1pp2xenyrx4y3f");
|
||||
} else {
|
||||
CommonLogic.openUrl(context, "http://dl.zaneyork.cn/alipay.png");
|
||||
}
|
||||
});
|
||||
}).show());
|
||||
break;
|
||||
case 1:
|
||||
CommonLogic.openUrl(context, "http://dl.zaneyork.cn/wechat.png");
|
||||
break;
|
||||
case 2:
|
||||
CommonLogic.openUrl(context, "http://dl.zaneyork.cn/qqpay.png");
|
||||
break;
|
||||
case 3:
|
||||
hasInstalledAlipayClient = AlipayDonate.hasInstalledAlipayClient(context);
|
||||
if (hasInstalledAlipayClient) {
|
||||
if (CommonLogic.copyToClipboard(context, Constants.RED_PACKET_CODE)) {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
Intent intent = packageManager.getLaunchIntentForPackage("com.eg.android.AlipayGphone");
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
Toast.makeText(context, R.string.toast_redpacket_message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
CommonLogic.openUrl(context, "http://zaneyork.cn/download/list.html");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,13 +13,13 @@ import android.widget.EditText;
|
|||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.zane.smapiinstaller.BuildConfig;
|
||||
import com.zane.smapiinstaller.R;
|
||||
import com.zane.smapiinstaller.constant.Constants;
|
||||
import com.zane.smapiinstaller.utils.DialogUtils;
|
||||
import com.zane.smapiinstaller.utils.FileUtils;
|
||||
import com.zane.smapiinstaller.utils.JSONUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -30,6 +30,9 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class ConfigEditFragment extends Fragment {
|
||||
@BindView(R.id.edit_text_config_edit)
|
||||
EditText editText;
|
||||
|
@ -54,7 +57,7 @@ public class ConfigEditFragment extends Fragment {
|
|||
configPath = this.getArguments().getString("configPath");
|
||||
if(configPath != null) {
|
||||
File file = new File(configPath);
|
||||
if(file.exists() && file.length() < 16 * 1024 * 1024) {
|
||||
if(file.exists() && file.length() < Constants.TEXT_FILE_OPEN_SIZE_LIMIT) {
|
||||
String fileText = FileUtils.getFileText(file);
|
||||
if (fileText != null) {
|
||||
editText.setText(fileText);
|
||||
|
|
|
@ -16,12 +16,14 @@ import butterknife.OnClick;
|
|||
import butterknife.OnTextChanged;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.zane.smapiinstaller.R;
|
||||
import com.zane.smapiinstaller.utils.DialogUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class ConfigFragment extends Fragment {
|
||||
|
||||
@BindView(R.id.view_mod_list)
|
||||
|
@ -37,9 +39,9 @@ public class ConfigFragment extends Fragment {
|
|||
configViewModel = new ConfigViewModel(root);
|
||||
ModManifestAdapter modManifestAdapter = new ModManifestAdapter(configViewModel, new ArrayList<>(configViewModel.getModList()));
|
||||
recyclerView.setAdapter(modManifestAdapter);
|
||||
configViewModel.registerListChangeListener((list) -> {
|
||||
configViewModel.registerOnChangeListener((list) -> {
|
||||
modManifestAdapter.setList(new ArrayList<>(list));
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL));
|
||||
return root;
|
||||
|
|
|
@ -2,12 +2,8 @@ package com.zane.smapiinstaller.ui.config;
|
|||
|
||||
import android.view.View;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.hjq.language.LanguagesManager;
|
||||
import com.zane.smapiinstaller.MainApplication;
|
||||
import com.zane.smapiinstaller.constant.AppConfigKey;
|
||||
|
@ -15,9 +11,10 @@ import com.zane.smapiinstaller.entity.AppConfig;
|
|||
import com.zane.smapiinstaller.entity.AppConfigDao;
|
||||
import com.zane.smapiinstaller.entity.DaoSession;
|
||||
import com.zane.smapiinstaller.entity.ModManifestEntry;
|
||||
import com.zane.smapiinstaller.entity.TranslationResult;
|
||||
import com.zane.smapiinstaller.dto.TranslationResult;
|
||||
import com.zane.smapiinstaller.entity.TranslationResultDao;
|
||||
import com.zane.smapiinstaller.logic.CommonLogic;
|
||||
import com.zane.smapiinstaller.logic.ListenableObject;
|
||||
import com.zane.smapiinstaller.logic.ModAssetsManager;
|
||||
import com.zane.smapiinstaller.utils.TranslateUtil;
|
||||
|
||||
|
@ -30,20 +27,24 @@ import java.util.List;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import java9.util.Objects;
|
||||
import java9.util.function.Predicate;
|
||||
import java9.util.stream.Collectors;
|
||||
import java9.util.stream.StreamSupport;
|
||||
|
||||
class ConfigViewModel extends ViewModel {
|
||||
class ConfigViewModel extends ViewModel implements ListenableObject<List<ModManifestEntry>> {
|
||||
|
||||
@NonNull
|
||||
private List<ModManifestEntry> modList;
|
||||
private final List<ModManifestEntry> modList;
|
||||
private List<ModManifestEntry> filteredModList;
|
||||
|
||||
private String sortBy = "Name asc";
|
||||
public String getSortBy() {
|
||||
return sortBy;
|
||||
}
|
||||
private View root;
|
||||
private final View root;
|
||||
|
||||
private List<Predicate<List<ModManifestEntry>>> onChangedListener = new ArrayList<>();
|
||||
private final List<Predicate<List<ModManifestEntry>>> onChangedListener = new ArrayList<>();
|
||||
|
||||
ConfigViewModel(View root) {
|
||||
this.root = root;
|
||||
|
@ -102,13 +103,11 @@ class ConfigViewModel extends ViewModel {
|
|||
default:
|
||||
return;
|
||||
}
|
||||
for (Predicate<List<ModManifestEntry>> listener : onChangedListener) {
|
||||
if(filteredModList != null){
|
||||
listener.apply(filteredModList);
|
||||
}
|
||||
else {
|
||||
listener.apply(modList);
|
||||
}
|
||||
if(filteredModList != null) {
|
||||
emitDataChangeEvent(filteredModList);
|
||||
}
|
||||
else {
|
||||
emitDataChangeEvent(modList);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,7 +118,7 @@ class ConfigViewModel extends ViewModel {
|
|||
AppConfig activeTranslator = daoSession.getAppConfigDao().queryBuilder().where(AppConfigDao.Properties.Name.eq(AppConfigKey.ACTIVE_TRANSLATOR)).build().unique();
|
||||
if (activeTranslator != null) {
|
||||
String translator = activeTranslator.getValue();
|
||||
ArrayList<String> descriptions = Lists.newArrayList(Iterables.filter(Iterables.transform(this.modList, ModManifestEntry::getDescription), item -> item != null));
|
||||
List<String> descriptions = StreamSupport.stream(this.modList).map(ModManifestEntry::getDescription).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
String language = LanguagesManager.getAppLanguage(app).getLanguage();
|
||||
Query<TranslationResult> query = daoSession.getTranslationResultDao().queryBuilder().where(
|
||||
TranslationResultDao.Properties.Origin.in(descriptions),
|
||||
|
@ -128,16 +127,15 @@ class ConfigViewModel extends ViewModel {
|
|||
).build();
|
||||
List<TranslationResult> translationResults = query.list();
|
||||
ImmutableMap<String, TranslationResult> translateMap = Maps.uniqueIndex(translationResults, TranslationResult::getOrigin);
|
||||
List<String> untranslatedText = Lists.newArrayList(Sets.newHashSet(Iterables.filter(Iterables.transform(modList, mod -> {
|
||||
assert mod != null;
|
||||
List<String> untranslatedText = StreamSupport.stream(modList).map(mod -> {
|
||||
if (translateMap.containsKey(mod.getDescription())) {
|
||||
mod.setTranslatedDescription(translateMap.get(mod.getDescription()).getTranslation());
|
||||
return null;
|
||||
} else {
|
||||
return mod.getDescription();
|
||||
}
|
||||
}), item -> item != null)));
|
||||
if (untranslatedText.size() > 0) {
|
||||
}).filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
||||
if (!untranslatedText.isEmpty()) {
|
||||
TranslateUtil.translateText(untranslatedText, translator, language, (results) -> {
|
||||
daoSession.getTranslationResultDao().insertOrReplaceInTx(results);
|
||||
ImmutableMap<String, TranslationResult> map = Maps.uniqueIndex(results, TranslationResult::getOrigin);
|
||||
|
@ -146,9 +144,7 @@ class ConfigViewModel extends ViewModel {
|
|||
mod.setTranslatedDescription(map.get(mod.getDescription()).getTranslation());
|
||||
}
|
||||
}
|
||||
for (Predicate<List<ModManifestEntry>> listener : onChangedListener) {
|
||||
listener.apply(modList);
|
||||
}
|
||||
emitDataChangeEvent(modList);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
@ -163,26 +159,17 @@ class ConfigViewModel extends ViewModel {
|
|||
|
||||
public void removeAll(Predicate<ModManifestEntry> predicate) {
|
||||
for (int i = modList.size() - 1; i >= 0; i--) {
|
||||
if (predicate.apply(modList.get(i))) {
|
||||
if (predicate.test(modList.get(i))) {
|
||||
modList.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册列表变化监听器
|
||||
*
|
||||
* @param onChanged 回调
|
||||
*/
|
||||
public void registerListChangeListener(Predicate<List<ModManifestEntry>> onChanged) {
|
||||
this.onChangedListener.add(onChanged);
|
||||
}
|
||||
|
||||
public void filter(CharSequence text) {
|
||||
if (StringUtils.isBlank(text)) {
|
||||
filteredModList = modList;
|
||||
} else {
|
||||
filteredModList = Lists.newArrayList(Iterables.filter(modList, mod -> {
|
||||
filteredModList = StreamSupport.stream(modList).filter(mod -> {
|
||||
if (StringUtils.containsIgnoreCase(mod.getName(), text)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -191,10 +178,13 @@ class ConfigViewModel extends ViewModel {
|
|||
} else {
|
||||
return StringUtils.containsIgnoreCase(mod.getDescription(), text);
|
||||
}
|
||||
}));
|
||||
}
|
||||
for (Predicate<List<ModManifestEntry>> listener : onChangedListener) {
|
||||
listener.apply(filteredModList);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
emitDataChangeEvent(filteredModList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Predicate<List<ModManifestEntry>>> getOnChangedListenerList() {
|
||||
return onChangedListener;
|
||||
}
|
||||
}
|
|
@ -30,6 +30,9 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class ModManifestAdapter extends RecyclerView.Adapter<ModManifestAdapter.ViewHolder> {
|
||||
private ConfigViewModel model;
|
||||
private List<ModManifestEntry> modList;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.zane.smapiinstaller.ui.download;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
@ -18,8 +19,8 @@ import com.lzy.okgo.OkGo;
|
|||
import com.lzy.okgo.callback.FileCallback;
|
||||
import com.lzy.okgo.model.Progress;
|
||||
import com.lzy.okgo.model.Response;
|
||||
import com.microsoft.appcenter.crashes.Crashes;
|
||||
import com.zane.smapiinstaller.R;
|
||||
import com.zane.smapiinstaller.constant.Constants;
|
||||
import com.zane.smapiinstaller.constant.DownloadableContentTypes;
|
||||
import com.zane.smapiinstaller.entity.DownloadableContent;
|
||||
import com.zane.smapiinstaller.entity.ModManifestEntry;
|
||||
|
@ -38,6 +39,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
|
||||
/**
|
||||
* {@link RecyclerView.Adapter} that can display a {@link DownloadableContent}
|
||||
* @author Zane
|
||||
*/
|
||||
public class DownloadableContentAdapter extends RecyclerView.Adapter<DownloadableContentAdapter.ViewHolder> {
|
||||
|
||||
|
@ -52,6 +54,7 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter<Downloadabl
|
|||
downloadableContentList = items;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
|
@ -80,7 +83,7 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter<Downloadabl
|
|||
Button buttonRemove;
|
||||
@BindView(R.id.button_download_content)
|
||||
Button buttonDownload;
|
||||
private AtomicBoolean downloading = new AtomicBoolean(false);
|
||||
private final AtomicBoolean downloading = new AtomicBoolean(false);
|
||||
|
||||
public DownloadableContent downloadableContent;
|
||||
|
||||
|
@ -137,8 +140,13 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter<Downloadabl
|
|||
}
|
||||
File file = new File(context.getCacheDir(), downloadableContent.getName() + ".zip");
|
||||
if (file.exists()) {
|
||||
if (!StringUtils.equalsIgnoreCase(com.zane.smapiinstaller.utils.FileUtils.getFileHash(file), downloadableContent.getHash())) {
|
||||
file.delete();
|
||||
if (!StringUtils.equalsIgnoreCase(FileUtils.getFileHash(file), downloadableContent.getHash())) {
|
||||
try {
|
||||
FileUtils.forceDelete(file);
|
||||
} catch (IOException e) {
|
||||
Crashes.trackError(e);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
unpackLogic(context, file, modManifestEntry);
|
||||
return;
|
||||
|
|
|
@ -18,6 +18,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
* @author Zane
|
||||
*/
|
||||
public class DownloadableContentFragment extends Fragment {
|
||||
|
||||
|
@ -41,7 +42,7 @@ public class DownloadableContentFragment extends Fragment {
|
|||
UpdatableListManager<DownloadableContentList> manager = new UpdatableListManager<>(view, "downloadable_content_list.json", DownloadableContentList.class, Constants.DLC_LIST_UPDATE_URL);
|
||||
DownloadableContentAdapter adapter = new DownloadableContentAdapter(manager.getList().getContents());
|
||||
recyclerView.setAdapter(adapter);
|
||||
manager.registerListChangeListener((list) -> {
|
||||
manager.registerOnChangeListener((list) -> {
|
||||
adapter.setDownloadableContentList(list.getContents());
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -25,6 +25,9 @@ import butterknife.BindView;
|
|||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class HelpFragment extends Fragment {
|
||||
|
||||
@BindView(R.id.view_help_list)
|
||||
|
@ -39,9 +42,9 @@ public class HelpFragment extends Fragment {
|
|||
UpdatableListManager<HelpItemList> manager = new UpdatableListManager<>(root, "help_item_list.json", HelpItemList.class, Constants.HELP_LIST_UPDATE_URL);
|
||||
HelpItemAdapter adapter = new HelpItemAdapter(manager.getList().getItems());
|
||||
recyclerView.setAdapter(adapter);
|
||||
manager.registerListChangeListener((list) -> {
|
||||
manager.registerOnChangeListener((list) -> {
|
||||
adapter.setHelpItems(list.getItems());
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL));
|
||||
return root;
|
||||
|
|
|
@ -17,6 +17,9 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class HelpItemAdapter extends RecyclerView.Adapter<HelpItemAdapter.ViewHolder> {
|
||||
|
||||
public void setHelpItems(List<HelpItem> helpItems) {
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
package com.zane.smapiinstaller.ui.help;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
class HelpViewModel extends ViewModel {
|
||||
|
||||
private MutableLiveData<String> mText;
|
||||
|
||||
public HelpViewModel() {
|
||||
mText = new MutableLiveData<>();
|
||||
mText.setValue("This is help fragment");
|
||||
}
|
||||
|
||||
public LiveData<String> getText() {
|
||||
return mText;
|
||||
}
|
||||
}
|
|
@ -19,16 +19,16 @@ import com.zane.smapiinstaller.utils.DialogUtils;
|
|||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.OnClick;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class InstallFragment extends Fragment {
|
||||
|
||||
private Context context;
|
||||
|
@ -77,9 +77,7 @@ public class InstallFragment extends Fragment {
|
|||
task = new Thread(() -> {
|
||||
try {
|
||||
ApkPatcher patcher = new ApkPatcher(context);
|
||||
patcher.registerProgressListener((progress)->{
|
||||
DialogUtils.setProgressDialogState(root, dialog, null, progress);
|
||||
});
|
||||
patcher.registerProgressListener((progress)-> DialogUtils.setProgressDialogState(root, dialog, null, progress));
|
||||
DialogUtils.setProgressDialogState(root, dialog, R.string.extracting_package, null);
|
||||
String path = patcher.extract();
|
||||
if (path == null) {
|
||||
|
|
|
@ -4,10 +4,12 @@ import android.content.Context;
|
|||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import com.zane.smapiinstaller.entity.DaoMaster;
|
||||
import com.zane.smapiinstaller.entity.TranslationResultDao;
|
||||
|
||||
import org.greenrobot.greendao.database.Database;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class DbOpenHelper extends DaoMaster.OpenHelper {
|
||||
public DbOpenHelper(Context context, String name) {
|
||||
super(context, name);
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
|
||||
/**
|
||||
* 对话框相关工具类
|
||||
* @author Zane
|
||||
*/
|
||||
public class DialogUtils {
|
||||
private static Dialog currentDialog = null;
|
||||
|
|
|
@ -9,7 +9,6 @@ import com.google.common.hash.Hashing;
|
|||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.hjq.language.LanguagesManager;
|
||||
import com.zane.smapiinstaller.MainApplication;
|
||||
|
||||
import org.apache.commons.io.input.BOMInputStream;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -21,12 +20,11 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* 文件工具类
|
||||
* @author Zane
|
||||
*/
|
||||
public class FileUtils extends org.zeroturnaround.zip.commons.FileUtils {
|
||||
/**
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.lzy.okgo.model.HttpHeaders;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Request;
|
||||
|
@ -13,6 +14,9 @@ import okio.BufferedSink;
|
|||
import okio.GzipSink;
|
||||
import okio.Okio;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class GzipRequestInterceptor implements Interceptor {
|
||||
@Override
|
||||
public Response intercept(Chain chain) throws IOException {
|
||||
|
@ -41,7 +45,7 @@ public class GzipRequestInterceptor implements Interceptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(BufferedSink sink) throws IOException {
|
||||
public void writeTo(@NonNull BufferedSink sink) throws IOException {
|
||||
BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
|
||||
body.writeTo(gzipSink);
|
||||
gzipSink.close();
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
|
||||
/**
|
||||
* JSON工具类
|
||||
* @author Zane
|
||||
*/
|
||||
public class JSONUtil {
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
package com.zane.smapiinstaller.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class MathUtils {
|
||||
|
||||
private static int INT_MAX_BIT_VALUE = 31;
|
||||
|
||||
private static int LONG_MAX_BIT_VALUE = 63;
|
||||
|
||||
/**
|
||||
* Returns the value of the {@code long} argument;
|
||||
* throwing an exception if the value overflows an {@code int}.
|
||||
|
@ -34,7 +40,7 @@ public class MathUtils {
|
|||
* @since 1.8
|
||||
*/
|
||||
public static int intValueExact(BigInteger value) {
|
||||
if (value.bitLength() <= 31) {
|
||||
if (value.bitLength() <= INT_MAX_BIT_VALUE) {
|
||||
return value.intValue();
|
||||
} else {
|
||||
throw new ArithmeticException("BigInteger out of int range");
|
||||
|
@ -54,7 +60,7 @@ public class MathUtils {
|
|||
* @since 1.8
|
||||
*/
|
||||
public static long longValueExact(BigInteger value) {
|
||||
if (value.bitLength() <= 63) {
|
||||
if (value.bitLength() <= LONG_MAX_BIT_VALUE) {
|
||||
return value.longValue();
|
||||
} else {
|
||||
throw new ArithmeticException("BigInteger out of long range");
|
||||
|
|
|
@ -5,6 +5,9 @@ import android.os.Build;
|
|||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class ReflectionUtils {
|
||||
public static <T extends Annotation> T getDeclaredAnnotation(Field targetField, Class<T> targetAnnotation) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
|
|
|
@ -3,17 +3,14 @@ package com.zane.smapiinstaller.utils;
|
|||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.lzy.okgo.OkGo;
|
||||
import com.lzy.okgo.callback.StringCallback;
|
||||
import com.lzy.okgo.model.Response;
|
||||
import com.zane.smapiinstaller.constant.Constants;
|
||||
import com.zane.smapiinstaller.entity.GoogleTranslationDto;
|
||||
import com.zane.smapiinstaller.entity.TranslationResult;
|
||||
import com.zane.smapiinstaller.entity.YouDaoTranslationDto;
|
||||
import com.zane.smapiinstaller.dto.GoogleTranslationDto;
|
||||
import com.zane.smapiinstaller.dto.TranslationResult;
|
||||
import com.zane.smapiinstaller.dto.YouDaoTranslationDto;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
@ -21,6 +18,12 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import java9.util.stream.Collectors;
|
||||
import java9.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class TranslateUtil {
|
||||
|
||||
public static final String GOOGLE = "Google";
|
||||
|
@ -30,8 +33,8 @@ public class TranslateUtil {
|
|||
if(textList == null || textList.size() == 0) {
|
||||
return;
|
||||
}
|
||||
textList = Lists.newArrayList(Iterables.filter(textList, item -> StringUtils.isNoneBlank(item) && !item.contains("\n")));
|
||||
if(textList.size() == 0) {
|
||||
textList = StreamSupport.stream(textList).filter(item -> StringUtils.isNoneBlank(item) && !item.contains("\n")).collect(Collectors.toList());
|
||||
if(textList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String queryText = Joiner.on("%0A").join(textList);
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
package com.zane.smapiinstaller.utils;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import java9.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* 版本比较工具
|
||||
* @author Zane
|
||||
*/
|
||||
public class VersionUtil {
|
||||
/**
|
||||
|
@ -56,7 +58,7 @@ public class VersionUtil {
|
|||
* @return 是否为空版本段
|
||||
*/
|
||||
private static boolean isZero(List<String> versionSections) {
|
||||
return !Iterables.filter(versionSections, version -> {
|
||||
return !StreamSupport.stream(versionSections).filter(version -> {
|
||||
try {
|
||||
int i = Integer.parseInt(version);
|
||||
if (i == 0) {
|
||||
|
@ -65,7 +67,7 @@ public class VersionUtil {
|
|||
} catch (Exception ignored) {
|
||||
}
|
||||
return true;
|
||||
}).iterator().hasNext();
|
||||
}).findAny().isPresent();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,6 +18,9 @@ import java9.util.function.Consumer;
|
|||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Zane
|
||||
*/
|
||||
public class ZipUtils {
|
||||
|
||||
public static void addOrReplaceEntries(String inputZipFilename, List<ZipEntrySource> entrySources, String outputZipFilename, Consumer<Integer> progressCallback) throws IOException {
|
||||
|
|
Loading…
Reference in New Issue