diff --git a/app/src/main/java/org/lsposed/manager/repo/RepoLoader.java b/app/src/main/java/org/lsposed/manager/repo/RepoLoader.java index 5fa2d857..00aacb8a 100644 --- a/app/src/main/java/org/lsposed/manager/repo/RepoLoader.java +++ b/app/src/main/java/org/lsposed/manager/repo/RepoLoader.java @@ -184,6 +184,8 @@ public class RepoLoader { default void moduleReleasesLoaded(OnlineModule module) { } - void onThrowable(Throwable t); + default void onThrowable(Throwable t) { + Log.e(App.TAG, "load repo failed", t); + } } } diff --git a/app/src/main/java/org/lsposed/manager/repo/model/OnlineModule.java b/app/src/main/java/org/lsposed/manager/repo/model/OnlineModule.java index 77df5ecb..f1892b21 100644 --- a/app/src/main/java/org/lsposed/manager/repo/model/OnlineModule.java +++ b/app/src/main/java/org/lsposed/manager/repo/model/OnlineModule.java @@ -47,6 +47,9 @@ public class OnlineModule implements Serializable, Parcelable { @SerializedName("collaborators") @Expose private List collaborators = new ArrayList<>(); + @SerializedName("latestRelease") + @Expose + private String latestRelease; @SerializedName("releases") @Expose private List releases = new ArrayList<>(); @@ -111,6 +114,7 @@ public class OnlineModule implements Serializable, Parcelable { this.createdAt = ((String) in.readValue((String.class.getClassLoader()))); this.stargazerCount = ((Integer) in.readValue((Integer.class.getClassLoader()))); this.readmeHTML = ((String) in.readValue((String.class.getClassLoader()))); + this.latestRelease = ((String) in.readValue((String.class.getClassLoader()))); } public OnlineModule() { @@ -262,10 +266,18 @@ public class OnlineModule implements Serializable, Parcelable { dest.writeValue(createdAt); dest.writeValue(stargazerCount); dest.writeValue(readmeHTML); + dest.writeValue(latestRelease); } public int describeContents() { return 0; } + public String getLatestRelease() { + return latestRelease; + } + + public void setLatestRelease(String latestRelease) { + this.latestRelease = latestRelease; + } } diff --git a/app/src/main/java/org/lsposed/manager/ui/fragment/ModulesFragment.java b/app/src/main/java/org/lsposed/manager/ui/fragment/ModulesFragment.java index d303df52..8e86b36f 100644 --- a/app/src/main/java/org/lsposed/manager/ui/fragment/ModulesFragment.java +++ b/app/src/main/java/org/lsposed/manager/ui/fragment/ModulesFragment.java @@ -20,7 +20,6 @@ package org.lsposed.manager.ui.fragment; import static android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS; - import static androidx.recyclerview.widget.RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY; import android.annotation.SuppressLint; @@ -40,6 +39,7 @@ import android.text.TextUtils; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.text.style.TypefaceSpan; +import android.util.Pair; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -87,6 +87,8 @@ import org.lsposed.manager.util.ModuleUtil; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -96,8 +98,7 @@ import rikka.insets.WindowInsetsHelperKt; import rikka.recyclerview.RecyclerViewKt; import rikka.widget.borderview.BorderRecyclerView; -public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleListener { - +public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleListener, RepoLoader.Listener { private static final Handler workHandler; private static final PackageManager pm = App.getInstance().getPackageManager(); private static final ModuleUtil moduleUtil = ModuleUtil.getInstance(); @@ -108,6 +109,8 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi private final ArrayList adapters = new ArrayList<>(); private final ArrayList tabTitles = new ArrayList<>(); + private final Map> latestVersion = new ConcurrentHashMap<>(); + private ModuleUtil.InstalledModule selectedModule; static { @@ -133,6 +136,8 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi return false; } }; + RepoLoader.getInstance().addListener(this); + repoLoaded(); } @Nullable @@ -339,6 +344,28 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi binding = null; } + @Override + synchronized public void repoLoaded() { + latestVersion.clear(); + for (var module : RepoLoader.getInstance().getOnlineModules()) { + var release = module.getLatestRelease(); + if (release == null || release.isEmpty()) continue; + var splits = release.split("-", 2); + if (splits.length < 2) continue; + int verCode; + String verName; + try { + verCode = Integer.parseInt(splits[0]); + verName = splits[1]; + } catch (NumberFormatException ignored) { + continue; + } + String pkgName = module.getName(); + latestVersion.put(pkgName, new Pair<>(verCode, verName)); + } + adapters.forEach(ModuleAdapter::notifyDataSetChanged); + } + public static class ModuleListFragment extends Fragment { @Nullable @Override @@ -487,6 +514,24 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi } sb.setSpan(foregroundColorSpan, sb.length() - warningText.length(), sb.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); } + + if (latestVersion.containsKey(item.packageName)) { + var ver = latestVersion.get(item.packageName); + if (ver != null && ver.first > item.versionCode) { + sb.append("\n"); + String recommended = getString(R.string.update_available, ver.second); + sb.append(recommended); + final ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(ResourcesKt.resolveColor(requireActivity().getTheme(), R.attr.colorAccent)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + final TypefaceSpan typefaceSpan = new TypefaceSpan(Typeface.create("sans-serif-medium", Typeface.NORMAL)); + sb.setSpan(typefaceSpan, sb.length() - recommended.length(), sb.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); + } else { + final StyleSpan styleSpan = new StyleSpan(Typeface.BOLD); + sb.setSpan(styleSpan, sb.length() - recommended.length(), sb.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); + } + sb.setSpan(foregroundColorSpan, sb.length() - recommended.length(), sb.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); + } + } holder.appDescription.setText(sb); if (!isPick) { diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 534a3ad6..7d4fb8c2 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -138,7 +138,7 @@ Wiederherstellen %s wurde aktualisiert Module Repo - Modul-Repository (Alpha) + Modul-Repository (Beta) Liesmich Veröffentlichungen Info diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index f339a249..977c2bb5 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -32,7 +32,7 @@ Configuración Acerca de Repositorio - Repositorio de módulos (alpha) + Repositorio de módulos (Beta) Únete a nuestro %2$s canal]]> Traductores: %s diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8ed99397..9b60c89d 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -32,7 +32,7 @@ Réglages A propos Dépôt - Dépôts de modules (Alpha) + Dépôts de modules (Beta) Rejoindre notre canal %2$s]]> Traducteur: %s diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index d25d8e7e..ed037594 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -32,7 +32,7 @@ Impostazioni Informazioni Repository - Repository moduli (Alpha) + Repository moduli (Beta) Unisciti al nostro canale %2$s]]> Traduttori: %s diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 7bd0d4ad..b8fbd2df 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -32,7 +32,7 @@ 설정 About 저장소 - 모듈 저장소 (Alpha) + 모듈 저장소 (Beta) %2$s 채널에 가입하십시오.]]> 번역가: %s diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 3706fa4c..eed4304f 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -32,7 +32,7 @@ Instellingen Over Opslagplaats - Module opslagplaats (Alpha) + Module opslagplaats (Beta) Sluit je aan bij onze %2$s kanaal]]> Vertaler: %1$s diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index ae615564..0d021a9c 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -32,7 +32,7 @@ Configurações Sobre Repositório - Repositório de Módulos (Alpha) + Repositório de Módulos (Beta) Entre em nosso canal no %2$s]]> Tradutor: %s diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 0f8ab619..0672d17c 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -138,7 +138,7 @@ Восстановить %s обновлён Репозиторий - Репозиторий модулей (Альфа) + Репозиторий модулей (Бета) Readme Релизаты Информация diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 85af6f02..13618941 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -102,7 +102,7 @@ Цей модуль вимагає новішої версії LSP (%d), тому його неможливо активувати Модуль LSPosed оновлено Репозиторій - Репозиторій модулів + Репозиторій модулів (Бета) Readme Релізи Інформація diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index b8ab3e29..3117747f 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -32,7 +32,7 @@ 设置 关于 仓库 - 模块仓库(Alpha) + 模块仓库(Beta) 加入我们的 %2$s 频道]]> 译者:%s @@ -122,6 +122,7 @@ 未选择任何应用。选择推荐的应用? 选择推荐的应用? 推荐的应用 + 可用更新:%1$s 由于未选择任何应用,模块 %s 已被禁用。 系统框架 备份… diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index d47aa0af..eae4acd8 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -32,7 +32,7 @@ 設置 關於 倉庫 - 模組倉庫(Alpha) + 模組倉庫(Beta) 加入我們的 %2$s 頻道]]> Translators: %s diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index eec27aae..dc37d2d4 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -32,7 +32,7 @@ 設定 關於 倉庫 - 模組倉庫(Alpha) + 模組倉庫(Beta) 加入我們的 %2$s 頻道]]> 翻譯者:%s diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c76256e6..d7e30f90 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -32,7 +32,7 @@ Settings About Repository - Module repository (Alpha) + Module repository (Beta) Join our %2$s channel]]> Translators: %s @@ -122,6 +122,7 @@ You did not select any app. Select recommended apps? Select recommended apps? Recommended + Update available: %1$s Module %s has been disabled since no app selected. System Framework Backup…