diff --git a/app/build.gradle b/app/build.gradle index e1521e1..970055f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,8 +9,8 @@ android { applicationId "com.zane.smapiinstaller" minSdkVersion 19 targetSdkVersion 28 - versionCode 7 - versionName "1.1.3" + versionCode 8 + versionName "1.2.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true @@ -42,8 +42,8 @@ dependencies { implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'com.google.android.material:material:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'androidx.navigation:navigation-fragment:2.3.0-alpha02' - implementation 'androidx.navigation:navigation-ui:2.3.0-alpha02' + implementation 'androidx.navigation:navigation-fragment:2.3.0-alpha03' + implementation 'androidx.navigation:navigation-ui:2.3.0-alpha03' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'com.madgag.spongycastle:core:1.54.0.0' implementation 'com.madgag.spongycastle:prov:1.54.0.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2fc68f5..a69229f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,6 +11,7 @@ 兼容性查询网站确认目标Mod的兼容性以及最新版本下载地址
2.下载Mod到手机
3.通过压缩文件管理器解压Mod文件包到手机内置存储的StardewValley/Mods目录下
4.点击安装器提供的启动按钮确认新增Mod之后的环境是否正常并启动游戏" + },{ + "title": "部分常用框架包下载链接", + "author": "ZaneYork", + "content": "Content Patcher: CP前置,大部分美化包(非xnb替换类)需要的前置Mod
Space Core: SC前置,被Json Assets等Mod依赖的框架
Json Assets: JA前置,大部分新增物品类Mod需要的前置Mod
Producer Framework Mod: PFM前置,大部分新增制作配方类Mod需要的前置Mod" + } + ] +} \ No newline at end of file diff --git a/app/src/main/assets/smapi/metadata.json b/app/src/main/assets/smapi/metadata.json index 78918ba..989e7d7 100644 --- a/app/src/main/assets/smapi/metadata.json +++ b/app/src/main/assets/smapi/metadata.json @@ -158,11 +158,6 @@ "~1.1.2 | Status": "AssumeBroken" // crashes game on startup }, - "Fix Dice": { - "ID": "ashley.fixdice", - "~1.1.2 | Status": "AssumeBroken" // crashes game on startup - }, - "Grass Growth": { "ID": "bcmpinc.GrassGrowth", "~1.0 | Status": "AssumeBroken" diff --git a/app/src/main/java/com/zane/smapiinstaller/constant/Constants.java b/app/src/main/java/com/zane/smapiinstaller/constant/Constants.java index cb2592d..b5f8932 100644 --- a/app/src/main/java/com/zane/smapiinstaller/constant/Constants.java +++ b/app/src/main/java/com/zane/smapiinstaller/constant/Constants.java @@ -8,5 +8,7 @@ public class Constants { public static final String DLC_LIST_UPDATE_URL = "http://dl.zaneyork.cn/smapi/downloadable_content_list.json"; + public static final String HELP_LIST_UPDATE_URL = "http://dl.zaneyork.cn/smapi/help_item_list.json"; + public static final String APP_CENTER_SECRET = "cb44e94a-7b2f-431e-9ad9-48013ec8c208"; } diff --git a/app/src/main/java/com/zane/smapiinstaller/entity/DownloadableContentList.java b/app/src/main/java/com/zane/smapiinstaller/entity/DownloadableContentList.java index 2dbe167..743e0ee 100644 --- a/app/src/main/java/com/zane/smapiinstaller/entity/DownloadableContentList.java +++ b/app/src/main/java/com/zane/smapiinstaller/entity/DownloadableContentList.java @@ -3,9 +3,10 @@ package com.zane.smapiinstaller.entity; import java.util.List; import lombok.Data; +import lombok.EqualsAndHashCode; @Data -public class DownloadableContentList { - private int version; +@EqualsAndHashCode(callSuper = true) +public class DownloadableContentList extends UpdatableList { List contents; } diff --git a/app/src/main/java/com/zane/smapiinstaller/entity/HelpItem.java b/app/src/main/java/com/zane/smapiinstaller/entity/HelpItem.java new file mode 100644 index 0000000..0bd4d44 --- /dev/null +++ b/app/src/main/java/com/zane/smapiinstaller/entity/HelpItem.java @@ -0,0 +1,10 @@ +package com.zane.smapiinstaller.entity; + +import lombok.Data; + +@Data +public class HelpItem { + private String title; + private String content; + private String author; +} diff --git a/app/src/main/java/com/zane/smapiinstaller/entity/HelpItemList.java b/app/src/main/java/com/zane/smapiinstaller/entity/HelpItemList.java new file mode 100644 index 0000000..fd049e6 --- /dev/null +++ b/app/src/main/java/com/zane/smapiinstaller/entity/HelpItemList.java @@ -0,0 +1,12 @@ +package com.zane.smapiinstaller.entity; + +import java.util.List; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +@Data +@EqualsAndHashCode(callSuper = true) +public class HelpItemList extends UpdatableList { + private List items; +} diff --git a/app/src/main/java/com/zane/smapiinstaller/entity/UpdatableList.java b/app/src/main/java/com/zane/smapiinstaller/entity/UpdatableList.java new file mode 100644 index 0000000..b9fb782 --- /dev/null +++ b/app/src/main/java/com/zane/smapiinstaller/entity/UpdatableList.java @@ -0,0 +1,8 @@ +package com.zane.smapiinstaller.entity; + +import lombok.Data; + +@Data +public class UpdatableList { + private int version; +} diff --git a/app/src/main/java/com/zane/smapiinstaller/logic/DownloadabeContentManager.java b/app/src/main/java/com/zane/smapiinstaller/logic/DownloadabeContentManager.java deleted file mode 100644 index 8a24652..0000000 --- a/app/src/main/java/com/zane/smapiinstaller/logic/DownloadabeContentManager.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.zane.smapiinstaller.logic; - -import android.view.View; - -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.DownloadableContentList; -import com.zane.smapiinstaller.utils.FileUtils; -import com.zane.smapiinstaller.utils.JSONUtil; - -public class DownloadabeContentManager { - - private final View root; - - private static final String TAG = "DLC_MGR"; - - private static boolean updateChecked = false; - - private static DownloadableContentList downloadableContentList = null; - - public DownloadabeContentManager(View root) { - this.root = root; - downloadableContentList = FileUtils.getAssetJson(root.getContext(), "downloadable_content_list.json", DownloadableContentList.class); - if(!updateChecked) { - updateChecked = true; - OkGo.get(Constants.DLC_LIST_UPDATE_URL).execute(new StringCallback(){ - @Override - public void onSuccess(Response response) { - DownloadableContentList content = JSONUtil.fromJson(response.body(), DownloadableContentList.class); - if(content != null && downloadableContentList.getVersion() < content.getVersion()) { - FileUtils.writeAssetJson(root.getContext(), "downloadable_content_list.json", content); - downloadableContentList = content; - } - } - }); - } - } - - public DownloadableContentList getDownloadableContentList() { - return downloadableContentList; - } -} diff --git a/app/src/main/java/com/zane/smapiinstaller/logic/GameLauncher.java b/app/src/main/java/com/zane/smapiinstaller/logic/GameLauncher.java index 5725b7c..42a6801 100644 --- a/app/src/main/java/com/zane/smapiinstaller/logic/GameLauncher.java +++ b/app/src/main/java/com/zane/smapiinstaller/logic/GameLauncher.java @@ -6,6 +6,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.view.View; +import com.microsoft.appcenter.crashes.Crashes; import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.constant.Constants; @@ -35,6 +36,9 @@ public class GameLauncher { }); } catch (PackageManager.NameNotFoundException ignored) { CommonLogic.showAlertDialog(root, R.string.error, R.string.error_smapi_not_installed); + } catch (Exception e) { + Crashes.trackError(e); + CommonLogic.showAlertDialog(root, R.string.error, e.getLocalizedMessage()); } } } diff --git a/app/src/main/java/com/zane/smapiinstaller/logic/ModAssetsManager.java b/app/src/main/java/com/zane/smapiinstaller/logic/ModAssetsManager.java index 8a43712..b4dd4cf 100644 --- a/app/src/main/java/com/zane/smapiinstaller/logic/ModAssetsManager.java +++ b/app/src/main/java/com/zane/smapiinstaller/logic/ModAssetsManager.java @@ -78,19 +78,25 @@ public class ModAssetsManager { File currentFile = files.poll(); if (currentFile != null && currentFile.exists()) { boolean foundManifest = false; - for (File file : currentFile.listFiles(File::isFile)) { - if (StringUtils.equalsIgnoreCase(file.getName(), "manifest.json")) { - ModManifestEntry manifest = FileUtils.getFileJson(file, ModManifestEntry.class); - foundManifest = true; - if (manifest != null) { - manifest.setAssetPath(file.getParentFile().getAbsolutePath()); - mods.add(manifest); + File[] listFiles = currentFile.listFiles(File::isFile); + 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())) { + manifest.setAssetPath(file.getParentFile().getAbsolutePath()); + mods.add(manifest); + } + break; } - break; } } if (!foundManifest) { - files.addAll(Lists.newArrayList(currentFile.listFiles(File::isDirectory))); + File[] listDirectories = currentFile.listFiles(File::isDirectory); + if(listDirectories != null) { + files.addAll(Lists.newArrayList(listDirectories)); + } } } } while (!files.isEmpty()); diff --git a/app/src/main/java/com/zane/smapiinstaller/logic/UpdatableListManager.java b/app/src/main/java/com/zane/smapiinstaller/logic/UpdatableListManager.java new file mode 100644 index 0000000..fd58259 --- /dev/null +++ b/app/src/main/java/com/zane/smapiinstaller/logic/UpdatableListManager.java @@ -0,0 +1,50 @@ +package com.zane.smapiinstaller.logic; + +import android.view.View; + +import com.google.common.base.Predicate; +import com.lzy.okgo.OkGo; +import com.lzy.okgo.callback.StringCallback; +import com.lzy.okgo.model.Response; +import com.zane.smapiinstaller.entity.UpdatableList; +import com.zane.smapiinstaller.utils.FileUtils; +import com.zane.smapiinstaller.utils.JSONUtil; + +import java.util.ArrayList; +import java.util.List; + +public class UpdatableListManager { + private static boolean updateChecked = false; + + private static UpdatableList updatableList = null; + + private List> onChangedListener = new ArrayList<>(); + + public UpdatableListManager(View root, String filename, Class tClass, String updateUrl) { + updatableList = FileUtils.getAssetJson(root.getContext(), filename, tClass); + if(!updateChecked) { + updateChecked = true; + OkGo.get(updateUrl).execute(new StringCallback(){ + @Override + public void onSuccess(Response response) { + UpdatableList content = JSONUtil.fromJson(response.body(), tClass); + if(content != null && updatableList.getVersion() < content.getVersion()) { + FileUtils.writeAssetJson(root.getContext(), filename, content); + updatableList = content; + for (Predicate listener : onChangedListener) { + listener.apply(getList()); + } + } + } + }); + } + } + + public T getList() { + return (T) updatableList; + } + + public void registerListChangeListener(Predicate onChanged) { + this.onChangedListener.add(onChanged); + } +} diff --git a/app/src/main/java/com/zane/smapiinstaller/ui/download/DownloadableContentAdapter.java b/app/src/main/java/com/zane/smapiinstaller/ui/download/DownloadableContentAdapter.java index a294458..c617891 100644 --- a/app/src/main/java/com/zane/smapiinstaller/ui/download/DownloadableContentAdapter.java +++ b/app/src/main/java/com/zane/smapiinstaller/ui/download/DownloadableContentAdapter.java @@ -39,7 +39,12 @@ import java.util.concurrent.atomic.AtomicReference; */ public class DownloadableContentAdapter extends RecyclerView.Adapter { - private final List downloadableContentList; + private List downloadableContentList; + + public void setDownloadableContentList(List downloadableContentList) { + this.downloadableContentList = downloadableContentList; + notifyDataSetChanged(); + } public DownloadableContentAdapter(List items) { downloadableContentList = items; @@ -62,7 +67,7 @@ public class DownloadableContentAdapter extends RecyclerView.Adapter 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) -> { + adapter.setDownloadableContentList(list.getContents()); + return true; + }); recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL)); } return view; diff --git a/app/src/main/java/com/zane/smapiinstaller/ui/help/HelpFragment.java b/app/src/main/java/com/zane/smapiinstaller/ui/help/HelpFragment.java index defef85..e0f2c89 100644 --- a/app/src/main/java/com/zane/smapiinstaller/ui/help/HelpFragment.java +++ b/app/src/main/java/com/zane/smapiinstaller/ui/help/HelpFragment.java @@ -8,7 +8,9 @@ import android.view.ViewGroup; import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.constant.Constants; +import com.zane.smapiinstaller.entity.HelpItemList; import com.zane.smapiinstaller.logic.CommonLogic; +import com.zane.smapiinstaller.logic.UpdatableListManager; import java.io.File; @@ -16,15 +18,31 @@ import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.navigation.NavController; import androidx.navigation.Navigation; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; public class HelpFragment extends Fragment { + @BindView(R.id.view_help_list) + RecyclerView recyclerView; + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_help, container, false); ButterKnife.bind(this, root); + recyclerView.setLayoutManager(new LinearLayoutManager(this.getContext())); + UpdatableListManager 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) -> { + adapter.setHelpItems(list.getItems()); + return true; + }); + recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL)); return root; } @OnClick(R.id.button_compat) void compat() { diff --git a/app/src/main/java/com/zane/smapiinstaller/ui/help/HelpItemAdapter.java b/app/src/main/java/com/zane/smapiinstaller/ui/help/HelpItemAdapter.java new file mode 100644 index 0000000..4403ac8 --- /dev/null +++ b/app/src/main/java/com/zane/smapiinstaller/ui/help/HelpItemAdapter.java @@ -0,0 +1,70 @@ +package com.zane.smapiinstaller.ui.help; + +import android.text.Html; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.zane.smapiinstaller.R; +import com.zane.smapiinstaller.entity.HelpItem; + +import java.util.List; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import butterknife.BindView; +import butterknife.ButterKnife; + +public class HelpItemAdapter extends RecyclerView.Adapter { + + public void setHelpItems(List helpItems) { + this.helpItems = helpItems; + notifyDataSetChanged(); + } + + private List helpItems; + + public HelpItemAdapter(List helpItems) { + this.helpItems = helpItems; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.help_list_item, parent, false); + return new ViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + holder.setHelpItem(helpItems.get(position)); + } + + @Override + public int getItemCount() { + return helpItems.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.text_item_title) + TextView textTitle; + @BindView(R.id.text_item_author) + TextView textAuthor; + @BindView(R.id.text_item_content) + TextView textContent; + + public ViewHolder(View view) { + super(view); + ButterKnife.bind(this, itemView); + } + void setHelpItem(HelpItem item) { + textTitle.setText(item.getTitle()); + textAuthor.setText(item.getAuthor()); + textContent.setText(Html.fromHtml(item.getContent())); + textContent.setMovementMethod(LinkMovementMethod.getInstance()); + } + } +} diff --git a/app/src/main/java/com/zane/smapiinstaller/ui/install/InstallFragment.java b/app/src/main/java/com/zane/smapiinstaller/ui/install/InstallFragment.java index 763f15b..2dae933 100644 --- a/app/src/main/java/com/zane/smapiinstaller/ui/install/InstallFragment.java +++ b/app/src/main/java/com/zane/smapiinstaller/ui/install/InstallFragment.java @@ -10,6 +10,8 @@ import android.view.ViewGroup; import com.afollestad.materialdialogs.DialogAction; import com.afollestad.materialdialogs.GravityEnum; import com.afollestad.materialdialogs.MaterialDialog; +import com.microsoft.appcenter.AppCenter; +import com.microsoft.appcenter.crashes.Crashes; import com.zane.smapiinstaller.R; import com.zane.smapiinstaller.logic.ApkPatcher; import com.zane.smapiinstaller.logic.CommonLogic; @@ -42,12 +44,11 @@ public class InstallFragment extends Fragment { void Install() { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { CommonLogic.showConfirmDialog(root, R.string.confirm, R.string.android_version_confirm, ((dialog, which) -> { - if(which == DialogAction.POSITIVE) { + if (which == DialogAction.POSITIVE) { installLogic(); } })); - } - else { + } else { installLogic(); } } @@ -95,7 +96,12 @@ public class InstallFragment extends Fragment { patcher.install(signPath); dialog.incrementProgress(1); - } finally { + } + catch (Exception e) { + Crashes.trackError(e); + CommonLogic.showAlertDialog(root, R.string.error, e.getLocalizedMessage()); + } + finally { if (!dialog.isCancelled()) { dialog.dismiss(); } diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml index 449c32d..fa94441 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/fragment_about.xml @@ -74,7 +74,7 @@ app:layout_constraintStart_toStartOf="parent" app:srcCompat="@drawable/ic_menu_share" android:contentDescription="@string/icon_desc" /> - diff --git a/app/src/main/res/layout/fragment_config.xml b/app/src/main/res/layout/fragment_config.xml index 490382d..a5d3336 100644 --- a/app/src/main/res/layout/fragment_config.xml +++ b/app/src/main/res/layout/fragment_config.xml @@ -8,6 +8,7 @@ diff --git a/app/src/main/res/layout/fragment_help.xml b/app/src/main/res/layout/fragment_help.xml index 17d535b..a918fad 100644 --- a/app/src/main/res/layout/fragment_help.xml +++ b/app/src/main/res/layout/fragment_help.xml @@ -30,6 +30,15 @@ app:layout_constraintTop_toBottomOf="@id/guideline_h1" app:layout_constraintStart_toEndOf="@id/button_nexus" /> + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/help_list_item.xml b/app/src/main/res/layout/help_list_item.xml new file mode 100644 index 0000000..0bb3ff1 --- /dev/null +++ b/app/src/main/res/layout/help_list_item.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 8588dff..ed31801 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -1,7 +1,5 @@ SMAPI安裝器 - Open navigation drawer - Close navigation drawer SMAPI安裝器 ZaneYork@qq.com 設置 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 8588dff..ed31801 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1,7 +1,5 @@ SMAPI安裝器 - Open navigation drawer - Close navigation drawer SMAPI安裝器 ZaneYork@qq.com 設置 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index ed36576..f5f5fe7 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -1,7 +1,5 @@ SMAPI安装器 - Open navigation drawer - Close navigation drawer SMAPI安装器 ZaneYork@qq.com 设置 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 030098f..8423202 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -3,4 +3,5 @@ #6200EE #3700B3 #03DAC5 + #8BD diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 683ca25..73d341e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,5 @@ SMAPI Installer - Open navigation drawer - Close navigation drawer SMAPI Installer ZaneYork@qq.com Settings diff --git a/app/src/main/res/xml/appcenter_backup_rule.xml b/app/src/main/res/xml/appcenter_backup_rule.xml new file mode 100644 index 0000000..b76e607 --- /dev/null +++ b/app/src/main/res/xml/appcenter_backup_rule.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file