Update SimpleMarkdownParser

This commit is contained in:
Gregor Santner 2017-07-29 04:44:28 +02:00
parent 0e7ff63c9a
commit 99e369088a
No known key found for this signature in database
GPG Key ID: 7E83A7834AECB009
10 changed files with 161 additions and 101 deletions

10
.gitignore vendored
View File

@ -1,10 +1,10 @@
##############
### Project ##
app/src/main/res/raw/changelog.md
app/src/main/res/raw/contributors.md
app/src/main/res/raw/license.md
app/src/main/res/raw/readme.md
app/src/main/res/raw/contributors.txt
app/src/main/res/raw/changelog.*
app/src/main/res/raw/contributors.*
app/src/main/res/raw/license.*
app/src/main/res/raw/readme.*
app/src/main/res/raw/contributors.*
#app/src/main/res/raw/podlist.json
##############

View File

@ -1,3 +1,6 @@
### v1.0.1
- Update SimpleMarkdownParser
### v1.0.0 (2017-06-14)
- Added AMOLED mode
- Improve NavDrawer

32
CONTRIBUTORS.md Normal file
View File

@ -0,0 +1,32 @@
<!--
This file contains references to people who contributed to the app.
If you helped by translating the app, please send a message on Crowdin.
You can also send a mail to [gsantner AT mailbox DOT org](https://gsantner.github.io#contact) to get included.
Schema: **[Name](Reference)**<br/>~° Text
Where:
* Name: username, first/lastname
* Reference: E-Mail, Webpage
* Text: Information about / kind of contribution
## LIST OF CONTRIBUTORS
-->
* **[Gregor Santner](https://gsantner.github.io)**<br/>~° Current developer of dandelion
* **[Paul Schaub](https://github.com/vanitasvitae)**<br/>~° Development of dandelion
* **[Abhijith Balan](abhijithb21 AT openmailbox DOT org)**<br/>~° Malayalam translation
* **[Airon90](https://diasp.eu/u/airon90)**<br/>~° Italian translation
* **[Gaukler Faun](https://github.com/scoute-dich)**<br/>~° Diaspora Native WebApp additions
* **[Martín Vukovic](martinvukovic AT protonmail DOT com)**<br/>~° Diaspora Native WebApp
* **[Nacho Fernández](nacho_f AT joindiaspora DOT com)**<br/>~° Spanish translation
* **[Naofumi Fukue](https://github.com/naofum)**<br/>~° Japanese translation
* **[pskosinski](email AT pskosinski DOT pl)**<br/>~° Polish translation
* **[SansPseudoFix](https://github.com/SansPseudoFix)**<br/>~° French translation
* **[secitem](secitem AT tuta DOT io)**<br/>~° Czech translation
* **[Zsolt Szakács](maxigaz AT diaspora DOT zone)**<br/>~° Hungarian translation
* **[Danilo Raffaelli](https://crowdin.com/profile/Daraf)**<br/>~° Italian translation
* **[O'Loubám](loubam AT diasp DOT org)**<br/>~° Galician translation
* **[transifex3](https://crowdin.com/profile/transifex3)**<br/>~° Korean translation
* **[Âng Iōngchun](https://pubpod.alqualonde.org/u/iongchun)**<br/>~° Chinese traditional translation

View File

@ -1,24 +0,0 @@
00l>> This file contains references to people who contributed to the app.
01l>> If you helped by translating the app, please send a message on Crowdin.
02l>> You can also send a mail to [gdev AT live DOT de](https://gsantner.github.io/about/email/) to get included.
03l>>
04l>> Schemes:
05l>> Firstname Lastname (Link): Text
06l>> Firstname Lastname (E-Mail): Text
07l>> Username (Link): Text
08l>> Username (E-Mail): Text
## 99l CONTRIBUTORS
Abhijith Balan (abhijithb21 AT openmailbox DOT org): Malayalam translation
Airon90 (https://diasp.eu/u/airon90): Italian translation
Gaukler Faun (https://github.com/scoute-dich): Diaspora Native WebApp additions
Martín Vukovic (martinvukovic AT protonmail DOT com): Diaspora Native WebApp
Nacho Fernández (nacho_f AT joindiaspora DOT com): Spanish translation
Naofumi Fukue (https://github.com/naofum): Japanese translation
pskosinski (email AT pskosinski DOT pl): Polish translation
SansPseudoFix (https://github.com/SansPseudoFix): French translation
secitem (secitem AT tuta DOT io): Czech translation
Zsolt Szakács (maxigaz AT diaspora DOT zone): Hungarian translation
Danilo Raffaelli (https://crowdin.com/profile/Daraf): Italian translation
O'Loubám (loubam AT diasp DOT org): Galician translation
transifex3 (https://crowdin.com/profile/transifex3): Korean translation
Âng Iōngchun (https://pubpod.alqualonde.org/u/iongchun): Chinese traditional translation

View File

@ -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()

View File

@ -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;

View File

@ -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) {

View File

@ -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();

View File

@ -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)

View File

@ -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("", "&nbsp;&nbsp;") // 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'>&#8226;</font> $2 ") // unordered list + end line
.replaceAll("^ (-|\\*) ([^<]*)", "&nbsp;&nbsp;<font color='#000001'>&#8226;</font> $2 ") // unordered list2 + end line
.replaceAll("(?m)^([-*] )(.*)$", "<font color='#000001'>&#8226;</font> $2<br/>") // unordered list + end line
.replaceAll("(?m)^ (-|\\*) ([^<]*)$", "&nbsp;&nbsp;<font color='#000001'>&#8226;</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("", "&nbsp;&nbsp;") // 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'>&#8226;</font> $2 ") // unordered list + end line
.replaceAll("^ (-|\\*) ([^<]*)", "&nbsp;&nbsp;<font color='#000001'>&#8226;</font> $2 ") // unordered list2 + end line
.replaceAll("(?m)^([-*] )(.*)$", "<font color='#000001'>&#8226;</font> $2 ") // unordered list + end line
.replaceAll("(?m)^ (-|\\*) ([^<]*)$", "&nbsp;&nbsp;<font color='#000001'>&#8226;</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;
}