making java kotlin since 2023(tm)

Signed-off-by: androidacy-user <opensource@androidacy.com>
pull/27/head
androidacy-user 2 years ago
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…
Cancel
Save