1.Mod update check(in progress)

2.Upgrade material dialog dependency to latest version
3.Virtual keyboard update(auto hidden feature)
This commit is contained in:
ZaneYork 2020-03-31 11:22:24 +08:00
parent e69565d5e3
commit f15d305661
29 changed files with 524 additions and 227 deletions

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="AlibabaAvoidManuallyCreateThread" enabled="false" level="CRITICAL" enabled_by_default="false" />
</profile>
</component>

View File

@ -1,6 +1,8 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: "androidx.navigation.safeargs"
apply plugin: 'org.greenrobot.greendao' apply plugin: 'org.greenrobot.greendao'
apply plugin: 'androidx.navigation.safeargs'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android { android {
compileSdkVersion 28 compileSdkVersion 28
@ -57,14 +59,18 @@ dependencies {
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.google.android.material:material:1.1.0' implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.navigation:navigation-fragment:2.3.0-alpha04' def nav_version = "2.3.0-alpha04"
implementation 'androidx.navigation:navigation-ui:2.3.0-alpha04' implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'com.madgag.spongycastle:core:1.54.0.0' implementation 'com.madgag.spongycastle:core:1.54.0.0'
implementation 'com.madgag.spongycastle:prov:1.54.0.0' implementation 'com.madgag.spongycastle:prov:1.54.0.0'
implementation 'com.madgag.spongycastle:pkix:1.54.0.0' implementation 'com.madgag.spongycastle:pkix:1.54.0.0'
implementation 'com.madgag.spongycastle:pg:1.54.0.0' implementation 'com.madgag.spongycastle:pg:1.54.0.0'
implementation 'com.afollestad.material-dialogs:core:0.9.6.0' implementation 'com.afollestad.material-dialogs:core:3.3.0'
implementation 'com.afollestad.material-dialogs:input:3.3.0'
implementation 'com.afollestad.material-dialogs:lifecycle:3.3.0'
implementation 'com.lmntrx.android.library.livin.missme:missme:0.1.5'
// https://mvnrepository.com/artifact/com.jakewharton/butterknife // https://mvnrepository.com/artifact/com.jakewharton/butterknife
implementation 'com.jakewharton:butterknife:10.2.1' implementation 'com.jakewharton:butterknife:10.2.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.recyclerview:recyclerview:1.1.0'

View File

@ -1,5 +1,5 @@
{ {
"version": 8, "version": 9,
"contents": [ "contents": [
{ {
"type": "COMPAT", "type": "COMPAT",
@ -14,8 +14,8 @@
"name": "SMAPI for Galaxy Store", "name": "SMAPI for Galaxy Store",
"assetPath": "compat/samsung_138/", "assetPath": "compat/samsung_138/",
"description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.4.1.1", "description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.4.1.1",
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_3.zip", "url": "http://zaneyork.cn/download/compat/smapi_samsung_138_4.zip",
"hash": "d559c4b62fbf598eb8fff99ddcd152d7e34f6e30aa32a64d728ce1dd174b0dff" "hash": "e6d018c164d9f7d482f3d28dddf33dd5d7463bc414b61af9d65e3ca0b1eecc93"
}, },
{ {
"type": "LOCALE", "type": "LOCALE",

View File

@ -1,5 +1,5 @@
{ {
"version": 8, "version": 9,
"contents": [ "contents": [
{ {
"type": "COMPAT", "type": "COMPAT",
@ -14,8 +14,8 @@
"name": "SMAPI for Galaxy Store", "name": "SMAPI for Galaxy Store",
"assetPath": "compat/samsung_138/", "assetPath": "compat/samsung_138/",
"description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.4.1.1", "description": "SMAPI compat package for game 1.4.4.138 - latest, SMAPI 3.4.1.1",
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_3.zip", "url": "http://zaneyork.cn/download/compat/smapi_samsung_138_4.zip",
"hash": "d559c4b62fbf598eb8fff99ddcd152d7e34f6e30aa32a64d728ce1dd174b0dff" "hash": "e6d018c164d9f7d482f3d28dddf33dd5d7463bc414b61af9d65e3ca0b1eecc93"
}, },
{ {
"type": "LOCALE", "type": "LOCALE",

View File

@ -1,5 +1,5 @@
{ {
"version": 8, "version": 9,
"contents": [ "contents": [
{ {
"type": "COMPAT", "type": "COMPAT",
@ -14,8 +14,8 @@
"name": "SMAPI三星商店兼容包", "name": "SMAPI三星商店兼容包",
"assetPath": "compat/samsung_138/", "assetPath": "compat/samsung_138/",
"description": "SMAPI三星商店兼容包 适用版本1.4.4.138至今, SMAPI 3.4.1.1", "description": "SMAPI三星商店兼容包 适用版本1.4.4.138至今, SMAPI 3.4.1.1",
"url": "http://zaneyork.cn/download/compat/smapi_samsung_138_3.zip", "url": "http://zaneyork.cn/download/compat/smapi_samsung_138_4.zip",
"hash": "d559c4b62fbf598eb8fff99ddcd152d7e34f6e30aa32a64d728ce1dd174b0dff" "hash": "e6d018c164d9f7d482f3d28dddf33dd5d7463bc414b61af9d65e3ca0b1eecc93"
}, },
{ {
"type": "LOCALE", "type": "LOCALE",

View File

@ -9,9 +9,9 @@ import android.os.Environment;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import com.afollestad.materialdialogs.MaterialDialog;
import com.google.android.material.navigation.NavigationView; import com.google.android.material.navigation.NavigationView;
import com.hjq.language.LanguagesManager; import com.hjq.language.LanguagesManager;
import com.lmntrx.android.library.livin.missme.ProgressDialog;
import com.microsoft.appcenter.AppCenter; import com.microsoft.appcenter.AppCenter;
import com.microsoft.appcenter.analytics.Analytics; import com.microsoft.appcenter.analytics.Analytics;
import com.microsoft.appcenter.crashes.Crashes; import com.microsoft.appcenter.crashes.Crashes;
@ -25,6 +25,7 @@ import com.zane.smapiinstaller.logic.ConfigManager;
import com.zane.smapiinstaller.logic.GameLauncher; import com.zane.smapiinstaller.logic.GameLauncher;
import com.zane.smapiinstaller.logic.ModAssetsManager; import com.zane.smapiinstaller.logic.ModAssetsManager;
import com.zane.smapiinstaller.utils.DialogUtils; import com.zane.smapiinstaller.utils.DialogUtils;
import com.zane.smapiinstaller.utils.JSONUtil;
import com.zane.smapiinstaller.utils.TranslateUtil; import com.zane.smapiinstaller.utils.TranslateUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -128,7 +129,7 @@ public class MainActivity extends AppCompatActivity {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if(item.isCheckable()) { if (item.isCheckable()) {
if (item.isChecked()) { if (item.isChecked()) {
item.setChecked(false); item.setChecked(false);
} else { } else {
@ -148,16 +149,15 @@ public class MainActivity extends AppCompatActivity {
config.setDeveloperMode(item.isChecked()); config.setDeveloperMode(item.isChecked());
break; break;
case R.id.settings_set_mod_path: case R.id.settings_set_mod_path:
DialogUtils.showInputDialog(this, R.string.input, R.string.input_mods_path, Constants.MOD_PATH, Constants.MOD_PATH, (dialog, input) -> { DialogUtils.showInputDialog(toolbar, R.string.input, R.string.input_mods_path, Constants.MOD_PATH, Constants.MOD_PATH, (dialog, input) -> {
if(StringUtils.isNoneBlank(input)) { if (StringUtils.isNoneBlank(input)) {
String pathString = input.toString(); String pathString = input.toString();
File file = new File(Environment.getExternalStorageDirectory(), pathString); File file = new File(Environment.getExternalStorageDirectory(), pathString);
if(file.exists() && file.isDirectory()) { if (file.exists() && file.isDirectory()) {
Constants.MOD_PATH = pathString; Constants.MOD_PATH = pathString;
config.setModsPath(pathString); config.setModsPath(pathString);
manager.flushConfig(); manager.flushConfig();
} } else {
else {
DialogUtils.showAlertDialog(drawer, R.string.error, R.string.error_illegal_path); DialogUtils.showAlertDialog(drawer, R.string.error, R.string.error_illegal_path);
} }
} }
@ -180,10 +180,10 @@ public class MainActivity extends AppCompatActivity {
} }
private int getTranslateServiceIndex(AppConfig selectedTranslator) { private int getTranslateServiceIndex(AppConfig selectedTranslator) {
if(selectedTranslator == null) { if (selectedTranslator == null) {
return 0; return 0;
} }
switch (selectedTranslator.getValue()){ switch (selectedTranslator.getValue()) {
case "OFF": case "OFF":
return 0; return 0;
case "Google": case "Google":
@ -194,19 +194,19 @@ public class MainActivity extends AppCompatActivity {
} }
private void selectTranslateServiceLogic() { private void selectTranslateServiceLogic() {
DaoSession daoSession = ((MainApplication)this.getApplication()).getDaoSession(); DaoSession daoSession = ((MainApplication) this.getApplication()).getDaoSession();
AppConfigDao appConfigDao = daoSession.getAppConfigDao(); AppConfigDao appConfigDao = daoSession.getAppConfigDao();
int index = getTranslateServiceIndex(appConfigDao.queryBuilder().where(AppConfigDao.Properties.Name.eq(AppConfigKey.ACTIVE_TRANSLATOR)).build().unique()); int index = getTranslateServiceIndex(appConfigDao.queryBuilder().where(AppConfigDao.Properties.Name.eq(AppConfigKey.ACTIVE_TRANSLATOR)).build().unique());
DialogUtils.setCurrentDialog(new MaterialDialog.Builder(this).title(R.string.settings_translation_service).items(R.array.translators).itemsCallbackSingleChoice(index, (dialog, itemView, position, text) -> { DialogUtils.showSingleChoiceDialog(toolbar, R.string.settings_translation_service, R.array.translators, index, (dialog, position) -> {
AppConfig activeTranslator = appConfigDao.queryBuilder().where(AppConfigDao.Properties.Name.eq(AppConfigKey.ACTIVE_TRANSLATOR)).build().unique(); AppConfig activeTranslator = appConfigDao.queryBuilder().where(AppConfigDao.Properties.Name.eq(AppConfigKey.ACTIVE_TRANSLATOR)).build().unique();
switch (position) { switch (position) {
case 0: case 0:
if(activeTranslator != null) { if (activeTranslator != null) {
appConfigDao.delete(activeTranslator); appConfigDao.delete(activeTranslator);
} }
break; break;
case 1: case 1:
if(activeTranslator == null) { if (activeTranslator == null) {
activeTranslator = new AppConfig(null, AppConfigKey.ACTIVE_TRANSLATOR, TranslateUtil.GOOGLE); activeTranslator = new AppConfig(null, AppConfigKey.ACTIVE_TRANSLATOR, TranslateUtil.GOOGLE);
} else { } else {
activeTranslator.setValue(TranslateUtil.GOOGLE); activeTranslator.setValue(TranslateUtil.GOOGLE);
@ -214,7 +214,7 @@ public class MainActivity extends AppCompatActivity {
appConfigDao.insertOrReplace(activeTranslator); appConfigDao.insertOrReplace(activeTranslator);
break; break;
case 2: case 2:
if(activeTranslator == null) { if (activeTranslator == null) {
activeTranslator = new AppConfig(null, AppConfigKey.ACTIVE_TRANSLATOR, TranslateUtil.YOU_DAO); activeTranslator = new AppConfig(null, AppConfigKey.ACTIVE_TRANSLATOR, TranslateUtil.YOU_DAO);
} else { } else {
activeTranslator.setValue(TranslateUtil.YOU_DAO); activeTranslator.setValue(TranslateUtil.YOU_DAO);
@ -222,14 +222,12 @@ public class MainActivity extends AppCompatActivity {
appConfigDao.insertOrReplace(activeTranslator); appConfigDao.insertOrReplace(activeTranslator);
break; break;
default: default:
return false;
} }
return true; });
}).show());
} }
private void selectLanguageLogic() { private void selectLanguageLogic() {
DialogUtils.setCurrentDialog(new MaterialDialog.Builder(this).title(R.string.settings_set_language).items(R.array.languages).itemsCallback((dialog, itemView, position, text) -> { DialogUtils.showListItemsDialog(toolbar, R.string.settings_set_language, R.array.languages, (dialog, position) -> {
boolean restart; boolean restart;
switch (position) { switch (position) {
case 0: case 0:
@ -271,12 +269,19 @@ public class MainActivity extends AppCompatActivity {
overridePendingTransition(R.anim.fragment_fade_enter, R.anim.fragment_fade_exit); overridePendingTransition(R.anim.fragment_fade_enter, R.anim.fragment_fade_exit);
finish(); finish();
} }
}).show()); });
} }
private void updateCheckLogic() { private void updateCheckLogic() {
ModAssetsManager modAssetsManager = new ModAssetsManager(toolbar); ModAssetsManager modAssetsManager = new ModAssetsManager(toolbar);
modAssetsManager.checkModUpdate(); modAssetsManager.checkModUpdate((list) -> {
try {
NavController controller = Navigation.findNavController(toolbar);
controller.navigate(MobileNavigationDirections.actionNavAnyToModUpdateFragment(JSONUtil.toJson(list)));
} catch (Exception e) {
Crashes.trackError(e);
}
});
} }
@Override @Override
@ -286,6 +291,20 @@ public class MainActivity extends AppCompatActivity {
|| super.onSupportNavigateUp(); || super.onSupportNavigateUp();
} }
@Override
public void onBackPressed() {
Object dialog = DialogUtils.getCurrentDialog();
if (dialog instanceof ProgressDialog) {
ProgressDialog progressDialog = ((ProgressDialog) dialog);
progressDialog.onBackPressed(
() -> {
super.onBackPressed();
return null;
}
);
}
}
@Override @Override
protected void attachBaseContext(Context newBase) { protected void attachBaseContext(Context newBase) {
// 国际化适配绑定语种 // 国际化适配绑定语种

View File

@ -0,0 +1,16 @@
package com.zane.smapiinstaller.constant;
/**
* @author Zane
*/
public enum DialogAction {
/**
* 确认
*/
POSITIVE,
/**
* 取消
*/
NEGATIVE
}

View File

@ -4,6 +4,7 @@ import lombok.Data;
/** /**
* 帮助信息 * 帮助信息
* @author Zane
*/ */
@Data @Data
public class HelpItem { public class HelpItem {

View File

@ -1,4 +1,4 @@
package com.zane.smapiinstaller.dto; package com.zane.smapiinstaller.entity;
import org.greenrobot.greendao.annotation.Entity; import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id; import org.greenrobot.greendao.annotation.Id;

View File

@ -92,6 +92,17 @@ public class CommonLogic {
} }
} }
/**
* 在UI线程执行操作
* @param activity activity
* @param action 操作
*/
public static void runOnUiThread(Activity activity, Consumer<Activity> action) {
if (activity != null && !activity.isFinishing()) {
activity.runOnUiThread(() -> action.accept(activity));
}
}
/** /**
* 打开指定URL * 打开指定URL
* *

View File

@ -6,7 +6,6 @@ import android.os.Environment;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import com.afollestad.materialdialogs.DialogAction;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -19,6 +18,7 @@ import com.lzy.okgo.model.Response;
import com.microsoft.appcenter.crashes.Crashes; import com.microsoft.appcenter.crashes.Crashes;
import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.constant.Constants; import com.zane.smapiinstaller.constant.Constants;
import com.zane.smapiinstaller.constant.DialogAction;
import com.zane.smapiinstaller.dto.ModUpdateCheckRequestDto; import com.zane.smapiinstaller.dto.ModUpdateCheckRequestDto;
import com.zane.smapiinstaller.dto.ModUpdateCheckResponseDto; import com.zane.smapiinstaller.dto.ModUpdateCheckResponseDto;
import com.zane.smapiinstaller.entity.ModManifestEntry; import com.zane.smapiinstaller.entity.ModManifestEntry;
@ -37,8 +37,8 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import androidx.core.util.Consumer;
import java9.util.Objects; import java9.util.Objects;
import java9.util.function.Consumer;
import java9.util.function.Predicate; import java9.util.function.Predicate;
import java9.util.stream.Collectors; import java9.util.stream.Collectors;
import java9.util.stream.StreamSupport; import java9.util.stream.StreamSupport;
@ -291,7 +291,7 @@ public class ModAssetsManager {
} }
} }
public void checkModUpdate() { public void checkModUpdate(Consumer<List<ModUpdateCheckResponseDto>> callback) {
List<ModUpdateCheckRequestDto.ModInfo> list = StreamSupport.stream(findAllInstalledMods(false)) List<ModUpdateCheckRequestDto.ModInfo> list = StreamSupport.stream(findAllInstalledMods(false))
.filter(mod -> mod.getUpdateKeys() != null && !mod.getUpdateKeys().isEmpty()) .filter(mod -> mod.getUpdateKeys() != null && !mod.getUpdateKeys().isEmpty())
.map(ModUpdateCheckRequestDto.ModInfo::fromModManifestEntry) .map(ModUpdateCheckRequestDto.ModInfo::fromModManifestEntry)
@ -313,7 +313,7 @@ public class ModAssetsManager {
List<ModUpdateCheckResponseDto> checkResponseDtos = response.body(); List<ModUpdateCheckResponseDto> checkResponseDtos = response.body();
if (checkResponseDtos != null) { if (checkResponseDtos != null) {
List<ModUpdateCheckResponseDto> list = StreamSupport.stream(checkResponseDtos).filter(dto -> dto.getSuggestedUpdate() != null).collect(Collectors.toList()); List<ModUpdateCheckResponseDto> list = StreamSupport.stream(checkResponseDtos).filter(dto -> dto.getSuggestedUpdate() != null).collect(Collectors.toList());
callback.accept(list);
} }
} }
}); });

View File

@ -1,6 +1,5 @@
package com.zane.smapiinstaller.ui.about; package com.zane.smapiinstaller.ui.about;
import android.content.ActivityNotFoundException;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@ -14,7 +13,7 @@ import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.Toast; import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog; import com.microsoft.appcenter.crashes.Crashes;
import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.constant.Constants; import com.zane.smapiinstaller.constant.Constants;
import com.zane.smapiinstaller.logic.CommonLogic; import com.zane.smapiinstaller.logic.CommonLogic;
@ -50,7 +49,7 @@ public class AboutFragment extends Fragment {
void gplay() { void gplay() {
try { try {
CommonLogic.doOnNonNull(this.getActivity(), (activity) -> this.openPlayStore("market://details?id=" + activity.getPackageName())); CommonLogic.doOnNonNull(this.getActivity(), (activity) -> this.openPlayStore("market://details?id=" + activity.getPackageName()));
} catch (ActivityNotFoundException ex) { } catch (Exception ex) {
CommonLogic.doOnNonNull(this.getActivity(), (activity) -> CommonLogic.openUrl(activity, "https://play.google.com/store/apps/details?id=" + activity.getPackageName())); CommonLogic.doOnNonNull(this.getActivity(), (activity) -> CommonLogic.openUrl(activity, "https://play.google.com/store/apps/details?id=" + activity.getPackageName()));
} }
} }
@ -75,11 +74,9 @@ public class AboutFragment extends Fragment {
@OnClick(R.id.button_donation) @OnClick(R.id.button_donation)
void donation() { void donation() {
CommonLogic.doOnNonNull(this.getContext(), (context) -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(context) DialogUtils.showListItemsDialog(imgHeart, R.string.button_donation_text, R.array.donation_methods, (dialog, position) ->
.title(R.string.button_donation_text) CommonLogic.showAnimation(imgHeart, R.anim.heart_beat, (animation) ->
.items(R.array.donation_methods) CommonLogic.doOnNonNull(this.getActivity(), (activity) -> listSelectLogic(activity, position))));
.itemsCallback((dialog, itemView, position, text) ->
CommonLogic.showAnimation(imgHeart, R.anim.heart_beat, (animation) -> listSelectLogic(context, position))).show()));
} }
private void listSelectLogic(Context context, int position) { private void listSelectLogic(Context context, int position) {
@ -87,7 +84,12 @@ public class AboutFragment extends Fragment {
case 0: case 0:
boolean hasInstalledAlipayClient = AlipayDonate.hasInstalledAlipayClient(context); boolean hasInstalledAlipayClient = AlipayDonate.hasInstalledAlipayClient(context);
if (hasInstalledAlipayClient) { if (hasInstalledAlipayClient) {
AlipayDonate.startAlipayClient(this.getActivity(), "fkx13570v1pp2xenyrx4y3f"); try {
AlipayDonate.startAlipayClient(this.getActivity(), "fkx13570v1pp2xenyrx4y3f");
} catch (Exception e) {
Crashes.trackError(e);
CommonLogic.openUrl(context, "http://dl.zaneyork.cn/alipay.png");
}
} else { } else {
CommonLogic.openUrl(context, "http://dl.zaneyork.cn/alipay.png"); CommonLogic.openUrl(context, "http://dl.zaneyork.cn/alipay.png");
} }

View File

@ -10,10 +10,10 @@ import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import com.afollestad.materialdialogs.DialogAction;
import com.zane.smapiinstaller.BuildConfig; import com.zane.smapiinstaller.BuildConfig;
import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.constant.Constants; import com.zane.smapiinstaller.constant.Constants;
import com.zane.smapiinstaller.constant.DialogAction;
import com.zane.smapiinstaller.logic.CommonLogic; import com.zane.smapiinstaller.logic.CommonLogic;
import com.zane.smapiinstaller.utils.DialogUtils; import com.zane.smapiinstaller.utils.DialogUtils;
import com.zane.smapiinstaller.utils.FileUtils; import com.zane.smapiinstaller.utils.FileUtils;

View File

@ -5,6 +5,11 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.utils.DialogUtils;
import java.util.ArrayList;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
@ -15,13 +20,6 @@ import butterknife.ButterKnife;
import butterknife.OnClick; import butterknife.OnClick;
import butterknife.OnTextChanged; import butterknife.OnTextChanged;
import com.afollestad.materialdialogs.MaterialDialog;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.logic.CommonLogic;
import com.zane.smapiinstaller.utils.DialogUtils;
import java.util.ArrayList;
/** /**
* @author Zane * @author Zane
*/ */
@ -55,7 +53,7 @@ public class ConfigFragment extends Fragment {
@OnClick(R.id.button_sort_by) @OnClick(R.id.button_sort_by)
void onSortByClick() { void onSortByClick() {
int index; int index = 0;
switch (configViewModel.getSortBy()) { switch (configViewModel.getSortBy()) {
case "Name asc": case "Name asc":
index = 0; index = 0;
@ -70,29 +68,23 @@ public class ConfigFragment extends Fragment {
index = 3; index = 3;
break; break;
default: default:
index = 0;
} }
CommonLogic.doOnNonNull(this.getContext(), context -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(context) DialogUtils.showSingleChoiceDialog(recyclerView, R.string.sort_by, R.array.mod_list_sort_by, index, (dialog, position) -> {
.title(R.string.sort_by) switch (position) {
.items(R.array.mod_list_sort_by) case 0:
.itemsCallbackSingleChoice(index, (dialog, itemView, position, text) -> { configViewModel.switchSortBy("Name asc");
switch (position) { break;
case 0: case 1:
configViewModel.switchSortBy("Name asc"); configViewModel.switchSortBy("Name desc");
break; break;
case 1: case 2:
configViewModel.switchSortBy("Name desc"); configViewModel.switchSortBy("Date asc");
break; break;
case 2: case 3:
configViewModel.switchSortBy("Date asc"); configViewModel.switchSortBy("Date desc");
break; break;
case 3: default:
configViewModel.switchSortBy("Date desc"); }
break; });
default:
return false;
}
return true;
}).show()));
} }
} }

View File

@ -11,7 +11,7 @@ import com.zane.smapiinstaller.entity.AppConfig;
import com.zane.smapiinstaller.entity.AppConfigDao; import com.zane.smapiinstaller.entity.AppConfigDao;
import com.zane.smapiinstaller.entity.DaoSession; import com.zane.smapiinstaller.entity.DaoSession;
import com.zane.smapiinstaller.entity.ModManifestEntry; import com.zane.smapiinstaller.entity.ModManifestEntry;
import com.zane.smapiinstaller.dto.TranslationResult; import com.zane.smapiinstaller.entity.TranslationResult;
import com.zane.smapiinstaller.entity.TranslationResultDao; import com.zane.smapiinstaller.entity.TranslationResultDao;
import com.zane.smapiinstaller.logic.CommonLogic; import com.zane.smapiinstaller.logic.CommonLogic;
import com.zane.smapiinstaller.logic.ListenableObject; import com.zane.smapiinstaller.logic.ListenableObject;

View File

@ -7,9 +7,9 @@ import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import com.afollestad.materialdialogs.DialogAction;
import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.constant.Constants; import com.zane.smapiinstaller.constant.Constants;
import com.zane.smapiinstaller.constant.DialogAction;
import com.zane.smapiinstaller.entity.ModManifestEntry; import com.zane.smapiinstaller.entity.ModManifestEntry;
import com.zane.smapiinstaller.utils.DialogUtils; import com.zane.smapiinstaller.utils.DialogUtils;
import com.zane.smapiinstaller.utils.FileUtils; import com.zane.smapiinstaller.utils.FileUtils;

View File

@ -13,14 +13,14 @@ import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import com.afollestad.materialdialogs.DialogAction; import com.lmntrx.android.library.livin.missme.ProgressDialog;
import com.afollestad.materialdialogs.MaterialDialog;
import com.lzy.okgo.OkGo; import com.lzy.okgo.OkGo;
import com.lzy.okgo.callback.FileCallback; import com.lzy.okgo.callback.FileCallback;
import com.lzy.okgo.model.Progress; import com.lzy.okgo.model.Progress;
import com.lzy.okgo.model.Response; import com.lzy.okgo.model.Response;
import com.microsoft.appcenter.crashes.Crashes; import com.microsoft.appcenter.crashes.Crashes;
import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.constant.DialogAction;
import com.zane.smapiinstaller.constant.DownloadableContentTypes; import com.zane.smapiinstaller.constant.DownloadableContentTypes;
import com.zane.smapiinstaller.entity.DownloadableContent; import com.zane.smapiinstaller.entity.DownloadableContent;
import com.zane.smapiinstaller.entity.ModManifestEntry; import com.zane.smapiinstaller.entity.ModManifestEntry;
@ -157,13 +157,13 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter<Downloadabl
} }
downloading.set(true); downloading.set(true);
ModManifestEntry finalModManifestEntry = modManifestEntry; ModManifestEntry finalModManifestEntry = modManifestEntry;
AtomicReference<MaterialDialog> dialogRef = DialogUtils.showProgressDialog(itemView, R.string.progress, ""); AtomicReference<ProgressDialog> dialogRef = DialogUtils.showProgressDialog(itemView, R.string.progress, "");
OkGo.<File>get(downloadableContent.getUrl()).execute(new FileCallback(file.getParentFile().getAbsolutePath(), file.getName()) { OkGo.<File>get(downloadableContent.getUrl()).execute(new FileCallback(file.getParentFile().getAbsolutePath(), file.getName()) {
@Override @Override
public void onError(Response<File> response) { public void onError(Response<File> response) {
super.onError(response); super.onError(response);
MaterialDialog dialog = dialogRef.get(); ProgressDialog dialog = dialogRef.get();
DialogUtils.dismissDialog(itemView, dialog); dialog.dismiss();
downloading.set(false); downloading.set(false);
DialogUtils.showAlertDialog(itemView, R.string.error, R.string.error_failed_to_download); DialogUtils.showAlertDialog(itemView, R.string.error, R.string.error_failed_to_download);
} }
@ -171,17 +171,17 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter<Downloadabl
@Override @Override
public void downloadProgress(Progress progress) { public void downloadProgress(Progress progress) {
super.downloadProgress(progress); super.downloadProgress(progress);
MaterialDialog dialog = dialogRef.get(); ProgressDialog dialog = dialogRef.get();
if (dialog != null && !dialog.isCancelled()) { if (dialog != null) {
dialog.setContent(R.string.downloading, progress.currentSize / 1024, progress.totalSize / 1024); dialog.setMessage(context.getString(R.string.downloading, progress.currentSize / 1024, progress.totalSize / 1024));
dialog.setProgress((int) (progress.currentSize * 100.0 / progress.totalSize)); dialog.setProgress((int) (progress.currentSize * 100.0 / progress.totalSize));
} }
} }
@Override @Override
public void onSuccess(Response<File> response) { public void onSuccess(Response<File> response) {
MaterialDialog dialog = dialogRef.get(); ProgressDialog dialog = dialogRef.get();
DialogUtils.dismissDialog(itemView, dialog); dialog.dismiss();
downloading.set(false); downloading.set(false);
File downloadedFile = response.body(); File downloadedFile = response.body();
String hash = com.zane.smapiinstaller.utils.FileUtils.getFileHash(downloadedFile); String hash = com.zane.smapiinstaller.utils.FileUtils.getFileHash(downloadedFile);

View File

@ -7,11 +7,10 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.afollestad.materialdialogs.DialogAction; import com.lmntrx.android.library.livin.missme.ProgressDialog;
import com.afollestad.materialdialogs.GravityEnum;
import com.afollestad.materialdialogs.MaterialDialog;
import com.microsoft.appcenter.crashes.Crashes; import com.microsoft.appcenter.crashes.Crashes;
import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.constant.DialogAction;
import com.zane.smapiinstaller.logic.ApkPatcher; import com.zane.smapiinstaller.logic.ApkPatcher;
import com.zane.smapiinstaller.logic.CommonLogic; import com.zane.smapiinstaller.logic.CommonLogic;
import com.zane.smapiinstaller.logic.ModAssetsManager; import com.zane.smapiinstaller.logic.ModAssetsManager;
@ -19,6 +18,8 @@ import com.zane.smapiinstaller.utils.DialogUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.concurrent.atomic.AtomicReference;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.navigation.NavController; import androidx.navigation.NavController;
@ -63,70 +64,68 @@ public class InstallFragment extends Fragment {
* 安装逻辑 * 安装逻辑
*/ */
private void installLogic() { private void installLogic() {
new MaterialDialog.Builder(context).title(R.string.install_progress_title).content(R.string.extracting_package).contentGravity(GravityEnum.CENTER) AtomicReference<ProgressDialog> dialogHolder = DialogUtils.showProgressDialog(root, R.string.install_progress_title, context.getString(R.string.extracting_package));
.progress(false, 100, true).cancelable(false).cancelListener(dialog -> { if (task != null) {
if (task != null) { task.interrupt();
task.interrupt(); }
task = new Thread(() -> {
ProgressDialog dialog = null;
try {
do {
Thread.sleep(10);
dialog = dialogHolder.get();
} while (dialog == null);
ApkPatcher patcher = new ApkPatcher(context);
ProgressDialog finalDialog = dialog;
patcher.registerProgressListener((progress) -> DialogUtils.setProgressDialogState(root, finalDialog, null, progress));
DialogUtils.setProgressDialogState(root, dialog, R.string.extracting_package, null);
String path = patcher.extract();
if (path == null) {
DialogUtils.showAlertDialog(root, R.string.error, StringUtils.firstNonBlank(patcher.getErrorMessage().get(), context.getString(R.string.error_game_not_found)));
return;
}
DialogUtils.setProgressDialogState(root, dialog, R.string.unpacking_smapi_files, null);
if (!CommonLogic.unpackSmapiFiles(context, path, false)) {
DialogUtils.showAlertDialog(root, R.string.error, StringUtils.firstNonBlank(patcher.getErrorMessage().get(), context.getString(R.string.failed_to_unpack_smapi_files)));
return;
}
ModAssetsManager modAssetsManager = new ModAssetsManager(root);
DialogUtils.setProgressDialogState(root, dialog, R.string.unpacking_smapi_files, 6);
modAssetsManager.installDefaultMods();
DialogUtils.setProgressDialogState(root, dialog, R.string.patching_package, 8);
if (!patcher.patch(path)) {
int target = patcher.getSwitchAction().getAndSet(0);
if (target == R.string.menu_download) {
DialogUtils.showConfirmDialog(root, R.string.error, StringUtils.firstNonBlank(patcher.getErrorMessage().get(), context.getString(R.string.failed_to_patch_game)), R.string.menu_download, R.string.cancel, (d, which) -> {
if (which == DialogAction.POSITIVE) {
NavController controller = Navigation.findNavController(root);
controller.navigate(InstallFragmentDirections.actionNavInstallToNavDownload());
}
});
} else {
DialogUtils.showAlertDialog(root, R.string.error, StringUtils.firstNonBlank(patcher.getErrorMessage().get(), context.getString(R.string.failed_to_patch_game)));
}
return;
}
DialogUtils.setProgressDialogState(root, dialog, R.string.signing_package, null);
String signPath = patcher.sign(path);
if (signPath == null) {
DialogUtils.showAlertDialog(root, R.string.error, StringUtils.firstNonBlank(patcher.getErrorMessage().get(), context.getString(R.string.failed_to_sign_game)));
return;
}
DialogUtils.setProgressDialogState(root, dialog, R.string.installing_package, null);
patcher.install(signPath);
} catch (InterruptedException ignored) {
} catch (Exception e) {
Crashes.trackError(e);
DialogUtils.showAlertDialog(root, R.string.error, e.getLocalizedMessage());
} finally {
if(dialog != null) {
dialog.dismiss();
}
} }
}).showListener(dialogInterface -> { });
final MaterialDialog dialog = (MaterialDialog) dialogInterface; task.start();
DialogUtils.setCurrentDialog(dialog);
if (task != null) {
task.interrupt();
}
task = new Thread(() -> {
try {
ApkPatcher patcher = new ApkPatcher(context);
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) {
DialogUtils.showAlertDialog(root, R.string.error, StringUtils.firstNonBlank(patcher.getErrorMessage().get(), context.getString(R.string.error_game_not_found)));
return;
}
DialogUtils.setProgressDialogState(root, dialog, R.string.unpacking_smapi_files, null);
if (!CommonLogic.unpackSmapiFiles(context, path, false)) {
DialogUtils.showAlertDialog(root, R.string.error, StringUtils.firstNonBlank(patcher.getErrorMessage().get(), context.getString(R.string.failed_to_unpack_smapi_files)));
return;
}
ModAssetsManager modAssetsManager = new ModAssetsManager(root);
DialogUtils.setProgressDialogState(root, dialog, R.string.unpacking_smapi_files, 6);
modAssetsManager.installDefaultMods();
DialogUtils.setProgressDialogState(root, dialog, R.string.patching_package, 8);
if (!patcher.patch(path)) {
int target = patcher.getSwitchAction().getAndSet(0);
if(target == R.string.menu_download) {
DialogUtils.showConfirmDialog(root, R.string.error, StringUtils.firstNonBlank(patcher.getErrorMessage().get(), context.getString(R.string.failed_to_patch_game)), R.string.menu_download, R.string.cancel, (d, which) -> {
if(which == DialogAction.POSITIVE) {
NavController controller = Navigation.findNavController(root);
controller.navigate(InstallFragmentDirections.actionNavInstallToNavDownload());
}
});
}
else {
DialogUtils.showAlertDialog(root, R.string.error, StringUtils.firstNonBlank(patcher.getErrorMessage().get(), context.getString(R.string.failed_to_patch_game)));
}
return;
}
DialogUtils.setProgressDialogState(root, dialog, R.string.signing_package, null);
String signPath = patcher.sign(path);
if (signPath == null) {
DialogUtils.showAlertDialog(root, R.string.error, StringUtils.firstNonBlank(patcher.getErrorMessage().get(), context.getString(R.string.failed_to_sign_game)));
return;
}
DialogUtils.setProgressDialogState(root, dialog, R.string.installing_package, null);
patcher.install(signPath);
}
catch (Exception e) {
Crashes.trackError(e);
DialogUtils.showAlertDialog(root, R.string.error, e.getLocalizedMessage());
}
finally {
DialogUtils.dismissDialog(root, dialog);
}
});
task.start();
}).show();
} }
} }

View File

@ -0,0 +1,63 @@
package com.zane.smapiinstaller.ui.update;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.dto.ModUpdateCheckResponseDto;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.ButterKnife;
/**
* {@link RecyclerView.Adapter} that can display a {@link ModUpdateCheckResponseDto.UpdateInfo}
* @author Zane
*/
public class ModUpdateAdapter extends RecyclerView.Adapter<ModUpdateAdapter.ViewHolder> {
private List<ModUpdateCheckResponseDto.UpdateInfo> updateInfoList;
public void setUpdateInfoList(List<ModUpdateCheckResponseDto.UpdateInfo> updateInfoList) {
this.updateInfoList = updateInfoList;
notifyDataSetChanged();
}
public ModUpdateAdapter(List<ModUpdateCheckResponseDto.UpdateInfo> items) {
updateInfoList = items;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.download_content_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.setUpdateInfo(updateInfoList.get(position));
}
@Override
public int getItemCount() {
return updateInfoList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
public ModUpdateCheckResponseDto.UpdateInfo updateInfo;
public void setUpdateInfo(ModUpdateCheckResponseDto.UpdateInfo updateInfo) {
this.updateInfo = updateInfo;
}
public ViewHolder(View view) {
super(view);
ButterKnife.bind(this, itemView);
}
}
}

View File

@ -0,0 +1,56 @@
package com.zane.smapiinstaller.ui.update;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.fasterxml.jackson.core.type.TypeReference;
import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.dto.ModUpdateCheckResponseDto;
import com.zane.smapiinstaller.logic.CommonLogic;
import com.zane.smapiinstaller.utils.JSONUtil;
import java.util.List;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* A fragment representing a list of Items.
* @author Zane
*/
public class ModUpdateFragment extends Fragment {
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public ModUpdateFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_mod_update_list, container, false);
// Set the adapter
if (view instanceof RecyclerView) {
Context context = view.getContext();
RecyclerView recyclerView = (RecyclerView) view;
recyclerView.setLayoutManager(new LinearLayoutManager(context));
CommonLogic.doOnNonNull(this.getArguments(), arguments -> {
String updateInfoListJson = arguments.getString("updateInfoListJson", "[]");
List<ModUpdateCheckResponseDto.UpdateInfo> updateInfos = JSONUtil.fromJson(updateInfoListJson, new TypeReference<List<ModUpdateCheckResponseDto.UpdateInfo>>() {
});
ModUpdateAdapter adapter = new ModUpdateAdapter(updateInfos);
recyclerView.setAdapter(adapter);
});
recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL));
}
return view;
}
}

View File

@ -1,26 +1,40 @@
package com.zane.smapiinstaller.utils; package com.zane.smapiinstaller.utils;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog;
import android.text.InputType; import android.text.InputType;
import android.view.View; import android.view.View;
import android.widget.ProgressBar;
import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.input.DialogInputExtKt;
import com.afollestad.materialdialogs.list.DialogListExtKt;
import com.afollestad.materialdialogs.list.DialogSingleChoiceExtKt;
import com.lmntrx.android.library.livin.missme.ProgressDialog;
import com.microsoft.appcenter.crashes.Crashes; import com.microsoft.appcenter.crashes.Crashes;
import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.R;
import com.zane.smapiinstaller.constant.DialogAction;
import com.zane.smapiinstaller.logic.CommonLogic; import com.zane.smapiinstaller.logic.CommonLogic;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java9.util.function.BiConsumer;
/** /**
* 对话框相关工具类 * 对话框相关工具类
*
* @author Zane * @author Zane
*/ */
public class DialogUtils { public class DialogUtils {
private static Dialog currentDialog = null; private static Object currentDialog = null;
public static void setCurrentDialog(Dialog currentDialog) {
public static Object getCurrentDialog() {
return currentDialog;
}
public static void setCurrentDialog(Object currentDialog) {
DialogUtils.currentDialog = currentDialog; DialogUtils.currentDialog = currentDialog;
} }
/** /**
* 设置进度条状态 * 设置进度条状态
* *
@ -29,18 +43,15 @@ public class DialogUtils {
* @param message 消息 * @param message 消息
* @param progress 进度 * @param progress 进度
*/ */
public static void setProgressDialogState(View view, MaterialDialog dialog, Integer message, Integer progress) { public static void setProgressDialogState(View view, ProgressDialog dialog, Integer message, Integer progress) {
Activity activity = CommonLogic.getActivityFromView(view); CommonLogic.runOnUiThread(CommonLogic.getActivityFromView(view), (activity) -> {
if (activity != null && !activity.isFinishing() && !dialog.isCancelled()) { if (progress != null) {
activity.runOnUiThread(() -> { dialog.setProgress(progress);
if(progress != null) { }
dialog.setProgress(progress); if (message != null) {
} dialog.setMessage(activity.getString(message));
if(message != null) { }
dialog.setContent(message); });
}
});
}
} }
/** /**
@ -51,10 +62,11 @@ public class DialogUtils {
* @param message 消息 * @param message 消息
*/ */
public static void showAlertDialog(View view, int title, String message) { public static void showAlertDialog(View view, int title, String message) {
Activity activity = CommonLogic.getActivityFromView(view); CommonLogic.runOnUiThread(CommonLogic.getActivityFromView(view), (activity) -> {
if (activity != null && !activity.isFinishing()) { MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null).message(null, message, null).positiveButton(R.string.ok, null, null);
activity.runOnUiThread(() -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(activity).title(title).content(message).positiveText(R.string.ok).show())); DialogUtils.setCurrentDialog(materialDialog);
} materialDialog.show();
});
} }
/** /**
@ -65,10 +77,11 @@ public class DialogUtils {
* @param message 消息 * @param message 消息
*/ */
public static void showAlertDialog(View view, int title, int message) { public static void showAlertDialog(View view, int title, int message) {
Activity activity = CommonLogic.getActivityFromView(view); CommonLogic.runOnUiThread(CommonLogic.getActivityFromView(view), (activity) -> {
if (activity != null && !activity.isFinishing()) { MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null).message(message, null, null).positiveButton(R.string.ok, null, null);
activity.runOnUiThread(() -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(activity).title(title).content(message).positiveText(R.string.ok).show())); DialogUtils.setCurrentDialog(materialDialog);
} materialDialog.show();
});
} }
/** /**
@ -79,11 +92,18 @@ public class DialogUtils {
* @param message 消息 * @param message 消息
* @param callback 回调 * @param callback 回调
*/ */
public static void showConfirmDialog(View view, int title, int message, MaterialDialog.SingleButtonCallback callback) { public static void showConfirmDialog(View view, int title, int message, BiConsumer<MaterialDialog, DialogAction> callback) {
Activity activity = CommonLogic.getActivityFromView(view); CommonLogic.runOnUiThread(CommonLogic.getActivityFromView(view), (activity) -> {
if (activity != null && !activity.isFinishing()) { MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null).message(message, null, null).positiveButton(R.string.confirm, null, dialog -> {
activity.runOnUiThread(() -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(activity).title(title).content(message).positiveText(R.string.confirm).negativeText(R.string.cancel).onAny(callback).show())); callback.accept(dialog, DialogAction.POSITIVE);
} return null;
}).negativeButton(R.string.cancel, null, dialog -> {
callback.accept(dialog, DialogAction.NEGATIVE);
return null;
});
DialogUtils.setCurrentDialog(materialDialog);
materialDialog.show();
});
} }
/** /**
@ -94,7 +114,7 @@ public class DialogUtils {
* @param message 消息 * @param message 消息
* @param callback 回调 * @param callback 回调
*/ */
public static void showConfirmDialog(View view, int title, String message, MaterialDialog.SingleButtonCallback callback) { public static void showConfirmDialog(View view, int title, String message, BiConsumer<MaterialDialog, DialogAction> callback) {
showConfirmDialog(view, title, message, R.string.confirm, R.string.cancel, callback); showConfirmDialog(view, title, message, R.string.confirm, R.string.cancel, callback);
} }
@ -108,11 +128,18 @@ public class DialogUtils {
* @param negativeText 取消文本 * @param negativeText 取消文本
* @param callback 回调 * @param callback 回调
*/ */
public static void showConfirmDialog(View view, int title, String message, int positiveText, int negativeText, MaterialDialog.SingleButtonCallback callback) { public static void showConfirmDialog(View view, int title, String message, int positiveText, int negativeText, BiConsumer<MaterialDialog, DialogAction> callback) {
Activity activity = CommonLogic.getActivityFromView(view); CommonLogic.runOnUiThread(CommonLogic.getActivityFromView(view), (activity) -> {
if (activity != null && !activity.isFinishing()) { MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null).message(null, message, null).positiveButton(positiveText, null, dialog -> {
activity.runOnUiThread(() -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(activity).title(title).content(message).positiveText(positiveText).negativeText(negativeText).onAny(callback).show())); callback.accept(dialog, DialogAction.POSITIVE);
} return null;
}).negativeButton(negativeText, null, dialog -> {
callback.accept(dialog, DialogAction.NEGATIVE);
return null;
});
DialogUtils.setCurrentDialog(materialDialog);
materialDialog.show();
});
} }
/** /**
@ -123,58 +150,123 @@ public class DialogUtils {
* @param message 消息 * @param message 消息
* @return 对话框引用 * @return 对话框引用
*/ */
public static AtomicReference<MaterialDialog> showProgressDialog(View view, int title, String message) { public static AtomicReference<ProgressDialog> showProgressDialog(View view, int title, String message) {
Activity activity = CommonLogic.getActivityFromView(view); AtomicReference<ProgressDialog> reference = new AtomicReference<>();
AtomicReference<MaterialDialog> reference = new AtomicReference<>(); CommonLogic.runOnUiThread(CommonLogic.getActivityFromView(view), (activity) -> {
if (activity != null && !activity.isFinishing()) { ProgressDialog dialog = new ProgressDialog(activity);
activity.runOnUiThread(() -> { DialogUtils.setCurrentDialog(dialog);
MaterialDialog dialog = new MaterialDialog.Builder(activity) dialog.setMessage(message);
.title(title) dialog.setCancelable(false);
.content(message) dialog.setMax(100);
.progress(false, 100, true) dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
.cancelable(false) dialog.show();
.show(); reference.set(dialog);
currentDialog = dialog; });
reference.set(dialog);
});
}
return reference; return reference;
} }
/**
* 解散指定对话框
*
* @param view view
* @param dialog 对话框
*/
public static void dismissDialog(View view, MaterialDialog dialog) { public static void dismissDialog(View view, MaterialDialog dialog) {
Activity activity = CommonLogic.getActivityFromView(view); Activity activity = CommonLogic.getActivityFromView(view);
if (activity != null && !activity.isFinishing()) { if (activity != null && !activity.isFinishing()) {
if (dialog != null && !dialog.isCancelled()) { if (dialog != null && dialog.isShowing()) {
try { try {
dialog.dismiss(); dialog.dismiss();
} } catch (Exception e) {
catch (Exception e) {
Crashes.trackError(e); Crashes.trackError(e);
} }
} }
} }
} }
/**
* 解散当前对话框
*/
public static void dismissDialog() { public static void dismissDialog() {
if (currentDialog != null && currentDialog.isShowing()) { if (currentDialog != null) {
try { if (currentDialog instanceof MaterialDialog) {
currentDialog.dismiss(); MaterialDialog dialog = (MaterialDialog) currentDialog;
} if (dialog.isShowing()) {
catch (Exception e) { try {
Crashes.trackError(e); dialog.dismiss();
} catch (Exception e) {
Crashes.trackError(e);
}
}
} else if (currentDialog instanceof ProgressDialog) {
ProgressDialog dialog = (ProgressDialog) currentDialog;
dialog.dismiss();
} }
} }
} }
public static void showInputDialog(Activity activity, int title, int content, String hint, String prefill, MaterialDialog.InputCallback callback) { /**
if (activity != null && !activity.isFinishing()) { * 显示输入框
activity.runOnUiThread(() -> DialogUtils.setCurrentDialog(new MaterialDialog.Builder(activity) *
.title(title) * @param view context容器
.content(content) * @param title 标题
.inputType(InputType.TYPE_CLASS_TEXT) * @param content 内容
.input(hint, prefill, callback) * @param hint 提示
.show()) * @param prefill 预输入
); * @param callback 回调
} */
public static void showInputDialog(View view, int title, int content, String hint, String prefill, BiConsumer<MaterialDialog, CharSequence> callback) {
CommonLogic.runOnUiThread(CommonLogic.getActivityFromView(view), (activity) -> {
MaterialDialog dialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null).message(content, null, null);
dialog = DialogInputExtKt.input(dialog, hint, null, prefill, null,
InputType.TYPE_CLASS_TEXT,
null, true, false, (materialDialog, text) -> {
callback.accept(materialDialog, text);
return null;
});
DialogUtils.setCurrentDialog(dialog);
dialog.show();
});
}
/**
* 显示列表单选框
*
* @param view context容器
* @param title 标题
* @param items 列表
* @param index 默认选择
* @param callback 回调
*/
public static void showSingleChoiceDialog(View view, int title, int items, int index, BiConsumer<MaterialDialog, Integer> callback) {
CommonLogic.runOnUiThread(CommonLogic.getActivityFromView(view), (activity) -> {
MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null);
materialDialog = DialogSingleChoiceExtKt.listItemsSingleChoice(materialDialog, items, null, null, index, false, (dialog, position, text) -> {
callback.accept(dialog, position);
return null;
});
DialogUtils.setCurrentDialog(materialDialog);
materialDialog.show();
});
}
/**
* 显示列表选择框
*
* @param view context容器
* @param title 标题
* @param items 列表
* @param callback 回调
*/
public static void showListItemsDialog(View view, int title, int items, BiConsumer<MaterialDialog, Integer> callback) {
CommonLogic.runOnUiThread(CommonLogic.getActivityFromView(view), (activity) -> {
MaterialDialog materialDialog = new MaterialDialog(activity, MaterialDialog.getDEFAULT_BEHAVIOR()).title(title, null);
materialDialog = DialogListExtKt.listItems(materialDialog, items, null, null, false, (dialog, position, text) -> {
callback.accept(dialog, position);
return null;
});
DialogUtils.setCurrentDialog(materialDialog);
materialDialog.show();
});
} }
} }

View File

@ -7,6 +7,9 @@ import com.lzy.okgo.request.base.Request;
import okhttp3.Response; import okhttp3.Response;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
/**
* @author Zane
*/
public abstract class JsonCallback<T> extends AbsCallback<T> { public abstract class JsonCallback<T> extends AbsCallback<T> {
private TypeReference<T> type; private TypeReference<T> type;

View File

@ -9,7 +9,7 @@ import com.lzy.okgo.callback.StringCallback;
import com.lzy.okgo.model.Response; import com.lzy.okgo.model.Response;
import com.zane.smapiinstaller.constant.Constants; import com.zane.smapiinstaller.constant.Constants;
import com.zane.smapiinstaller.dto.GoogleTranslationDto; import com.zane.smapiinstaller.dto.GoogleTranslationDto;
import com.zane.smapiinstaller.dto.TranslationResult; import com.zane.smapiinstaller.entity.TranslationResult;
import com.zane.smapiinstaller.dto.YouDaoTranslationDto; import com.zane.smapiinstaller.dto.YouDaoTranslationDto;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:name="com.zane.smapiinstaller.ui.download.DownloadContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context=".ui.update.ModUpdateFragment"
tools:listitem="@layout/updatable_mod_list_item" />

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -52,4 +52,16 @@
android:name="com.zane.smapiinstaller.ui.about.AboutFragment" android:name="com.zane.smapiinstaller.ui.about.AboutFragment"
android:label="@string/menu_about" android:label="@string/menu_about"
tools:layout="@layout/fragment_about" /> tools:layout="@layout/fragment_about" />
<fragment
android:id="@+id/nav_mod_update"
android:name="com.zane.smapiinstaller.ui.update.ModUpdateFragment"
android:label="@string/settings_check_for_updates"
tools:layout="@layout/fragment_mod_update_list">
</fragment>
<action
android:id="@+id/action_nav_any_to_mod_update_fragment"
app:destination="@id/nav_mod_update" >
<argument android:name="updateInfoListJson" app:argType="string"/>
</action>
</navigation> </navigation>

View File

@ -9,7 +9,8 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.6.1' classpath 'com.android.tools.build:gradle:3.6.1'
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.0-alpha03" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.0-alpha04"
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong