diff --git a/app/build.gradle b/app/build.gradle
index 8b195a07..8c46ef88 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -76,7 +76,9 @@ dependencies {
final def markwon_version = '4.6.2'
implementation "io.noties.markwon:core:$markwon_version"
implementation "io.noties.markwon:image:$markwon_version"
+ implementation "io.noties.markwon:image-glide:$markwon_version"
implementation "io.noties.markwon:html:$markwon_version"
+ implementation "io.noties.markwon:linkify:$markwon_version"
implementation 'rikka.insets:insets:1.0.1'
implementation 'rikka.recyclerview:recyclerview-utils:1.2.0'
implementation "rikka.widget:switchbar:1.0.2"
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 2b6adff3..3ca11552 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
@@ -34,26 +34,17 @@ import androidx.appcompat.app.ActionBar;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.RecyclerView;
-import com.google.gson.Gson;
-
-import java.io.IOException;
-
-import io.github.lsposed.manager.App;
import io.github.lsposed.manager.R;
import io.github.lsposed.manager.databinding.ActivityAppListBinding;
import io.github.lsposed.manager.repo.RepoLoader;
import io.github.lsposed.manager.repo.model.OnlineModule;
import io.github.lsposed.manager.util.LinearLayoutManagerFix;
import me.zhanghai.android.fastscroll.FastScrollerBuilder;
-import okhttp3.Call;
-import okhttp3.Callback;
-import okhttp3.Request;
-import okhttp3.Response;
public class RepoActivity extends BaseActivity implements RepoLoader.Listener {
+ private final RepoLoader repoLoader = RepoLoader.getInstance();
private ActivityAppListBinding binding;
private RepoAdapter adapter;
- private RepoLoader repoLoader = RepoLoader.getInstance();
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -80,15 +71,14 @@ public class RepoActivity extends BaseActivity implements RepoLoader.Listener {
}
repoLoader.addListener(this);
fastScrollerBuilder.build();
- binding.swipeRefreshLayout.setOnRefreshListener(() -> {
- repoLoader.loadRemoteData();
- });
+ binding.swipeRefreshLayout.setOnRefreshListener(repoLoader::loadRemoteData);
}
@Override
protected void onResume() {
super.onResume();
adapter.setData(repoLoader.getOnlineModules());
+ binding.swipeRefreshLayout.setRefreshing(adapter.getItemCount() == 0);
}
@Override
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 238fd775..90757f99 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
@@ -22,6 +22,7 @@ package io.github.lsposed.manager.ui.activity;
import android.os.Build;
import android.os.Bundle;
+import android.text.util.Linkify;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
@@ -49,9 +50,13 @@ import io.github.lsposed.manager.databinding.ItemRepoReleaseBinding;
import io.github.lsposed.manager.databinding.ItemRepoReleasesBinding;
import io.github.lsposed.manager.repo.model.OnlineModule;
import io.github.lsposed.manager.repo.model.Release;
+import io.github.lsposed.manager.util.GlideApp;
import io.github.lsposed.manager.util.LinearLayoutManagerFix;
import io.github.lsposed.manager.util.NavUtil;
+import io.github.lsposed.manager.util.chrome.LinkTransformationMethod;
import io.noties.markwon.Markwon;
+import io.noties.markwon.image.glide.GlideImagesPlugin;
+import io.noties.markwon.linkify.LinkifyPlugin;
public class RepoItemActivity extends BaseActivity {
ActivityModuleDetailBinding binding;
@@ -71,7 +76,10 @@ public class RepoItemActivity extends BaseActivity {
bar.setTitle(module.getDescription());
bar.setSubtitle(module.getName());
bar.setDisplayHomeAsUpEnabled(true);
- markwon = Markwon.create(this);
+ markwon = Markwon.builder(this)
+ .usePlugin(GlideImagesPlugin.create(GlideApp.with(this)))
+ .usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS))
+ .build();
binding.viewPager.setAdapter(new PagerAdapter());
binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
@@ -83,7 +91,7 @@ public class RepoItemActivity extends BaseActivity {
}
}
});
- int[] titles = new int[]{R.string.module_readme, R.string.module_readme};
+ int[] titles = new int[]{R.string.module_readme, R.string.module_releases};
new TabLayoutMediator(binding.tabLayout, binding.viewPager, (tab, position) -> tab.setText(titles[position])).attach();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
@@ -183,6 +191,7 @@ public class RepoItemActivity extends BaseActivity {
}
if (position == 0) {
binding.appBar.setLiftOnScrollTargetViewId(R.id.scrollView);
+ holder.textView.setTransformationMethod(new LinkTransformationMethod(RepoItemActivity.this));
markwon.setMarkdown(holder.textView, module.getReadme());
} else {
binding.appBar.setLiftOnScrollTargetViewId(R.id.recyclerView);
diff --git a/app/src/main/java/io/github/lsposed/manager/util/IconLoader.java b/app/src/main/java/io/github/lsposed/manager/util/AppModule.java
similarity index 71%
rename from app/src/main/java/io/github/lsposed/manager/util/IconLoader.java
rename to app/src/main/java/io/github/lsposed/manager/util/AppModule.java
index 8b4e1edd..0a30b886 100644
--- a/app/src/main/java/io/github/lsposed/manager/util/IconLoader.java
+++ b/app/src/main/java/io/github/lsposed/manager/util/AppModule.java
@@ -10,19 +10,26 @@ import androidx.annotation.NonNull;
import com.bumptech.glide.Glide;
import com.bumptech.glide.Registry;
import com.bumptech.glide.annotation.GlideModule;
+import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
+import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.AppGlideModule;
+import java.io.InputStream;
+
+import io.github.lsposed.manager.App;
import io.github.lsposed.manager.R;
import me.zhanghai.android.appiconloader.glide.AppIconModelLoader;
@GlideModule
-public class IconLoader extends AppGlideModule {
+public class AppModule extends AppGlideModule {
@Override
public void registerComponents(Context context, @NonNull Glide glide, Registry registry) {
int iconSize = context.getResources().getDimensionPixelSize(R.dimen.app_icon_size);
registry.prepend(PackageInfo.class, Bitmap.class, new AppIconModelLoader.Factory(iconSize,
context.getApplicationInfo().loadIcon(context.getPackageManager()) instanceof AdaptiveIconDrawable, context));
+ OkHttpUrlLoader.Factory factory = new OkHttpUrlLoader.Factory(App.getOkHttpClient());
+ registry.prepend(GlideUrl.class, InputStream.class, factory);
}
}
diff --git a/app/src/main/java/io/github/lsposed/manager/util/chrome/CustomTabsURLSpan.java b/app/src/main/java/io/github/lsposed/manager/util/chrome/CustomTabsURLSpan.java
new file mode 100644
index 00000000..faf7b516
--- /dev/null
+++ b/app/src/main/java/io/github/lsposed/manager/util/chrome/CustomTabsURLSpan.java
@@ -0,0 +1,43 @@
+/*
+ * This file is part of LSPosed.
+ *
+ * LSPosed is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LSPosed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LSPosed. If not, see .
+ *
+ * Copyright (C) 2020 EdXposed Contributors
+ * Copyright (C) 2021 LSPosed Contributors
+ */
+
+package io.github.lsposed.manager.util.chrome;
+
+import android.text.style.URLSpan;
+import android.view.View;
+
+import io.github.lsposed.manager.ui.activity.BaseActivity;
+import io.github.lsposed.manager.util.NavUtil;
+
+public class CustomTabsURLSpan extends URLSpan {
+
+ private final BaseActivity activity;
+
+ CustomTabsURLSpan(BaseActivity activity, String url) {
+ super(url);
+ this.activity = activity;
+ }
+
+ @Override
+ public void onClick(View widget) {
+ String url = getURL();
+ NavUtil.startURL(activity, url);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/github/lsposed/manager/util/chrome/LinkTransformationMethod.java b/app/src/main/java/io/github/lsposed/manager/util/chrome/LinkTransformationMethod.java
new file mode 100644
index 00000000..ad2f6506
--- /dev/null
+++ b/app/src/main/java/io/github/lsposed/manager/util/chrome/LinkTransformationMethod.java
@@ -0,0 +1,66 @@
+/*
+ * This file is part of LSPosed.
+ *
+ * LSPosed is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LSPosed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LSPosed. If not, see .
+ *
+ * Copyright (C) 2020 EdXposed Contributors
+ * Copyright (C) 2021 LSPosed Contributors
+ */
+
+package io.github.lsposed.manager.util.chrome;
+
+import android.graphics.Rect;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.method.TransformationMethod;
+import android.text.style.URLSpan;
+import android.view.View;
+import android.widget.TextView;
+
+import io.github.lsposed.manager.ui.activity.BaseActivity;
+
+public class LinkTransformationMethod implements TransformationMethod {
+
+ private final BaseActivity activity;
+
+ public LinkTransformationMethod(BaseActivity activity) {
+ this.activity = activity;
+ }
+
+ @Override
+ public CharSequence getTransformation(CharSequence source, View view) {
+ if (view instanceof TextView) {
+ TextView textView = (TextView) view;
+ if (textView.getText() == null || !(textView.getText() instanceof Spannable)) {
+ return source;
+ }
+ Spannable text = (Spannable) textView.getText();
+ URLSpan[] spans = text.getSpans(0, textView.length(), URLSpan.class);
+ for (int i = spans.length - 1; i >= 0; i--) {
+ URLSpan oldSpan = spans[i];
+ int start = text.getSpanStart(oldSpan);
+ int end = text.getSpanEnd(oldSpan);
+ String url = oldSpan.getURL();
+ text.removeSpan(oldSpan);
+ text.setSpan(new CustomTabsURLSpan(activity, url), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ return text;
+ }
+ return source;
+ }
+
+ @Override
+ public void onFocusChanged(View view, CharSequence sourceText, boolean focused, int direction, Rect previouslyFocusedRect) {
+ }
+}
\ No newline at end of file