[app] Show upgradable modules on front page (#1365)
This commit is contained in:
parent
1f522ef4ef
commit
0a83d165b7
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue