making java kotlin since 2023(tm)
Signed-off-by: androidacy-user <opensource@androidacy.com>pull/27/head
parent
906a5cbab9
commit
0708c2f7a9
@ -1,254 +1,255 @@
|
||||
package com.fox2code.mmm.markdown;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.fox2code.foxcompat.app.FoxActivity;
|
||||
import com.fox2code.mmm.Constants;
|
||||
import com.fox2code.mmm.MainApplication;
|
||||
import com.fox2code.mmm.R;
|
||||
import com.fox2code.mmm.XHooks;
|
||||
import com.fox2code.mmm.utils.IntentHelper;
|
||||
import com.fox2code.mmm.utils.io.net.Http;
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
import com.google.android.material.chip.Chip;
|
||||
import com.google.android.material.chip.ChipGroup;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler;
|
||||
|
||||
import org.matomo.sdk.extra.TrackHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public class MarkdownActivity extends FoxActivity {
|
||||
private static final HashMap<String, String> redirects = new HashMap<>(4);
|
||||
private static final String[] variants = new String[]{"readme.md", "README.MD", ".github/README.md"};
|
||||
private TextView header;
|
||||
private TextView footer;
|
||||
|
||||
private static byte[] getRawMarkdown(String url) throws IOException {
|
||||
String newUrl = redirects.get(url);
|
||||
if (newUrl != null && !newUrl.equals(url)) {
|
||||
return Http.doHttpGet(newUrl, true);
|
||||
}
|
||||
try {
|
||||
return Http.doHttpGet(url, true);
|
||||
} catch (IOException e) {
|
||||
// Workaround GitHub README.md case sensitivity issue
|
||||
if (url.startsWith("https://raw.githubusercontent.com/") && url.endsWith("/README.md")) {
|
||||
String prefix = url.substring(0, url.length() - 9);
|
||||
for (String suffix : variants) {
|
||||
newUrl = prefix + suffix;
|
||||
try { // Try with lowercase version
|
||||
byte[] rawMarkdown = Http.doHttpGet(prefix + suffix, true);
|
||||
redirects.put(url, newUrl); // Avoid retries
|
||||
return rawMarkdown;
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
TrackHelper.track().screen(this).with(MainApplication.getINSTANCE().getTracker());
|
||||
this.setDisplayHomeAsUpEnabled(true);
|
||||
Intent intent = this.getIntent();
|
||||
package com.fox2code.mmm.markdown
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import com.fox2code.foxcompat.app.FoxActivity
|
||||
import com.fox2code.mmm.Constants
|
||||
import com.fox2code.mmm.MainApplication
|
||||
import com.fox2code.mmm.R
|
||||
import com.fox2code.mmm.XHooks
|
||||
import com.fox2code.mmm.utils.IntentHelper
|
||||
import com.fox2code.mmm.utils.io.net.Http
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||
import org.matomo.sdk.extra.TrackHelper
|
||||
import timber.log.Timber
|
||||
import java.io.IOException
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
class MarkdownActivity : FoxActivity() {
|
||||
private var header: TextView? = null
|
||||
private var footer: TextView? = null
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
TrackHelper.track().screen(this).with(MainApplication.getINSTANCE().tracker)
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
val intent = this.intent
|
||||
if (!MainApplication.checkSecret(intent)) {
|
||||
Timber.e("Impersonation detected!");
|
||||
this.forceBackPressed();
|
||||
return;
|
||||
Timber.e("Impersonation detected!")
|
||||
forceBackPressed()
|
||||
return
|
||||
}
|
||||
String url = Objects.requireNonNull(intent.getExtras()).getString(Constants.EXTRA_MARKDOWN_URL);
|
||||
String title = intent.getExtras().getString(Constants.EXTRA_MARKDOWN_TITLE);
|
||||
String config = intent.getExtras().getString(Constants.EXTRA_MARKDOWN_CONFIG);
|
||||
boolean change_boot = intent.getExtras().getBoolean(Constants.EXTRA_MARKDOWN_CHANGE_BOOT);
|
||||
boolean needs_ramdisk = intent.getExtras().getBoolean(Constants.EXTRA_MARKDOWN_NEEDS_RAMDISK);
|
||||
int min_magisk = intent.getExtras().getInt(Constants.EXTRA_MARKDOWN_MIN_MAGISK);
|
||||
int min_api = intent.getExtras().getInt(Constants.EXTRA_MARKDOWN_MIN_API);
|
||||
int max_api = intent.getExtras().getInt(Constants.EXTRA_MARKDOWN_MAX_API);
|
||||
if (title != null && !title.isEmpty()) {
|
||||
this.setTitle(title);
|
||||
val url = intent.extras?.getString(Constants.EXTRA_MARKDOWN_URL)
|
||||
var title = intent.extras!!.getString(Constants.EXTRA_MARKDOWN_TITLE)
|
||||
val config = intent.extras!!.getString(Constants.EXTRA_MARKDOWN_CONFIG)
|
||||
val changeBoot = intent.extras!!.getBoolean(Constants.EXTRA_MARKDOWN_CHANGE_BOOT)
|
||||
val needsRamdisk = intent.extras!!.getBoolean(Constants.EXTRA_MARKDOWN_NEEDS_RAMDISK)
|
||||
val minMagisk = intent.extras!!.getInt(Constants.EXTRA_MARKDOWN_MIN_MAGISK)
|
||||
val minApi = intent.extras!!.getInt(Constants.EXTRA_MARKDOWN_MIN_API)
|
||||
val maxApi = intent.extras!!.getInt(Constants.EXTRA_MARKDOWN_MAX_API)
|
||||
if (!title.isNullOrEmpty()) {
|
||||
this.title = title
|
||||
} else {
|
||||
@Suppress("UNUSED_VALUE")
|
||||
title = url
|
||||
}
|
||||
setActionBarBackground(null);
|
||||
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, 0);
|
||||
if (config != null && !config.isEmpty()) {
|
||||
String configPkg = IntentHelper.getPackageOfConfig(config);
|
||||
setActionBarBackground(null)
|
||||
@Suppress("DEPRECATION")
|
||||
this.window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, 0)
|
||||
if (!config.isNullOrEmpty()) {
|
||||
val configPkg = IntentHelper.getPackageOfConfig(config)
|
||||
try {
|
||||
XHooks.checkConfigTargetExists(this, configPkg, config);
|
||||
this.setActionBarExtraMenuButton(R.drawable.ic_baseline_app_settings_alt_24, menu -> {
|
||||
IntentHelper.openConfig(this, config);
|
||||
return true;
|
||||
});
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Timber.w("Config package \"" + configPkg + "\" missing for markdown view");
|
||||
XHooks.checkConfigTargetExists(this, configPkg, config)
|
||||
this.setActionBarExtraMenuButton(R.drawable.ic_baseline_app_settings_alt_24) { _: MenuItem? ->
|
||||
IntentHelper.openConfig(this, config)
|
||||
true
|
||||
}
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
Timber.w("Config package \"$configPkg\" missing for markdown view")
|
||||
}
|
||||
}
|
||||
// validate the url won't crash the app
|
||||
if (url == null || url.isEmpty() || url.contains("..")) {
|
||||
Timber.e("Invalid url %s", String.valueOf(url));
|
||||
this.forceBackPressed();
|
||||
return;
|
||||
if (url.isNullOrEmpty() || url.contains("..")) {
|
||||
Timber.e("Invalid url %s", url.toString())
|
||||
forceBackPressed()
|
||||
return
|
||||
}
|
||||
Timber.i("Url for markdown %s", url.toString())
|
||||
setContentView(R.layout.markdown_view)
|
||||
val markdownBackground = findViewById<ViewGroup>(R.id.markdownBackground)
|
||||
val textView = findViewById<TextView>(R.id.markdownView)
|
||||
header = findViewById(R.id.markdownHeader)
|
||||
footer = findViewById(R.id.markdownFooter)
|
||||
updateBlurState()
|
||||
UiThreadHandler.handler.post { // Fix header/footer height
|
||||
this.updateScreenInsets(this.resources.configuration)
|
||||
}
|
||||
//noinspection UnnecessaryCallToStringValueOf
|
||||
Timber.i("Url for markdown %s", String.valueOf(url));
|
||||
setContentView(R.layout.markdown_view);
|
||||
final ViewGroup markdownBackground = findViewById(R.id.markdownBackground);
|
||||
final TextView textView = findViewById(R.id.markdownView);
|
||||
this.header = findViewById(R.id.markdownHeader);
|
||||
this.footer = findViewById(R.id.markdownFooter);
|
||||
this.updateBlurState();
|
||||
UiThreadHandler.handler.post(() -> // Fix header/footer height
|
||||
this.updateScreenInsets(this.getResources().getConfiguration()));
|
||||
|
||||
// Really bad created (MSG by Der_Googler)
|
||||
// set "message" to null to disable dialog
|
||||
if (change_boot) this.addChip(MarkdownChip.CHANGE_BOOT);
|
||||
if (needs_ramdisk) this.addChip(MarkdownChip.NEED_RAMDISK);
|
||||
if (min_magisk != 0) this.addChip(MarkdownChip.MIN_MAGISK, String.valueOf(min_magisk));
|
||||
if (min_api != 0) this.addChip(MarkdownChip.MIN_SDK, parseAndroidVersion(min_api));
|
||||
if (max_api != 0) this.addChip(MarkdownChip.MAX_SDK, parseAndroidVersion(max_api));
|
||||
|
||||
new Thread(() -> {
|
||||
if (changeBoot) this.addChip(MarkdownChip.CHANGE_BOOT)
|
||||
if (needsRamdisk) this.addChip(MarkdownChip.NEED_RAMDISK)
|
||||
if (minMagisk != 0) this.addChip(MarkdownChip.MIN_MAGISK, minMagisk.toString())
|
||||
if (minApi != 0) this.addChip(MarkdownChip.MIN_SDK, parseAndroidVersion(minApi))
|
||||
if (maxApi != 0) this.addChip(MarkdownChip.MAX_SDK, parseAndroidVersion(maxApi))
|
||||
Thread({
|
||||
try {
|
||||
Timber.i("Downloading");
|
||||
byte[] rawMarkdown = getRawMarkdown(url);
|
||||
Timber.i("Encoding");
|
||||
String markdown = new String(rawMarkdown, StandardCharsets.UTF_8);
|
||||
Timber.i("Done!");
|
||||
runOnUiThread(() -> {
|
||||
findViewById(R.id.markdownFooter).setMinimumHeight(this.getNavigationBarHeight());
|
||||
MainApplication.getINSTANCE().getMarkwon().setMarkdown(textView, MarkdownUrlLinker.urlLinkify(markdown));
|
||||
Timber.i("Downloading")
|
||||
val rawMarkdown = getRawMarkdown(url)
|
||||
Timber.i("Encoding")
|
||||
val markdown = String(rawMarkdown, StandardCharsets.UTF_8)
|
||||
Timber.i("Done!")
|
||||
runOnUiThread {
|
||||
footer?.minimumHeight = this.navigationBarHeight
|
||||
MainApplication.getINSTANCE().markwon.setMarkdown(
|
||||
textView,
|
||||
MarkdownUrlLinker.urlLinkify(markdown)
|
||||
)
|
||||
if (markdownBackground != null) {
|
||||
markdownBackground.setClickable(true);
|
||||
markdownBackground.isClickable = true
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
Timber.e(e);
|
||||
runOnUiThread(() -> Toast.makeText(this, R.string.failed_download, Toast.LENGTH_SHORT).show());
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e)
|
||||
runOnUiThread {
|
||||
Toast.makeText(this, R.string.failed_download, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}, "Markdown load thread").start();
|
||||
}, "Markdown load thread").start()
|
||||
}
|
||||
|
||||
private void updateBlurState() {
|
||||
private fun updateBlurState() {
|
||||
if (MainApplication.isBlurEnabled()) {
|
||||
// set bottom navigation bar color to transparent blur
|
||||
BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);
|
||||
val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_navigation)
|
||||
if (bottomNavigationView != null) {
|
||||
bottomNavigationView.setBackgroundColor(Color.TRANSPARENT);
|
||||
bottomNavigationView.setAlpha(0.8F);
|
||||
bottomNavigationView.setBackgroundColor(Color.TRANSPARENT)
|
||||
bottomNavigationView.alpha = 0.8f
|
||||
} else {
|
||||
Timber.w("Bottom navigation view not found");
|
||||
Timber.w("Bottom navigation view not found")
|
||||
}
|
||||
// set dialogs to have transparent blur
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND)
|
||||
}
|
||||
}
|
||||
|
||||
private void updateScreenInsets() {
|
||||
this.runOnUiThread(() -> this.updateScreenInsets(this.getResources().getConfiguration()));
|
||||
private fun updateScreenInsets() {
|
||||
runOnUiThread { this.updateScreenInsets(this.resources.configuration) }
|
||||
}
|
||||
|
||||
private void updateScreenInsets(Configuration configuration) {
|
||||
boolean landscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE;
|
||||
int bottomInset = (landscape ? 0 : this.getNavigationBarHeight());
|
||||
int statusBarHeight = getStatusBarHeight();
|
||||
int actionBarHeight = getActionBarHeight();
|
||||
int combinedBarsHeight = statusBarHeight + actionBarHeight;
|
||||
this.header.setMinHeight(combinedBarsHeight);
|
||||
this.footer.setMinHeight(bottomInset);
|
||||
private fun updateScreenInsets(configuration: Configuration) {
|
||||
val landscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
val bottomInset = if (landscape) 0 else this.navigationBarHeight
|
||||
val statusBarHeight = statusBarHeight
|
||||
val actionBarHeight = actionBarHeight
|
||||
val combinedBarsHeight = statusBarHeight + actionBarHeight
|
||||
header!!.minHeight = combinedBarsHeight
|
||||
footer!!.minHeight = bottomInset
|
||||
//this.actionBarBlur.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshUI() {
|
||||
super.refreshUI();
|
||||
this.updateScreenInsets();
|
||||
this.updateBlurState();
|
||||
override fun refreshUI() {
|
||||
super.refreshUI()
|
||||
this.updateScreenInsets()
|
||||
updateBlurState()
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onWindowUpdated() {
|
||||
this.updateScreenInsets();
|
||||
override fun onWindowUpdated() {
|
||||
this.updateScreenInsets()
|
||||
}
|
||||
|
||||
private void addChip(MarkdownChip markdownChip) {
|
||||
this.makeChip(this.getString(markdownChip.title), markdownChip.desc == 0 ? null : this.getString(markdownChip.desc));
|
||||
private fun addChip(markdownChip: MarkdownChip) {
|
||||
makeChip(
|
||||
this.getString(markdownChip.title),
|
||||
if (markdownChip.desc == 0) null else this.getString(markdownChip.desc)
|
||||
)
|
||||
}
|
||||
|
||||
private void addChip(MarkdownChip markdownChip, String extra) {
|
||||
String title = this.getString(markdownChip.title);
|
||||
if (title.contains("%s")) {
|
||||
title = title.replace("%s", extra);
|
||||
private fun addChip(markdownChip: MarkdownChip, extra: String) {
|
||||
var title = this.getString(markdownChip.title)
|
||||
title = if (title.contains("%s")) {
|
||||
title.replace("%s", extra)
|
||||
} else {
|
||||
title = title + " " + extra;
|
||||
"$title $extra"
|
||||
}
|
||||
this.makeChip(title, markdownChip.desc == 0 ? null : this.getString(markdownChip.desc));
|
||||
makeChip(title, if (markdownChip.desc == 0) null else this.getString(markdownChip.desc))
|
||||
}
|
||||
|
||||
private void makeChip(String title, String message) {
|
||||
final ChipGroup chip_group_holder = findViewById(R.id.chip_group_holder);
|
||||
Chip chip = new Chip(this);
|
||||
chip.setText(title);
|
||||
chip.setVisibility(View.VISIBLE);
|
||||
private fun makeChip(title: String, message: String?) {
|
||||
val chipGroupHolder = findViewById<ChipGroup>(R.id.chip_group_holder)
|
||||
val chip = Chip(this)
|
||||
chip.text = title
|
||||
chip.visibility = View.VISIBLE
|
||||
if (message != null) {
|
||||
chip.setOnClickListener(_view -> {
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
|
||||
|
||||
builder.setTitle(title).setMessage(message).setCancelable(true).setPositiveButton(R.string.ok, (x, y) -> x.dismiss()).show();
|
||||
chip.setOnClickListener { _: View? ->
|
||||
val builder = MaterialAlertDialogBuilder(this)
|
||||
builder.setTitle(title).setMessage(message).setCancelable(true)
|
||||
.setPositiveButton(R.string.ok) { x: DialogInterface, _: Int -> x.dismiss() }
|
||||
.show()
|
||||
}
|
||||
}
|
||||
chipGroupHolder.addView(chip)
|
||||
}
|
||||
|
||||
});
|
||||
private fun parseAndroidVersion(version: Int): String {
|
||||
return when (version) {
|
||||
Build.VERSION_CODES.JELLY_BEAN -> "4.1 JellyBean"
|
||||
Build.VERSION_CODES.JELLY_BEAN_MR1 -> "4.2 JellyBean"
|
||||
Build.VERSION_CODES.JELLY_BEAN_MR2 -> "4.3 JellyBean"
|
||||
Build.VERSION_CODES.KITKAT -> "4.4 KitKat"
|
||||
Build.VERSION_CODES.KITKAT_WATCH -> "4.4 KitKat Watch"
|
||||
Build.VERSION_CODES.LOLLIPOP -> "5.0 Lollipop"
|
||||
Build.VERSION_CODES.LOLLIPOP_MR1 -> "5.1 Lollipop"
|
||||
Build.VERSION_CODES.M -> "6.0 Marshmallow"
|
||||
Build.VERSION_CODES.N -> "7.0 Nougat"
|
||||
Build.VERSION_CODES.N_MR1 -> "7.1 Nougat"
|
||||
Build.VERSION_CODES.O -> "8.0 Oreo"
|
||||
Build.VERSION_CODES.O_MR1 -> "8.1 Oreo"
|
||||
Build.VERSION_CODES.P -> "9.0 Pie"
|
||||
Build.VERSION_CODES.Q -> "10 (Q)"
|
||||
Build.VERSION_CODES.R -> "11 (R)"
|
||||
Build.VERSION_CODES.S -> "12 (S)"
|
||||
Build.VERSION_CODES.S_V2 -> "12L"
|
||||
Build.VERSION_CODES.TIRAMISU -> "13 Tiramisu"
|
||||
else -> "Sdk: $version"
|
||||
}
|
||||
chip_group_holder.addView(chip);
|
||||
}
|
||||
|
||||
private String parseAndroidVersion(int version) {
|
||||
return switch (version) {
|
||||
case Build.VERSION_CODES.JELLY_BEAN -> "4.1 JellyBean";
|
||||
case Build.VERSION_CODES.JELLY_BEAN_MR1 -> "4.2 JellyBean";
|
||||
case Build.VERSION_CODES.JELLY_BEAN_MR2 -> "4.3 JellyBean";
|
||||
case Build.VERSION_CODES.KITKAT -> "4.4 KitKat";
|
||||
case Build.VERSION_CODES.KITKAT_WATCH -> "4.4 KitKat Watch";
|
||||
case Build.VERSION_CODES.LOLLIPOP -> "5.0 Lollipop";
|
||||
case Build.VERSION_CODES.LOLLIPOP_MR1 -> "5.1 Lollipop";
|
||||
case Build.VERSION_CODES.M -> "6.0 Marshmallow";
|
||||
case Build.VERSION_CODES.N -> "7.0 Nougat";
|
||||
case Build.VERSION_CODES.N_MR1 -> "7.1 Nougat";
|
||||
case Build.VERSION_CODES.O -> "8.0 Oreo";
|
||||
case Build.VERSION_CODES.O_MR1 -> "8.1 Oreo";
|
||||
case Build.VERSION_CODES.P -> "9.0 Pie";
|
||||
case Build.VERSION_CODES.Q -> "10 (Q)";
|
||||
case Build.VERSION_CODES.R -> "11 (R)";
|
||||
case Build.VERSION_CODES.S -> "12 (S)";
|
||||
case Build.VERSION_CODES.S_V2 -> "12L";
|
||||
case Build.VERSION_CODES.TIRAMISU -> "13 Tiramisu";
|
||||
default -> "Sdk: " + version;
|
||||
};
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val footer = findViewById<View>(R.id.markdownFooter)
|
||||
if (footer != null) footer.minimumHeight = this.navigationBarHeight
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
View footer = findViewById(R.id.markdownFooter);
|
||||
if (footer != null) footer.setMinimumHeight(this.getNavigationBarHeight());
|
||||
companion object {
|
||||
private val redirects = HashMap<String, String>(4)
|
||||
private val variants = arrayOf("readme.md", "README.MD", ".github/README.md")
|
||||
@Throws(IOException::class)
|
||||
private fun getRawMarkdown(url: String): ByteArray {
|
||||
var newUrl = redirects[url]
|
||||
return if (newUrl != null && newUrl != url) {
|
||||
Http.doHttpGet(newUrl, true)
|
||||
} else try {
|
||||
Http.doHttpGet(url, true)
|
||||
} catch (e: IOException) {
|
||||
// Workaround GitHub README.md case sensitivity issue
|
||||
if (url.startsWith("https://raw.githubusercontent.com/") && url.endsWith("/README.md")) {
|
||||
val prefix = url.substring(0, url.length - 9)
|
||||
for (suffix in variants) {
|
||||
newUrl = prefix + suffix
|
||||
try { // Try with lowercase version
|
||||
val rawMarkdown = Http.doHttpGet(prefix + suffix, true)
|
||||
redirects[url] = newUrl // Avoid retries
|
||||
return rawMarkdown
|
||||
} catch (ignored: IOException) {
|
||||
}
|
||||
}
|
||||
}
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,19 +1,21 @@
|
||||
package com.fox2code.mmm.markdown;
|
||||
package com.fox2code.mmm.markdown
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.annotation.StringRes
|
||||
import com.fox2code.mmm.R
|
||||
|
||||
import com.fox2code.mmm.R;
|
||||
|
||||
public enum MarkdownChip {
|
||||
CHANGE_BOOT(R.string.module_can_change_boot, R.string.module_can_change_boot_desc),
|
||||
NEED_RAMDISK(R.string.module_needs_ramdisk, R.string.module_needs_ramdisk_desc),
|
||||
MIN_MAGISK(R.string.module_min_magisk_chip, 0),
|
||||
MIN_SDK(R.string.module_min_sdk_chip, 0),
|
||||
MAX_SDK(R.string.module_max_sdk_chip, 0);
|
||||
@StringRes public final int title, desc;
|
||||
|
||||
MarkdownChip(@StringRes int title,@StringRes int desc) {
|
||||
this.title = title;
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
enum class MarkdownChip(
|
||||
@field:StringRes @param:StringRes val title: Int,
|
||||
@field:StringRes @param:StringRes val desc: Int
|
||||
) {
|
||||
CHANGE_BOOT(
|
||||
R.string.module_can_change_boot,
|
||||
R.string.module_can_change_boot_desc
|
||||
),
|
||||
NEED_RAMDISK(
|
||||
R.string.module_needs_ramdisk, R.string.module_needs_ramdisk_desc
|
||||
),
|
||||
MIN_MAGISK(R.string.module_min_magisk_chip, 0), MIN_SDK(
|
||||
R.string.module_min_sdk_chip, 0
|
||||
),
|
||||
MAX_SDK(R.string.module_max_sdk_chip, 0)
|
||||
}
|
@ -1,57 +1,51 @@
|
||||
package com.fox2code.mmm.markdown;
|
||||
package com.fox2code.mmm.markdown
|
||||
|
||||
import java.util.ArrayList;
|
||||
import timber.log.Timber
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
public enum MarkdownUrlLinker {
|
||||
enum class MarkdownUrlLinker {
|
||||
;
|
||||
|
||||
public static String urlLinkify(String url) {
|
||||
int index = url.indexOf("https://");
|
||||
if (index == -1)
|
||||
return url;
|
||||
ArrayList<LinkifyTask> linkifyTasks = new ArrayList<>();
|
||||
int extra = 0;
|
||||
while (index != -1) {
|
||||
int end = url.indexOf(' ', index);
|
||||
end = end == -1 ? url.indexOf('\n', index) : Math.min(url.indexOf('\n', index), end);
|
||||
if (end == -1)
|
||||
end = url.length();
|
||||
if (index == 0 || '\n' == url.charAt(index - 1) || ' ' == url.charAt(index - 1)) {
|
||||
int endDomain = url.indexOf('/', index + 9);
|
||||
char endCh = url.charAt(end - 1);
|
||||
if (endDomain != -1 && endDomain < end && endCh != '>' && endCh != ')' && endCh != ']') {
|
||||
linkifyTasks.add(new LinkifyTask(index, end));
|
||||
extra += (end - index) + 4;
|
||||
Timber.d("Linkify url: %s", url.substring(end));
|
||||
}
|
||||
}
|
||||
index = url.indexOf("https://", end);
|
||||
private class LinkifyTask(val start: Int, val end: Int) {
|
||||
companion object {
|
||||
val NULL = LinkifyTask(0, 0)
|
||||
}
|
||||
if (linkifyTasks.isEmpty())
|
||||
return url;
|
||||
LinkifyTask prev = LinkifyTask.NULL;
|
||||
StringBuilder stringBuilder = new StringBuilder(url.length() + extra);
|
||||
for (LinkifyTask linkifyTask : linkifyTasks) {
|
||||
stringBuilder.append(url, prev.end, linkifyTask.start).append('[').append(url, linkifyTask.start, linkifyTask.end).append("](").append(url, linkifyTask.start, linkifyTask.end).append(')');
|
||||
prev = linkifyTask;
|
||||
}
|
||||
if (prev.end != url.length())
|
||||
stringBuilder.append(url, prev.end, url.length());
|
||||
Timber.i("Added Markdown link to " + linkifyTasks.size() + " urls");
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
private static class LinkifyTask {
|
||||
static final LinkifyTask NULL = new LinkifyTask(0, 0);
|
||||
|
||||
private final int start;
|
||||
private final int end;
|
||||
|
||||
private LinkifyTask(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun urlLinkify(url: String): String {
|
||||
var index = url.indexOf("https://")
|
||||
if (index == -1) return url
|
||||
val linkifyTasks = ArrayList<LinkifyTask>()
|
||||
var extra = 0
|
||||
while (index != -1) {
|
||||
var end = url.indexOf(' ', index)
|
||||
end = if (end == -1) url.indexOf('\n', index) else url.indexOf('\n', index)
|
||||
.coerceAtMost(end)
|
||||
if (end == -1) end = url.length
|
||||
if (index == 0 || '\n' == url[index - 1] || ' ' == url[index - 1]) {
|
||||
val endDomain = url.indexOf('/', index + 9)
|
||||
val endCh = url[end - 1]
|
||||
if (endDomain != -1 && endDomain < end && endCh != '>' && endCh != ')' && endCh != ']') {
|
||||
linkifyTasks.add(LinkifyTask(index, end))
|
||||
extra += end - index + 4
|
||||
Timber.d("Linkify url: %s", url.substring(end))
|
||||
}
|
||||
}
|
||||
index = url.indexOf("https://", end)
|
||||
}
|
||||
if (linkifyTasks.isEmpty()) return url
|
||||
var prev = LinkifyTask.NULL
|
||||
val stringBuilder = StringBuilder(url.length + extra)
|
||||
for (linkifyTask in linkifyTasks) {
|
||||
stringBuilder.append(url, prev.end, linkifyTask.start).append('[')
|
||||
.append(url, linkifyTask.start, linkifyTask.end).append("](")
|
||||
.append(url, linkifyTask.start, linkifyTask.end).append(')')
|
||||
prev = linkifyTask
|
||||
}
|
||||
if (prev.end != url.length) stringBuilder.append(url, prev.end, url.length)
|
||||
Timber.i("Added Markdown link to " + linkifyTasks.size + " urls")
|
||||
return stringBuilder.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue