From affa6fe6432332b68558869c87fa53f25cd1ecb1 Mon Sep 17 00:00:00 2001 From: tehcneko <7764726+tehcneko@users.noreply.github.com> Date: Sat, 13 Feb 2021 18:09:59 +0800 Subject: [PATCH] [app] Add load more to releases --- .../lsposed/manager/repo/RepoLoader.java | 28 ++++ .../manager/repo/model/OnlineModule.java | 1 + .../manager/ui/activity/RepoActivity.java | 5 + .../manager/ui/activity/RepoItemActivity.java | 137 +++++++++++++----- .../res/drawable/ic_keyboard_arrow_down.xml | 30 ++++ .../main/res/layout/item_repo_loadmore.xml | 50 +++++++ app/src/main/res/values/strings.xml | 2 + 7 files changed, 214 insertions(+), 39 deletions(-) create mode 100644 app/src/main/res/drawable/ic_keyboard_arrow_down.xml create mode 100644 app/src/main/res/layout/item_repo_loadmore.xml diff --git a/app/src/main/java/io/github/lsposed/manager/repo/RepoLoader.java b/app/src/main/java/io/github/lsposed/manager/repo/RepoLoader.java index 10ea9ddc..43eb0b53 100644 --- a/app/src/main/java/io/github/lsposed/manager/repo/RepoLoader.java +++ b/app/src/main/java/io/github/lsposed/manager/repo/RepoLoader.java @@ -107,6 +107,32 @@ public class RepoLoader { }); } + public void loadRemoteReleases(String packageName) { + App.getOkHttpClient().newCall(new Request.Builder() + .url(String.format("https://modules.lsposed.org/module/%s.json", packageName)) + .build()).enqueue(new Callback() { + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + App.getInstance().runOnUiThread(() -> Toast.makeText(App.getInstance(), e.getMessage(), Toast.LENGTH_LONG).show()); + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + ResponseBody body = response.body(); + if (body != null) { + String bodyString = body.string(); + Gson gson = new Gson(); + OnlineModule module = gson.fromJson(bodyString, OnlineModule.class); + module.releasesLoaded = true; + onlineModules.replace(packageName, module); + for (Listener listener : listeners) { + listener.moduleReleasesLoaded(module); + } + } + } + }); + } + public void addListener(Listener listener) { if (!listeners.contains(listener)) listeners.add(listener); @@ -126,5 +152,7 @@ public class RepoLoader { public interface Listener { void repoLoaded(); + + void moduleReleasesLoaded(OnlineModule module); } } diff --git a/app/src/main/java/io/github/lsposed/manager/repo/model/OnlineModule.java b/app/src/main/java/io/github/lsposed/manager/repo/model/OnlineModule.java index c7f3908a..caaaee61 100644 --- a/app/src/main/java/io/github/lsposed/manager/repo/model/OnlineModule.java +++ b/app/src/main/java/io/github/lsposed/manager/repo/model/OnlineModule.java @@ -77,6 +77,7 @@ public class OnlineModule implements Serializable, Parcelable { @SerializedName("stargazerCount") @Expose private Integer stargazerCount; + public boolean releasesLoaded = false; public final static Creator CREATOR = new Creator() { public OnlineModule createFromParcel(Parcel in) { diff --git a/app/src/main/java/io/github/lsposed/manager/ui/activity/RepoActivity.java b/app/src/main/java/io/github/lsposed/manager/ui/activity/RepoActivity.java index 3f95040c..d8aeb323 100644 --- a/app/src/main/java/io/github/lsposed/manager/ui/activity/RepoActivity.java +++ b/app/src/main/java/io/github/lsposed/manager/ui/activity/RepoActivity.java @@ -82,6 +82,11 @@ public class RepoActivity extends ListActivity implements RepoLoader.Listener { }); } + @Override + public void moduleReleasesLoaded(OnlineModule module) { + + } + @Override public boolean onOptionsItemSelected(@NonNull MenuItem item) { int itemId = item.getItemId(); diff --git a/app/src/main/java/io/github/lsposed/manager/ui/activity/RepoItemActivity.java b/app/src/main/java/io/github/lsposed/manager/ui/activity/RepoItemActivity.java index d39e4f70..abd43446 100644 --- a/app/src/main/java/io/github/lsposed/manager/ui/activity/RepoItemActivity.java +++ b/app/src/main/java/io/github/lsposed/manager/ui/activity/RepoItemActivity.java @@ -39,6 +39,8 @@ import androidx.appcompat.app.AlertDialog; import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager2.widget.ViewPager2; +import com.google.android.material.progressindicator.CircularProgressIndicator; +import com.google.android.material.snackbar.Snackbar; import com.google.android.material.tabs.TabLayoutMediator; import java.util.ArrayList; @@ -47,6 +49,7 @@ import java.util.ListIterator; import io.github.lsposed.manager.R; import io.github.lsposed.manager.databinding.ActivityModuleDetailBinding; +import io.github.lsposed.manager.databinding.ItemRepoLoadmoreBinding; import io.github.lsposed.manager.databinding.ItemRepoReadmeBinding; import io.github.lsposed.manager.databinding.ItemRepoRecyclerviewBinding; import io.github.lsposed.manager.databinding.ItemRepoReleaseBinding; @@ -77,13 +80,15 @@ import rikka.widget.borderview.BorderNestedScrollView; import rikka.widget.borderview.BorderRecyclerView; import rikka.widget.borderview.BorderView; -public class RepoItemActivity extends BaseActivity { +public class RepoItemActivity extends BaseActivity implements RepoLoader.Listener { ActivityModuleDetailBinding binding; private Markwon markwon; private OnlineModule module; + private ReleaseAdapter releaseAdapter; @Override public void onCreate(@Nullable Bundle savedInstanceState) { + RepoLoader.getInstance().addListener(this); super.onCreate(savedInstanceState); binding = ActivityModuleDetailBinding.inflate(getLayoutInflater()); String modulePackageName = getIntent().getStringExtra("modulePackageName"); @@ -136,12 +141,36 @@ public class RepoItemActivity extends BaseActivity { public boolean onOptionsItemSelected(@NonNull MenuItem item) { int id = item.getItemId(); if (id == R.id.menu_open_in_browser) { - NavUtil.startURL(this, module.getUrl()); - // TODO: replace with web version + NavUtil.startURL(this, "https://modules.lsposed.org/module/" + module.getName()); } return super.onOptionsItemSelected(item); } + @Override + public void repoLoaded() { + + } + + @Override + public void moduleReleasesLoaded(OnlineModule module) { + this.module = module; + if (releaseAdapter != null) { + runOnUiThread(() -> { + if (module.getReleases().size() == 1) { + Snackbar.make(binding.snackbar, R.string.module_release_no_more, Snackbar.LENGTH_SHORT).show(); + } + releaseAdapter.loadItems(); + releaseAdapter.notifyDataSetChanged(); + }); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + RepoLoader.getInstance().removeListener(this); + } + private class InformationAdapter extends RecyclerView.Adapter { private final OnlineModule module; @@ -229,52 +258,76 @@ public class RepoItemActivity extends BaseActivity { } private class ReleaseAdapter extends RecyclerView.Adapter { - private final List items; + private List items; - public ReleaseAdapter(List items) { - this.items = items; + public ReleaseAdapter() { + loadItems(); + } + + public void loadItems() { + this.items = module.getReleases(); + notifyDataSetChanged(); } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new ViewHolder(ItemRepoReleaseBinding.inflate(getLayoutInflater(), parent, false)); + if (viewType == 0) { + return new ViewHolder(ItemRepoReleaseBinding.inflate(getLayoutInflater(), parent, false).getRoot()); + } else { + return new ViewHolder(ItemRepoLoadmoreBinding.inflate(getLayoutInflater(), parent, false).getRoot()); + } } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - Release release = items.get(position); - holder.title.setText(release.getName()); - holder.description.setTransformationMethod(new LinkTransformationMethod(RepoItemActivity.this)); - holder.description.setSpannableFactory(NoCopySpannableFactory.getInstance()); - markwon.setMarkdown(holder.description, release.getDescription()); - holder.description.setMovementMethod(null); - holder.openInBrowser.setOnClickListener(v -> NavUtil.startURL(RepoItemActivity.this, release.getUrl())); - List assets = release.getReleaseAssets(); - if (assets != null && !assets.isEmpty()) { - holder.viewAssets.setOnClickListener(v -> { - ArrayList names = new ArrayList<>(); - assets.forEach(releaseAsset -> names.add(releaseAsset.getName())); - new AlertDialog.Builder(RepoItemActivity.this) - .setItems(names.toArray(new String[0]), (dialog, which) -> NavUtil.startURL(RepoItemActivity.this, assets.get(which).getDownloadUrl())) - .show(); + if (position == items.size()) { + holder.itemView.setOnClickListener(v -> { + if (holder.progress.getVisibility() == View.GONE) { + holder.title.setVisibility(View.GONE); + holder.progress.show(); + RepoLoader.getInstance().loadRemoteReleases(module.getName()); + } }); } else { - holder.viewAssets.setVisibility(View.GONE); - } - holder.itemView.setOnClickListener(v -> { - ClickableSpan span = holder.description.getCurrentSpan(); - holder.description.clearCurrentSpan(); - - if (span instanceof CustomTabsURLSpan) { - span.onClick(v); + Release release = items.get(position); + holder.title.setText(release.getName()); + holder.description.setTransformationMethod(new LinkTransformationMethod(RepoItemActivity.this)); + holder.description.setSpannableFactory(NoCopySpannableFactory.getInstance()); + markwon.setMarkdown(holder.description, release.getDescription()); + holder.description.setMovementMethod(null); + holder.openInBrowser.setOnClickListener(v -> NavUtil.startURL(RepoItemActivity.this, release.getUrl())); + List assets = release.getReleaseAssets(); + if (assets != null && !assets.isEmpty()) { + holder.viewAssets.setOnClickListener(v -> { + ArrayList names = new ArrayList<>(); + assets.forEach(releaseAsset -> names.add(releaseAsset.getName())); + new AlertDialog.Builder(RepoItemActivity.this) + .setItems(names.toArray(new String[0]), (dialog, which) -> NavUtil.startURL(RepoItemActivity.this, assets.get(which).getDownloadUrl())) + .show(); + }); + } else { + holder.viewAssets.setVisibility(View.GONE); } - }); + holder.itemView.setOnClickListener(v -> { + ClickableSpan span = holder.description.getCurrentSpan(); + holder.description.clearCurrentSpan(); + + if (span instanceof CustomTabsURLSpan) { + span.onClick(v); + } + }); + } } @Override public int getItemCount() { - return items.size(); + return items.size() + (module.releasesLoaded ? 0 : 1); + } + + @Override + public int getItemViewType(int position) { + return !module.releasesLoaded && position == getItemCount() - 1 ? 1 : 0; } class ViewHolder extends RecyclerView.ViewHolder { @@ -282,13 +335,15 @@ public class RepoItemActivity extends BaseActivity { LinkifyTextView description; View openInBrowser; View viewAssets; + CircularProgressIndicator progress; - public ViewHolder(ItemRepoReleaseBinding binding) { - super(binding.getRoot()); - title = binding.title; - description = binding.description; - openInBrowser = binding.openInBrowser; - viewAssets = binding.viewAssets; + public ViewHolder(View view) { + super(view); + title = view.findViewById(R.id.title); + description = view.findViewById(R.id.description); + openInBrowser = view.findViewById(R.id.open_in_browser); + viewAssets = view.findViewById(R.id.view_assets); + progress = view.findViewById(R.id.progress); } } } @@ -315,7 +370,11 @@ public class RepoItemActivity extends BaseActivity { break; case 1: case 2: - holder.recyclerView.setAdapter(position == 1 ? new ReleaseAdapter(module.getReleases()) : new InformationAdapter(module)); + if (position == 1) { + holder.recyclerView.setAdapter(releaseAdapter = new ReleaseAdapter()); + } else { + holder.recyclerView.setAdapter(new InformationAdapter(module)); + } holder.recyclerView.setLayoutManager(new LinearLayoutManagerFix(RepoItemActivity.this)); holder.recyclerView.getBorderViewDelegate().setBorderVisibilityChangedListener((top, oldTop, bottom, oldBottom) -> binding.appBar.setRaised(!top)); RecyclerViewKt.fixEdgeEffect(holder.recyclerView, false, true); diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_down.xml b/app/src/main/res/drawable/ic_keyboard_arrow_down.xml new file mode 100644 index 00000000..0bc9590a --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_down.xml @@ -0,0 +1,30 @@ + + + + + diff --git a/app/src/main/res/layout/item_repo_loadmore.xml b/app/src/main/res/layout/item_repo_loadmore.xml new file mode 100644 index 00000000..4676a1e7 --- /dev/null +++ b/app/src/main/res/layout/item_repo_loadmore.xml @@ -0,0 +1,50 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d383db84..abdad236 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -175,4 +175,6 @@ DNS over HTTPS Workaround DNS poisoning in some nations Join our %s channel]]> + Load more + No more release