mirror of
https://github.com/gsantner/dandelion
synced 2025-09-09 10:19:42 +02:00
Update SimpleMarkdownParser
This commit is contained in:
parent
0e7ff63c9a
commit
99e369088a
10 changed files with 161 additions and 101 deletions
|
@ -9,8 +9,8 @@ android {
|
|||
minSdkVersion 17
|
||||
targetSdkVersion 24
|
||||
|
||||
versionCode 20
|
||||
versionName "1.0.0"
|
||||
versionCode 21
|
||||
versionName "1.0.1-dev"
|
||||
|
||||
applicationId "com.github.dfa.diaspora_android"
|
||||
resValue 'string', 'app_name', "dandelion*"
|
||||
|
@ -86,7 +86,7 @@ dependencies {
|
|||
// Groovy Coding Area
|
||||
// #####################
|
||||
final String RAW_DIR = "app/src/main/res/raw"
|
||||
final String[] ROOT_TO_RAW_COPYFILES = ["README.md", "LICENSE.md", "CHANGELOG.md", "CONTRIBUTORS.txt"]
|
||||
final String[] ROOT_TO_RAW_COPYFILES = ["README.md", "LICENSE.md", "CHANGELOG.md", "CONTRIBUTORS.md"]
|
||||
|
||||
// Called before building
|
||||
task copyRepoFiles(type: Copy) {
|
||||
|
@ -97,16 +97,5 @@ task copyRepoFiles(type: Copy) {
|
|||
rename { String fileName ->
|
||||
fileName.replace(fileName, fileName.toLowerCase())
|
||||
}
|
||||
|
||||
// Filter Contributors file
|
||||
from(rootProject.file("CONTRIBUTORS.txt")) {
|
||||
into '.' // Target already changed to 'src/main/res/raw'
|
||||
rename { String fileName ->
|
||||
fileName.replace(fileName, fileName.toLowerCase())
|
||||
}
|
||||
filter { line ->
|
||||
(line.toString().matches("..l>>.*") || line.toString().startsWith("## 99l CONTRIBUTORS")) ? null : line.toString().trim().replaceAll(" \\(.*\\)", "")
|
||||
}
|
||||
}
|
||||
}
|
||||
tasks.copyRepoFiles.execute()
|
||||
|
|
|
@ -268,7 +268,7 @@ public class AboutActivity extends ThemedActivity
|
|||
maintainers.setTextFormatted(getString(R.string.fragment_license__maintainers_text,
|
||||
Helpers.get().loadMarkdownForTextViewFromRaw(R.raw.maintainers, "")));
|
||||
contributors.setTextFormatted(getString(R.string.fragment_license__contributors_thank_you,
|
||||
Helpers.get().loadMarkdownForTextViewFromRaw(R.raw.contributors, "* ")));
|
||||
Helpers.get().loadMarkdownForTextViewFromRaw(R.raw.contributors, "")));
|
||||
thirdPartyLibs.setTextFormatted(
|
||||
Helpers.get().loadMarkdownForTextViewFromRaw(R.raw.license_third_party, ""));
|
||||
return rootView;
|
||||
|
|
|
@ -221,22 +221,20 @@ public class MainActivity extends ThemedActivity
|
|||
|
||||
// Show first start dialog
|
||||
try {
|
||||
SimpleMarkdownParser mdParser = SimpleMarkdownParser.get().setDefaultSmpFilter(SimpleMarkdownParser.FILTER_ANDROID_TEXTVIEW);
|
||||
if (appSettings.isAppFirstStart()) {
|
||||
SimpleMarkdownParser smp = new SimpleMarkdownParser().parse(
|
||||
getResources().openRawResource(R.raw.license),
|
||||
SimpleMarkdownParser.FILTER_ANDROID_TEXTVIEW, "");
|
||||
String html = smp.getHtml()
|
||||
mdParser.parse(
|
||||
getResources().openRawResource(R.raw.license), "");
|
||||
String html = mdParser.getHtml()
|
||||
+ "<br/><br/><br/>"
|
||||
+ "<h1>" + getString(R.string.fragment_license__thirdparty_libs) + "</h1>"
|
||||
+ smp.parse(getResources().openRawResource(R.raw.license_third_party),
|
||||
SimpleMarkdownParser.FILTER_ANDROID_TEXTVIEW, "");
|
||||
html = smp.setHtml(html).removeMultiNewlines().getHtml();
|
||||
+ mdParser.parse(getResources().openRawResource(R.raw.license_third_party), "");
|
||||
html = mdParser.setHtml(html).removeMultiNewlines().getHtml();
|
||||
HelpersA.get(this).showDialogWithHtmlTextView(R.string.about_activity__title_about_license, html);
|
||||
appSettings.isAppCurrentVersionFirstStart();
|
||||
} else if (appSettings.isAppCurrentVersionFirstStart()) {
|
||||
SimpleMarkdownParser smp = new SimpleMarkdownParser().parse(
|
||||
getResources().openRawResource(R.raw.changelog),
|
||||
SimpleMarkdownParser.FILTER_ANDROID_TEXTVIEW, "");
|
||||
getResources().openRawResource(R.raw.changelog), "");
|
||||
HelpersA.get(this).showDialogWithHtmlTextView(R.string.changelog, smp.getHtml());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* worth it, you can buy me a coke in return. Provided as is without any kind
|
||||
* of warranty. No attribution required. - Gregor Santner
|
||||
*
|
||||
* License: Creative Commons Zero (CC0 1.0)
|
||||
* License of this file: Creative Commons Zero (CC0 1.0)
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -32,19 +32,25 @@ import android.support.annotation.StringRes;
|
|||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.AppCompatButton;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.util.Linkify;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.BuildConfig;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.github.dfa.diaspora_android.App;
|
||||
import com.github.dfa.diaspora_android.BuildConfig;
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue"})
|
||||
public class Helpers {
|
||||
protected Context context;
|
||||
|
@ -177,7 +183,7 @@ public class Helpers {
|
|||
try {
|
||||
return new SimpleMarkdownParser()
|
||||
.parse(context.getResources().openRawResource(rawMdFile),
|
||||
SimpleMarkdownParser.FILTER_ANDROID_TEXTVIEW, prepend)
|
||||
prepend, SimpleMarkdownParser.FILTER_ANDROID_TEXTVIEW)
|
||||
.replaceColor("#000001", color(R.color.accent))
|
||||
.removeMultiNewlines().replaceBulletCharacter("*").getHtml();
|
||||
} catch (IOException e) {
|
||||
|
@ -186,6 +192,17 @@ public class Helpers {
|
|||
}
|
||||
}
|
||||
|
||||
public void setHtmlToTextView(TextView textView, String html) {
|
||||
Spanned spanned;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
spanned = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
|
||||
} else {
|
||||
spanned = Html.fromHtml(html);
|
||||
}
|
||||
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
textView.setText(new SpannableString(spanned));
|
||||
}
|
||||
|
||||
public double getEstimatedScreenSizeInches() {
|
||||
DisplayMetrics dm = context.getResources().getDisplayMetrics();
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* worth it, you can buy me a coke in return. Provided as is without any kind
|
||||
* of warranty. No attribution required. - Gregor Santner
|
||||
*
|
||||
* License: Creative Commons Zero (CC0 1.0)
|
||||
* License of this file: Creative Commons Zero (CC0 1.0)
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -20,7 +20,7 @@ import android.support.v7.app.AlertDialog;
|
|||
import android.support.v7.widget.AppCompatTextView;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableString;
|
||||
import android.text.method.ScrollingMovementMethod;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.TypedValue;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
|
@ -91,17 +91,17 @@ public class HelpersA extends Helpers {
|
|||
}
|
||||
|
||||
public void showDialogWithHtmlTextView(@StringRes int resTitleId, String html) {
|
||||
showDialogWithHtmlTextView(resTitleId, html, null);
|
||||
showDialogWithHtmlTextView(resTitleId, html, true, null);
|
||||
}
|
||||
|
||||
public void showDialogWithHtmlTextView(@StringRes int resTitleId, String html, DialogInterface.OnDismissListener dismissedListener) {
|
||||
public void showDialogWithHtmlTextView(@StringRes int resTitleId, String text, boolean isHtml, DialogInterface.OnDismissListener dismissedListener) {
|
||||
AppCompatTextView textView = new AppCompatTextView(context);
|
||||
int padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16,
|
||||
context.getResources().getDisplayMetrics());
|
||||
textView.setMovementMethod(new ScrollingMovementMethod());
|
||||
textView.setMovementMethod(new LinkMovementMethod());
|
||||
textView.setPadding(padding, 0, padding, 0);
|
||||
|
||||
textView.setText(new SpannableString(Html.fromHtml(html)));
|
||||
textView.setText(isHtml ? new SpannableString(Html.fromHtml(text)) : text);
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(context)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setOnDismissListener(dismissedListener)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* worth it, you can buy me a coke in return. Provided as is without any kind
|
||||
* of warranty. No attribution required. - Gregor Santner
|
||||
*
|
||||
* License: Creative Commons Zero (CC0 1.0)
|
||||
* License of this file: Creative Commons Zero (CC0 1.0)
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -22,9 +22,9 @@
|
|||
*
|
||||
* FILTER_ANDROID_TEXTVIEW output is intended to be used at simple Android TextViews,
|
||||
* were a limited set of html tags is supported. This allow to still display e.g. a simple
|
||||
* CHANGELOG.md file without inlcuding a WebView for showing HTML, or other additional UI-libraries.
|
||||
* CHANGELOG.md file without including a WebView for showing HTML, or other additional UI-libraries.
|
||||
*
|
||||
* FILTER_HTMLPART is intended to be used at engines understanding most common HTML tags.
|
||||
* FILTER_WEB is intended to be used at engines understanding most common HTML tags.
|
||||
*/
|
||||
|
||||
package io.github.gsantner.opoc.util;
|
||||
|
@ -38,72 +38,105 @@ import java.io.InputStreamReader;
|
|||
/**
|
||||
* Simple Markdown Parser
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "CaughtExceptionImmediatelyRethrown"})
|
||||
@SuppressWarnings({"WeakerAccess", "CaughtExceptionImmediatelyRethrown", "SameParameterValue", "unused", "SpellCheckingInspection", "RepeatedSpace", "SingleCharAlternation"})
|
||||
public class SimpleMarkdownParser {
|
||||
public interface SimpleLineFilter {
|
||||
String filterLine(String line);
|
||||
private static SimpleMarkdownParser instance;
|
||||
|
||||
public static SimpleMarkdownParser get() {
|
||||
if (instance == null) {
|
||||
instance = new SimpleMarkdownParser();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static final SimpleLineFilter FILTER_ANDROID_TEXTVIEW = new SimpleLineFilter() {
|
||||
public interface SmpFilter {
|
||||
String filter(String text);
|
||||
}
|
||||
|
||||
public final static SmpFilter FILTER_ANDROID_TEXTVIEW = new SmpFilter() {
|
||||
@Override
|
||||
public String filterLine(String line) {
|
||||
public String filter(String text) {
|
||||
// TextView supports a limited set of html tags, most notably
|
||||
// a href, b, big, font size&color, i, li, small, u
|
||||
line = line
|
||||
|
||||
// Don't start new line if 2 empty lines and heading
|
||||
while (text.contains("\n\n#")) {
|
||||
text = text.replace("\n\n#", "\n#");
|
||||
}
|
||||
|
||||
return text
|
||||
.replaceAll("(?s)<!--.*?-->", "") // HTML comments
|
||||
.replace("\n\n", "\n<br/>\n") // Start new line if 2 empty lines
|
||||
.replace("~°", " ") // double space/half tab
|
||||
.replaceAll("^### ([^<]*)", "<br/><big><b><font color='#000000'>$1</font></b></big> ") // h3
|
||||
.replaceAll("^## ([^<]*)", "<br/><big><big><b><font color='#000000'>$1</font></b></big></big><br/> ") // h2 (DEP: h3)
|
||||
.replaceAll("^# ([^<]*)", "<br/><big><big><big><b><font color='#000000'>$1</font></b></big></big></big><br/> ") // h1 (DEP: h2,h3)
|
||||
.replaceAll("(?m)^### (.*)$", "<br/><big><b><font color='#000000'>$1</font></b></big><br/>") // h3
|
||||
.replaceAll("(?m)^## (.*)$", "<br/><big><big><b><font color='#000000'>$1</font></b></big></big><br/><br/>") // h2 (DEP: h3)
|
||||
.replaceAll("(?m)^# (.*)$", "<br/><big><big><big><b><font color='#000000'>$1</font></b></big></big></big><br/><br/>") // h1 (DEP: h2,h3)
|
||||
.replaceAll("!\\[(.*?)\\]\\((.*?)\\)", "<a href=\\'$2\\'>$1</a>") // img
|
||||
.replaceAll("\\[(.*?)\\]\\((.*?)\\)", "<a href=\\'$2\\'>$1</a>") // a href (DEP: img)
|
||||
.replaceAll("<(http|https):\\/\\/(.*)>", "<a href='$1://$2'>$1://$2</a>") // a href (DEP: img)
|
||||
.replaceAll("^(-|\\*) ([^<]*)", "<font color='#000001'>•</font> $2 ") // unordered list + end line
|
||||
.replaceAll("^ (-|\\*) ([^<]*)", " <font color='#000001'>•</font> $2 ") // unordered list2 + end line
|
||||
.replaceAll("(?m)^([-*] )(.*)$", "<font color='#000001'>•</font> $2<br/>") // unordered list + end line
|
||||
.replaceAll("(?m)^ (-|\\*) ([^<]*)$", " <font color='#000001'>•</font> $2<br/>") // unordered list2 + end line
|
||||
.replaceAll("`([^<]*)`", "<font face='monospace'>$1</font>") // code
|
||||
.replace("\\*", "●") // temporary replace escaped star symbol
|
||||
.replaceAll("\\*\\*([^<]*)\\*\\*", "<b>$1</b>") // bold (DEP: temp star)
|
||||
.replaceAll("\\*([^<]*)\\*", "<i>$1</i>") // italic (DEP: temp star code)
|
||||
.replaceAll("(?m)\\*\\*(.*)\\*\\*", "<b>$1</b>") // bold (DEP: temp star)
|
||||
.replaceAll("(?m)\\*(.*)\\*", "<i>$1</i>") // italic (DEP: temp star code)
|
||||
.replace("●", "*") // restore escaped star symbol (DEP: b,i)
|
||||
.replaceAll(" $", "<br/>") // new line (DEP: ul)
|
||||
;
|
||||
return line.isEmpty() ? line + "<br/>" : line;
|
||||
.replaceAll("(?m) $", "<br/>") // new line (DEP: ul)
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
public static final SimpleLineFilter FILTER_HTMLPART = new SimpleLineFilter() {
|
||||
public final static SmpFilter FILTER_WEB = new SmpFilter() {
|
||||
@Override
|
||||
public String filterLine(String line) {
|
||||
line = line
|
||||
public String filter(String text) {
|
||||
// Don't start new line if 2 empty lines and heading
|
||||
while (text.contains("\n\n#")) {
|
||||
text = text.replace("\n\n#", "\n#");
|
||||
}
|
||||
|
||||
text = text
|
||||
.replaceAll("(?s)<!--.*?-->", "") // HTML comments
|
||||
.replace("\n\n", "\n<br/>\n") // Start new line if 2 empty lines
|
||||
.replaceAll("~°", " ") // double space/half tab
|
||||
.replaceAll("^### ([^<]*)", "<h3>$1</h3>") // h3
|
||||
.replaceAll("^## ([^<]*)", "<h2>$1</h2>") /// h2 (DEP: h3)
|
||||
.replaceAll("^# ([^<]*)", "<h1>$1</h1>") // h1 (DEP: h2,h3)
|
||||
.replaceAll("(?m)^### (.*)$", "<h3>$1</h3>") // h3
|
||||
.replaceAll("(?m)^## (.*)$", "<h2>$1</h2>") /// h2 (DEP: h3)
|
||||
.replaceAll("(?m)^# (.*)$", "<h1>$1</h1>") // h1 (DEP: h2,h3)
|
||||
.replaceAll("!\\[(.*?)\\]\\((.*?)\\)", "<img src=\\'$2\\' alt='$1' />") // img
|
||||
.replaceAll("<(http|https):\\/\\/(.*)>", "<a href='$1://$2'>$1://$2</a>") // a href (DEP: img)
|
||||
.replaceAll("\\[(.*?)\\]\\((.*?)\\)", "<a href=\\'$2\\'>$1</a>") // a href (DEP: img)
|
||||
.replaceAll("^(-|\\*) ([^<]*)", "<font color='#000001'>•</font> $2 ") // unordered list + end line
|
||||
.replaceAll("^ (-|\\*) ([^<]*)", " <font color='#000001'>•</font> $2 ") // unordered list2 + end line
|
||||
.replaceAll("(?m)^([-*] )(.*)$", "<font color='#000001'>•</font> $2 ") // unordered list + end line
|
||||
.replaceAll("(?m)^ (-|\\*) ([^<]*)$", " <font color='#000001'>•</font> $2 ") // unordered list2 + end line
|
||||
.replaceAll("`([^<]*)`", "<code>$1</code>") // code
|
||||
.replace("\\*", "●") // temporary replace escaped star symbol
|
||||
.replaceAll("\\*\\*([^<]*)\\*\\*", "<b>$1</b>") // bold (DEP: temp star)
|
||||
.replaceAll("\\*([^<]*)\\*", "<b>$1</b>") // italic (DEP: temp star)
|
||||
.replaceAll("(?m)\\*\\*(.*)\\*\\*", "<b>$1</b>") // bold (DEP: temp star)
|
||||
.replaceAll("(?m)\\*(.*)\\*", "<i>$1</i>") // italic (DEP: temp star code)
|
||||
.replace("●", "*") // restore escaped star symbol (DEP: b,i)
|
||||
.replaceAll(" $", "<br/>") // new line (DEP: ul)
|
||||
.replaceAll("(?m) $", "<br/>") // new line (DEP: ul)
|
||||
;
|
||||
return line.isEmpty() ? line + "<br/>" : line;
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
//########################
|
||||
//## Members
|
||||
//########################
|
||||
private SmpFilter defaultSmpFilter;
|
||||
private String html;
|
||||
|
||||
public SimpleMarkdownParser parse(String filepath, SimpleLineFilter simpleLineFilter) throws IOException {
|
||||
return parse(new FileInputStream(filepath), simpleLineFilter, "");
|
||||
public SimpleMarkdownParser() {
|
||||
setDefaultSmpFilter(FILTER_WEB);
|
||||
}
|
||||
|
||||
public SimpleMarkdownParser parse(InputStream inputStream, SimpleLineFilter simpleLineFilter, String lineMdPrefix) throws IOException {
|
||||
public SimpleMarkdownParser setDefaultSmpFilter(SmpFilter defaultSmpFilter) {
|
||||
this.defaultSmpFilter = defaultSmpFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleMarkdownParser parse(String filepath, SmpFilter... smpFilters) throws IOException {
|
||||
return parse(new FileInputStream(filepath), "", smpFilters);
|
||||
}
|
||||
|
||||
public SimpleMarkdownParser parse(InputStream inputStream, String lineMdPrefix, SmpFilter... smpFilters) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader br = null;
|
||||
String line;
|
||||
|
@ -111,7 +144,8 @@ public class SimpleMarkdownParser {
|
|||
try {
|
||||
br = new BufferedReader(new InputStreamReader(inputStream));
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(simpleLineFilter.filterLine(lineMdPrefix + line));
|
||||
sb.append(lineMdPrefix);
|
||||
sb.append(line);
|
||||
sb.append("\n");
|
||||
}
|
||||
} catch (IOException rethrow) {
|
||||
|
@ -125,7 +159,18 @@ public class SimpleMarkdownParser {
|
|||
}
|
||||
}
|
||||
}
|
||||
html = sb.toString().trim();
|
||||
html = parse(sb.toString(), "", smpFilters).getHtml();
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleMarkdownParser parse(String markdown, String lineMdPrefix, SmpFilter... smpFilters) throws IOException {
|
||||
html = markdown;
|
||||
if (smpFilters.length == 0) {
|
||||
smpFilters = new SmpFilter[]{defaultSmpFilter};
|
||||
}
|
||||
for (SmpFilter smpFilter : smpFilters) {
|
||||
html = smpFilter.filter(html).trim();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue