[app] Show upgradable modules on front page (#1365)

This commit is contained in:
LoveSy 2021-11-07 23:44:52 +08:00 committed by GitHub
parent 1f522ef4ef
commit 0a83d165b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 14 deletions

View File

@ -21,7 +21,6 @@
package org.lsposed.manager.repo; package org.lsposed.manager.repo;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -52,7 +51,21 @@ import okhttp3.ResponseBody;
public class RepoLoader { public class RepoLoader {
private static RepoLoader instance = null; private static RepoLoader instance = null;
private Map<String, OnlineModule> onlineModules = new HashMap<>(); private Map<String, OnlineModule> onlineModules = new HashMap<>();
private final Map<String, Pair<Integer, String>> latestVersion = new ConcurrentHashMap<>();
public static class ModuleVersion {
public String versionName;
public long versionCode;
private ModuleVersion(long versionCode, String versionName) {
this.versionName = versionName;
this.versionCode = versionCode;
}
public boolean upgradable(long versionCode, String versionName) {
return this.versionCode > versionCode || (this.versionCode == versionCode && !versionName.equals(this.versionName));
}
}
private final Map<String, ModuleVersion> latestVersion = new ConcurrentHashMap<>();
private final Path repoFile = Paths.get(App.getInstance().getFilesDir().getAbsolutePath(), "repo.json"); private final Path repoFile = Paths.get(App.getInstance().getFilesDir().getAbsolutePath(), "repo.json");
private final List<Listener> listeners = new CopyOnWriteArrayList<>(); private final List<Listener> listeners = new CopyOnWriteArrayList<>();
private boolean isLoading = false; private boolean isLoading = false;
@ -116,16 +129,16 @@ public class RepoLoader {
if (release == null || release.isEmpty()) continue; if (release == null || release.isEmpty()) continue;
var splits = release.split("-", 2); var splits = release.split("-", 2);
if (splits.length < 2) continue; if (splits.length < 2) continue;
int verCode; long verCode;
String verName; String verName;
try { try {
verCode = Integer.parseInt(splits[0]); verCode = Long.parseLong(splits[0]);
verName = splits[1]; verName = splits[1];
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
continue; continue;
} }
String pkgName = module.getName(); String pkgName = module.getName();
latestVersion.put(pkgName, new Pair<>(verCode, verName)); latestVersion.put(pkgName, new ModuleVersion(verCode, verName));
} }
onlineModules = modules; onlineModules = modules;
@ -151,7 +164,7 @@ public class RepoLoader {
}); });
} }
public Pair<Integer, String> getModuleLatestVersion(String packageName) { public ModuleVersion getModuleLatestVersion(String packageName) {
return latestVersion.get(packageName); return latestVersion.get(packageName);
} }

View File

@ -40,6 +40,7 @@ import org.lsposed.manager.ConfigManager;
import org.lsposed.manager.R; import org.lsposed.manager.R;
import org.lsposed.manager.databinding.DialogAboutBinding; import org.lsposed.manager.databinding.DialogAboutBinding;
import org.lsposed.manager.databinding.FragmentHomeBinding; import org.lsposed.manager.databinding.FragmentHomeBinding;
import org.lsposed.manager.repo.RepoLoader;
import org.lsposed.manager.ui.dialog.BlurBehindDialogBuilder; import org.lsposed.manager.ui.dialog.BlurBehindDialogBuilder;
import org.lsposed.manager.ui.dialog.FlashDialogBuilder; import org.lsposed.manager.ui.dialog.FlashDialogBuilder;
import org.lsposed.manager.ui.dialog.InfoDialogBuilder; import org.lsposed.manager.ui.dialog.InfoDialogBuilder;
@ -50,14 +51,17 @@ import org.lsposed.manager.util.NavUtil;
import org.lsposed.manager.util.UpdateUtil; import org.lsposed.manager.util.UpdateUtil;
import org.lsposed.manager.util.chrome.LinkTransformationMethod; import org.lsposed.manager.util.chrome.LinkTransformationMethod;
import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import rikka.core.util.ResourceUtils; import rikka.core.util.ResourceUtils;
public class HomeFragment extends BaseFragment { public class HomeFragment extends BaseFragment implements RepoLoader.Listener {
private FragmentHomeBinding binding; private FragmentHomeBinding binding;
private static final RepoLoader repoLoader = RepoLoader.getInstance();
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -103,6 +107,11 @@ public class HomeFragment extends BaseFragment {
binding.issue.setOnClickListener(view -> NavUtil.startURL(activity, "https://github.com/LSPosed/LSPosed/issues")); binding.issue.setOnClickListener(view -> NavUtil.startURL(activity, "https://github.com/LSPosed/LSPosed/issues"));
updateStates(requireActivity(), ConfigManager.isBinderAlive(), UpdateUtil.needUpdate()); updateStates(requireActivity(), ConfigManager.isBinderAlive(), UpdateUtil.needUpdate());
repoLoader.addListener(this);
if (repoLoader.isRepoLoaded()) {
repoLoaded();
}
return binding.getRoot(); return binding.getRoot();
} }
@ -185,6 +194,34 @@ public class HomeFragment extends BaseFragment {
} }
} }
@Override
public void repoLoaded() {
final int[] count = new int[]{0};
HashSet<String> processedModules = new HashSet<>();
ModuleUtil.getInstance().getModules().forEach((k, v) -> {
if (!processedModules.contains(k.first)) {
var ver = repoLoader.getModuleLatestVersion(k.first);
if (ver != null && ver.upgradable(v.versionCode, v.versionName)) {
++count[0];
}
processedModules.add(k.first);
}
}
);
runOnUiThread(() -> {
if (count[0] > 0) {
binding.downloadSummary.setText(getResources().getQuantityString(R.plurals.module_repo_upgradable, count[0], count[0]));
} else {
onThrowable(null);
}
});
}
@Override
public void onThrowable(Throwable t) {
runOnUiThread(() -> binding.downloadSummary.setText(getResources().getString(R.string.module_repo_up_to_date)));
}
private class StartFragmentListener implements View.OnClickListener { private class StartFragmentListener implements View.OnClickListener {
boolean requireInstalled; boolean requireInstalled;
int fragment; int fragment;
@ -219,7 +256,7 @@ public class HomeFragment extends BaseFragment {
@Override @Override
public void onDestroyView() { public void onDestroyView() {
super.onDestroyView(); super.onDestroyView();
repoLoader.removeListener(this);
binding = null; binding = null;
} }
} }

View File

@ -473,9 +473,9 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi
} }
if (repoLoader.isRepoLoaded()) { if (repoLoader.isRepoLoaded()) {
var ver = repoLoader.getModuleLatestVersion(item.packageName); var ver = repoLoader.getModuleLatestVersion(item.packageName);
if (ver != null && ver.first > item.versionCode) { if (ver != null && ver.upgradable(item.versionCode, item.versionName)) {
if (warningText != null) sb.append("\n"); if (warningText != null) sb.append("\n");
String recommended = getString(R.string.update_available, ver.second); String recommended = getString(R.string.update_available, ver.versionName);
sb.append(recommended); sb.append(recommended);
final ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(ResourceUtils.resolveColor(requireActivity().getTheme(), androidx.appcompat.R.attr.colorAccent)); final ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(ResourceUtils.resolveColor(requireActivity().getTheme(), androidx.appcompat.R.attr.colorAccent));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {

View File

@ -205,9 +205,9 @@ public class RepoFragment extends BaseFragment implements RepoLoader.Listener {
ModuleUtil.InstalledModule installedModule = ModuleUtil.getInstance().getModule(module.getName()); ModuleUtil.InstalledModule installedModule = ModuleUtil.getInstance().getModule(module.getName());
if (installedModule != null) { if (installedModule != null) {
var ver = repoLoader.getModuleLatestVersion(installedModule.packageName); var ver = repoLoader.getModuleLatestVersion(installedModule.packageName);
if (ver != null && ver.first > installedModule.versionCode) { if (ver != null && ver.upgradable(installedModule.versionCode, installedModule.versionName)) {
sb.append("\n"); sb.append("\n");
String recommended = getString(R.string.update_available, ver.second); String recommended = getString(R.string.update_available, ver.versionName);
sb.append(recommended); sb.append(recommended);
final ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(ResourceUtils.resolveColor(requireActivity().getTheme(), androidx.appcompat.R.attr.colorAccent)); final ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(ResourceUtils.resolveColor(requireActivity().getTheme(), androidx.appcompat.R.attr.colorAccent));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {

View File

@ -186,7 +186,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/download_title" android:layout_below="@id/download_title"
android:layout_alignStart="@id/download_title" android:layout_alignStart="@id/download_title"
android:text="@string/module_repo_summary" android:text="@string/module_repo_loading"
android:textAppearance="?android:attr/textAppearanceSmall" /> android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout> </RelativeLayout>
</com.google.android.material.card.MaterialCardView> </com.google.android.material.card.MaterialCardView>

View File

@ -31,7 +31,12 @@
<string name="About">About</string> <string name="About">About</string>
<string name="report_issue">Report issue</string> <string name="report_issue">Report issue</string>
<string name="module_repo">Repository</string> <string name="module_repo">Repository</string>
<string name="module_repo_summary">Module repository (Beta)</string> <string name="module_repo_loading">Loading…</string>
<string name="module_repo_up_to_date">All modules up to date</string>
<plurals name="module_repo_upgradable">
<item quantity="one">%d module upgradable</item>
<item quantity="other">%d modules upgradable</item>
</plurals>
<string name="about_view_source_code"><![CDATA[View source code at %1$s<br/>Join our %2$s channel]]></string> <string name="about_view_source_code"><![CDATA[View source code at %1$s<br/>Join our %2$s channel]]></string>
<string name="translators" comment="Dear translators, please add your home page here following the format. There can be more than one translator. So feel free to append yourself.">null</string> <string name="translators" comment="Dear translators, please add your home page here following the format. There can be more than one translator. So feel free to append yourself.">null</string>