diff --git a/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java b/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java index ae4af5e5..481f3ef4 100644 --- a/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java +++ b/app/src/main/java/org/lsposed/manager/adapters/ScopeAdapter.java @@ -35,14 +35,12 @@ import android.net.Uri; import android.os.Build; import android.os.Handler; import android.os.HandlerThread; -import android.os.Message; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; import android.text.style.TypefaceSpan; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -91,12 +89,13 @@ import rikka.core.res.ResourcesKt; import rikka.widget.switchbar.SwitchBar; @SuppressLint("NotifyDataSetChanged") -public class ScopeAdapter extends RecyclerView.Adapter implements Filterable, Handler.Callback { +public class ScopeAdapter extends RecyclerView.Adapter implements Filterable { private final Activity activity; private final AppListFragment fragment; private final PackageManager pm; private final SharedPreferences preferences; + private final HandlerThread handlerThread = new HandlerThread("appList"); private final Handler loadAppListHandler; private final ModuleUtil moduleUtil; @@ -143,9 +142,8 @@ public class ScopeAdapter extends RecyclerView.Adapter this.activity = fragment.requireActivity(); this.module = module; moduleUtil = ModuleUtil.getInstance(); - HandlerThread handlerThread = new HandlerThread("appList"); handlerThread.start(); - loadAppListHandler = new Handler(handlerThread.getLooper(), this); + loadAppListHandler = new Handler(handlerThread.getLooper()); preferences = App.getPreferences(); pm = activity.getPackageManager(); } @@ -269,7 +267,7 @@ public class ScopeAdapter extends RecyclerView.Adapter } else if (!AppHelper.onOptionsItemSelected(item, preferences)) { return false; } - refresh(false); + refresh(); return true; } @@ -444,52 +442,27 @@ public class ScopeAdapter extends RecyclerView.Adapter return showList.size(); } - public void refresh(boolean force) { + public void onDestroy() { + loadAppListHandler.removeCallbacksAndMessages(null); + handlerThread.quit(); + } + + public void refresh() { synchronized (this) { if (refreshing) { return; } refreshing = true; } - loadAppListHandler.removeMessages(0); - if (!force) { - fragment.binding.progress.setIndeterminate(true); - } + loadAppListHandler.removeCallbacksAndMessages(null); + boolean force = fragment.binding.swipeRefreshLayout.isRefreshing(); + if (!force) fragment.binding.progress.setIndeterminate(true); enabled = moduleUtil.isModuleEnabled(module.packageName); fragment.binding.masterSwitch.setOnCheckedChangeListener(null); fragment.binding.masterSwitch.setChecked(enabled); fragment.binding.masterSwitch.setOnCheckedChangeListener(switchBarOnCheckedChangeListener); - loadAppListHandler.sendMessage(Message.obtain(loadAppListHandler, 0, force)); - } - - protected void onCheckedChange(CompoundButton buttonView, boolean isChecked, AppInfo appInfo) { - if (isChecked) { - checkedList.add(appInfo.application); - } else { - checkedList.remove(appInfo.application); - } - if (!ConfigManager.setModuleScope(module.packageName, checkedList)) { - Snackbar.make(fragment.binding.snackbar, R.string.failed_to_save_scope_list, Snackbar.LENGTH_SHORT).show(); - if (!isChecked) { - checkedList.add(appInfo.application); - } else { - checkedList.remove(appInfo.application); - } - buttonView.setChecked(!isChecked); - } else if (appInfo.packageName.equals("android")) { - Snackbar.make(fragment.binding.snackbar, R.string.reboot_required, Snackbar.LENGTH_SHORT) - .setAction(R.string.reboot, v -> ConfigManager.reboot(false)) - .show(); - } - } - - @Override - public boolean handleMessage(@NonNull Message msg) { - if (msg.what != 0) { - return false; - } - try { - List appList = AppHelper.getAppList((Boolean) msg.obj); + loadAppListHandler.post(() -> { + List appList = AppHelper.getAppList(force); checkedList.clear(); recommendedList.clear(); var tmpList = new ArrayList(); @@ -543,12 +516,33 @@ public class ScopeAdapter extends RecyclerView.Adapter refreshing = false; } activity.runOnUiThread(dataReadyRunnable); - dataReadyRunnable.wait(); + try { + dataReadyRunnable.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } } - return true; - } catch (Exception e) { - Log.e(App.TAG, Log.getStackTraceString(e)); - return false; + }); + } + + protected void onCheckedChange(CompoundButton buttonView, boolean isChecked, AppInfo appInfo) { + if (isChecked) { + checkedList.add(appInfo.application); + } else { + checkedList.remove(appInfo.application); + } + if (!ConfigManager.setModuleScope(module.packageName, checkedList)) { + Snackbar.make(fragment.binding.snackbar, R.string.failed_to_save_scope_list, Snackbar.LENGTH_SHORT).show(); + if (!isChecked) { + checkedList.add(appInfo.application); + } else { + checkedList.remove(appInfo.application); + } + buttonView.setChecked(!isChecked); + } else if (appInfo.packageName.equals("android")) { + Snackbar.make(fragment.binding.snackbar, R.string.reboot_required, Snackbar.LENGTH_SHORT) + .setAction(R.string.reboot, v -> ConfigManager.reboot(false)) + .show(); } } @@ -609,13 +603,13 @@ public class ScopeAdapter extends RecyclerView.Adapter return new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { - refresh(false); + refresh(); return true; } @Override public boolean onQueryTextChange(String newText) { - refresh(false); + refresh(); return true; } }; 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 f27a0449..1f26865b 100644 --- a/app/src/main/java/org/lsposed/manager/repo/RepoLoader.java +++ b/app/src/main/java/org/lsposed/manager/repo/RepoLoader.java @@ -21,6 +21,7 @@ package org.lsposed.manager.repo; import android.util.Log; +import android.util.Pair; import androidx.annotation.NonNull; @@ -39,6 +40,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import okhttp3.Call; @@ -50,6 +52,7 @@ import okhttp3.ResponseBody; public class RepoLoader { private static RepoLoader instance = null; private Map onlineModules = new HashMap<>(); + private final Map> latestVersion = new ConcurrentHashMap<>(); private final Path repoFile = Paths.get(App.getInstance().getFilesDir().getAbsolutePath(), "repo.json"); private final List listeners = new CopyOnWriteArrayList<>(); private boolean isLoading = false; @@ -106,6 +109,25 @@ public class RepoLoader { Map modules = new HashMap<>(); OnlineModule[] repoModules = gson.fromJson(bodyString, OnlineModule[].class); Arrays.stream(repoModules).forEach(onlineModule -> modules.put(onlineModule.getName(), onlineModule)); + + latestVersion.clear(); + for (var module : repoModules) { + 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)); + } + onlineModules = modules; Files.write(repoFile, bodyString.getBytes(StandardCharsets.UTF_8)); for (Listener listener : listeners) { @@ -129,6 +151,10 @@ public class RepoLoader { }); } + public Pair getModuleLatestVersion(String packageName) { + return latestVersion.get(packageName); + } + public void loadRemoteReleases(String packageName) { App.getOkHttpClient().newCall(new Request.Builder() .url(String.format(repoUrl + "module/%s.json", packageName)) diff --git a/app/src/main/java/org/lsposed/manager/ui/fragment/AppListFragment.java b/app/src/main/java/org/lsposed/manager/ui/fragment/AppListFragment.java index 387b75a1..4b8b8328 100644 --- a/app/src/main/java/org/lsposed/manager/ui/fragment/AppListFragment.java +++ b/app/src/main/java/org/lsposed/manager/ui/fragment/AppListFragment.java @@ -81,7 +81,7 @@ public class AppListFragment extends BaseFragment { binding.recyclerView.setHasFixedSize(true); binding.recyclerView.setLayoutManager(new LinearLayoutManager(requireActivity())); RecyclerViewKt.fixEdgeEffect(binding.recyclerView, false, true); - binding.swipeRefreshLayout.setOnRefreshListener(() -> scopeAdapter.refresh(true)); + binding.swipeRefreshLayout.setOnRefreshListener(() -> scopeAdapter.refresh()); searchListener = scopeAdapter.getSearchListener(); @@ -150,7 +150,14 @@ public class AppListFragment extends BaseFragment { @Override public void onResume() { super.onResume(); - scopeAdapter.refresh(false); + scopeAdapter.refresh(); + } + + @Override + public void onDestroy() { + scopeAdapter.onDestroy(); + + super.onDestroy(); } @Override diff --git a/app/src/main/java/org/lsposed/manager/ui/fragment/BaseFragment.java b/app/src/main/java/org/lsposed/manager/ui/fragment/BaseFragment.java index d9308ef0..a100470b 100644 --- a/app/src/main/java/org/lsposed/manager/ui/fragment/BaseFragment.java +++ b/app/src/main/java/org/lsposed/manager/ui/fragment/BaseFragment.java @@ -19,6 +19,7 @@ package org.lsposed.manager.ui.fragment; +import android.app.Activity; import android.view.View; import androidx.appcompat.widget.Toolbar; @@ -66,4 +67,11 @@ public class BaseFragment extends Fragment { public Future runAsync(Runnable runnable) { return App.getExecutorService().submit(runnable); } + + public void runOnUiThread(Runnable runnable) { + Activity activity = getActivity(); + if (activity != null && !activity.isFinishing()) { + activity.runOnUiThread(runnable); + } + } } diff --git a/app/src/main/java/org/lsposed/manager/ui/fragment/LogsFragment.java b/app/src/main/java/org/lsposed/manager/ui/fragment/LogsFragment.java index 9d7c8950..375ca29d 100644 --- a/app/src/main/java/org/lsposed/manager/ui/fragment/LogsFragment.java +++ b/app/src/main/java/org/lsposed/manager/ui/fragment/LogsFragment.java @@ -280,13 +280,19 @@ public class LogsFragment extends BaseFragment { protected void onPostExecute(List logs) { adapter.setLogs(logs); - handler.removeCallbacks(mRunnable);//It loaded so fast that no need to show progress + handler.removeCallbacks(mRunnable); if (mProgressDialog.isShowing()) { mProgressDialog.dismiss(); } } } + @Override + public void onDestroy() { + handler.removeCallbacksAndMessages(null); + super.onDestroy(); + } + private class LogsAdapter extends RecyclerView.Adapter { ArrayList logs = new ArrayList<>(); 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 be960a5f..ef89f5bf 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 @@ -32,15 +32,12 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.Handler; -import android.os.HandlerThread; import android.text.Spannable; import android.text.SpannableStringBuilder; 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; @@ -59,7 +56,6 @@ import androidx.appcompat.widget.SearchView; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; -import androidx.lifecycle.Lifecycle; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager2.adapter.FragmentStateAdapter; @@ -89,8 +85,6 @@ 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; @@ -101,8 +95,7 @@ import rikka.insets.WindowInsetsHelperKt; import rikka.recyclerview.RecyclerViewKt; import rikka.widget.borderview.BorderRecyclerView; -public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleListener, RepoLoader.Listener { - private static final Handler workHandler; +public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleListener { private static final PackageManager pm = App.getInstance().getPackageManager(); private static final ModuleUtil moduleUtil = ModuleUtil.getInstance(); private static final RepoLoader repoLoader = RepoLoader.getInstance(); @@ -113,16 +106,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 { - HandlerThread workThread = new HandlerThread("ModulesActivity WorkHandler"); - workThread.start(); - workHandler = new Handler(workThread.getLooper()); - } - @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -142,18 +127,9 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi } @Override - public void onAttach(@NonNull Context context) { - super.onAttach(context); + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); moduleUtil.addListener(this); - repoLoader.addListener(this); - repoLoaded(); - } - - @Override - public void onDetach() { - moduleUtil.removeListener(this); - repoLoader.removeListener(this); - super.onDetach(); } @Nullable @@ -281,16 +257,16 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi .setTitle(getString(R.string.install_to_user, user.name)) .setMessage(getString(R.string.install_to_user_message, module.getAppName(), user.name)) .setPositiveButton(android.R.string.ok, (dialog, which) -> - workHandler.post(() -> { + runAsync(() -> { var success = ConfigManager.installExistingPackageAsUser(module.packageName, user.id); - requireActivity().runOnUiThread(() -> { - String text = success ? getString(R.string.module_installed, module.getAppName(), user.name) : getString(R.string.module_install_failed); - if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) { - Snackbar.make(binding.snackbar, text, Snackbar.LENGTH_SHORT).show(); - } else { - Toast.makeText(requireActivity(), text, Toast.LENGTH_SHORT).show(); - } - }); + String text = success ? + getString(R.string.module_installed, module.getAppName(), user.name) : + getString(R.string.module_install_failed); + if (binding != null && isResumed()) { + Snackbar.make(binding.snackbar, text, Snackbar.LENGTH_LONG).show(); + } else { + Toast.makeText(App.getInstance(), text, Toast.LENGTH_LONG).show(); + } if (success) moduleUtil.reloadSingleModule(module.packageName, user.id); })) @@ -330,16 +306,14 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi .setTitle(selectedModule.getAppName()) .setMessage(R.string.module_uninstall_message) .setPositiveButton(android.R.string.ok, (dialog, which) -> - workHandler.post(() -> { + runAsync(() -> { boolean success = ConfigManager.uninstallPackage(selectedModule.packageName, selectedModule.userId); - requireActivity().runOnUiThread(() -> { - String text = success ? getString(R.string.module_uninstalled, selectedModule.getAppName()) : getString(R.string.module_uninstall_failed); - if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) { - Snackbar.make(binding.snackbar, text, Snackbar.LENGTH_SHORT).show(); - } else { - Toast.makeText(requireActivity(), text, Toast.LENGTH_SHORT).show(); - } - }); + String text = success ? getString(R.string.module_uninstalled, selectedModule.getAppName()) : getString(R.string.module_uninstall_failed); + if (binding != null && isResumed()) { + Snackbar.make(binding.snackbar, text, Snackbar.LENGTH_LONG).show(); + } else { + Toast.makeText(App.getInstance(), text, Toast.LENGTH_LONG).show(); + } if (success) moduleUtil.reloadSingleModule(selectedModule.packageName, selectedModule.userId); })) @@ -357,31 +331,10 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi public void onDestroyView() { super.onDestroyView(); + moduleUtil.removeListener(this); binding = null; } - @Override - synchronized public void repoLoaded() { - latestVersion.clear(); - for (var module : repoLoader.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)); - } - requireActivity().runOnUiThread(() -> adapters.forEach(ModuleAdapter::notifyDataSetChanged)); - } - public static class ModuleListFragment extends Fragment { @Nullable @Override @@ -529,9 +482,8 @@ 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 (repoLoader.isRepoLoaded()) { + var ver = repoLoader.getModuleLatestVersion(item.packageName); if (ver != null && ver.first > item.versionCode) { sb.append("\n"); String recommended = getString(R.string.update_available, ver.second); @@ -630,7 +582,7 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi public void refresh(boolean force) { if (force) moduleUtil.reloadInstalledModules(); - requireActivity().runOnUiThread(reloadModules); + runOnUiThread(reloadModules); } private final Runnable reloadModules = new Runnable() { @@ -651,7 +603,7 @@ public class ModulesFragment extends BaseFragment implements ModuleUtil.ModuleLi searchList.clear(); searchList.addAll(tmpList); String queryStr = searchView != null ? searchView.getQuery().toString() : ""; - requireActivity().runOnUiThread(() -> getFilter().filter(queryStr)); + runOnUiThread(() -> getFilter().filter(queryStr)); } }; diff --git a/app/src/main/java/org/lsposed/manager/ui/fragment/RepoFragment.java b/app/src/main/java/org/lsposed/manager/ui/fragment/RepoFragment.java index 82aa2d34..cc2c431c 100644 --- a/app/src/main/java/org/lsposed/manager/ui/fragment/RepoFragment.java +++ b/app/src/main/java/org/lsposed/manager/ui/fragment/RepoFragment.java @@ -19,11 +19,17 @@ package org.lsposed.manager.ui.fragment; +import android.graphics.Typeface; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; +import android.text.style.StyleSpan; +import android.text.style.TypefaceSpan; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -50,6 +56,7 @@ import org.lsposed.manager.databinding.FragmentRepoBinding; import org.lsposed.manager.databinding.ItemOnlinemoduleBinding; import org.lsposed.manager.repo.RepoLoader; import org.lsposed.manager.repo.model.OnlineModule; +import org.lsposed.manager.util.ModuleUtil; import java.time.Instant; import java.util.ArrayList; @@ -59,6 +66,7 @@ import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; +import rikka.core.res.ResourcesKt; import rikka.core.util.LabelComparator; import rikka.recyclerview.RecyclerViewKt; @@ -66,7 +74,7 @@ public class RepoFragment extends BaseFragment implements RepoLoader.Listener { protected FragmentRepoBinding binding; protected SearchView searchView; private SearchView.OnQueryTextListener mSearchListener; - private Handler mHandler = new Handler(Looper.getMainLooper()); + private final Handler mHandler = new Handler(Looper.getMainLooper()); private boolean preLoadWebview = true; private final RepoLoader repoLoader = RepoLoader.getInstance(); @@ -121,9 +129,12 @@ public class RepoFragment extends BaseFragment implements RepoLoader.Listener { } @Override - public void onDestroy() { - super.onDestroy(); + public void onDestroyView() { + super.onDestroyView(); + + mHandler.removeCallbacksAndMessages(null); repoLoader.removeListener(this); + binding = null; } @Override @@ -138,15 +149,9 @@ public class RepoFragment extends BaseFragment implements RepoLoader.Listener { } } - @Override - public void onDetach() { - mHandler.removeCallbacksAndMessages(null); - super.onDetach(); - } - @Override public void repoLoaded() { - requireActivity().runOnUiThread(() -> { + runOnUiThread(() -> { binding.progress.hide(); adapter.setData(repoLoader.getOnlineModules()); }); @@ -201,6 +206,24 @@ public class RepoFragment extends BaseFragment implements RepoLoader.Listener { sb.append("\n"); sb.append(summary); } + ModuleUtil.InstalledModule installedModule = ModuleUtil.getInstance().getModule(module.getName()); + if (installedModule != null) { + var ver = repoLoader.getModuleLatestVersion(installedModule.packageName); + if (ver != null && ver.first > installedModule.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(), androidx.appcompat.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); holder.itemView.setOnClickListener(v -> { searchView.clearFocus(); diff --git a/app/src/main/java/org/lsposed/manager/ui/fragment/RepoItemFragment.java b/app/src/main/java/org/lsposed/manager/ui/fragment/RepoItemFragment.java index d61eff09..02bad7ec 100644 --- a/app/src/main/java/org/lsposed/manager/ui/fragment/RepoItemFragment.java +++ b/app/src/main/java/org/lsposed/manager/ui/fragment/RepoItemFragment.java @@ -204,8 +204,8 @@ public class RepoItemFragment extends BaseFragment implements RepoLoader.Listene public void moduleReleasesLoaded(OnlineModule module) { this.module = module; if (releaseAdapter != null) { - requireActivity().runOnUiThread(() -> releaseAdapter.loadItems()); - if (module.getReleases().size() == 1) { + runOnUiThread(() -> releaseAdapter.loadItems()); + if (isResumed() && module.getReleases().size() == 1) { Snackbar.make(binding.snackbar, R.string.module_release_no_more, Snackbar.LENGTH_SHORT).show(); } } @@ -214,23 +214,18 @@ public class RepoItemFragment extends BaseFragment implements RepoLoader.Listene @Override public void onThrowable(Throwable t) { if (releaseAdapter != null) { - requireActivity().runOnUiThread(() -> releaseAdapter.loadItems()); + runOnUiThread(() -> releaseAdapter.loadItems()); + if (isResumed()) { + Snackbar.make(binding.snackbar, getString(R.string.repo_load_failed, t.getLocalizedMessage()), Snackbar.LENGTH_SHORT).show(); + } } - if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) { - Snackbar.make(binding.snackbar, getString(R.string.repo_load_failed, t.getLocalizedMessage()), Snackbar.LENGTH_SHORT).show(); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - RepoLoader.getInstance().removeListener(this); } @Override public void onDestroyView() { super.onDestroyView(); + RepoLoader.getInstance().removeListener(this); binding = null; } diff --git a/app/src/main/res/layout/fragment_logs.xml b/app/src/main/res/layout/fragment_logs.xml index 25ec992a..d14bde7a 100644 --- a/app/src/main/res/layout/fragment_logs.xml +++ b/app/src/main/res/layout/fragment_logs.xml @@ -82,7 +82,7 @@ android:clipToPadding="false" android:fadeScrollbars="true" android:paddingTop="104dp" - android:scrollbarStyle="outsideOverlay" + android:scrollbarStyle="insideOverlay" android:scrollbars="vertical" app:borderTopVisibility="whenTop" app:borderTopDrawable="@null" diff --git a/build.gradle.kts b/build.gradle.kts index 8ff4242e..f2b7aea1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,7 +25,7 @@ buildscript { mavenCentral() } dependencies { - classpath("com.android.tools.build:gradle:7.1.0-alpha09") + classpath("com.android.tools.build:gradle:7.1.0-alpha10") classpath("org.eclipse.jgit:org.eclipse.jgit:5.12.0.202106070339-r") classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.4.0-alpha07") }