Syntax highlight HTML

pull/214/head
M66B 1 year ago
parent 45d94fecb0
commit 304d6de2da

@ -48,3 +48,4 @@ FairEmail uses parts or all of:
* [Send](https://github.com/timvisee/send). [Mozilla Public License 2.0](https://github.com/timvisee/send/blob/master/LICENSE). * [Send](https://github.com/timvisee/send). [Mozilla Public License 2.0](https://github.com/timvisee/send/blob/master/LICENSE).
* [DetectHtml](https://github.com/dbennett455/DetectHtml). [The MIT License](https://github.com/dbennett455/DetectHtml/blob/master/LICENSE). * [DetectHtml](https://github.com/dbennett455/DetectHtml). [The MIT License](https://github.com/dbennett455/DetectHtml/blob/master/LICENSE).
* [Liberation Sans Narrow font](https://github.com/liberationfonts/liberation-sans-narrow). Copyright (C) 1989, 1991 Free Software Foundation, Inc. [GNU General Public License version 2 with exceptions](https://fedoraproject.org/wiki/Licensing/LiberationFontLicense). * [Liberation Sans Narrow font](https://github.com/liberationfonts/liberation-sans-narrow). Copyright (C) 1989, 1991 Free Software Foundation, Inc. [GNU General Public License version 2 with exceptions](https://fedoraproject.org/wiki/Licensing/LiberationFontLicense).
* [Prism](https://github.com/PrismJS/prism). Copyright (c) 2012 Lea Verou. [MIT LICENSE](https://github.com/PrismJS/prism/blob/master/LICENSE).

@ -83,7 +83,7 @@ android {
// https://developer.android.com/reference/tools/gradle-api/8.0/com/android/build/api/dsl/LintOptions // https://developer.android.com/reference/tools/gradle-api/8.0/com/android/build/api/dsl/LintOptions
abortOnError true abortOnError true
checkReleaseBuilds false checkReleaseBuilds false
checkDependencies false //checkDependencies false
disable 'MissingTranslation' disable 'MissingTranslation'
fatal 'StringFormatInvalid', 'StringFormatMatches', 'StringFormatCount' fatal 'StringFormatInvalid', 'StringFormatMatches', 'StringFormatCount'
checkOnly 'StringFormatInvalid', 'StringFormatMatches', 'StringFormatCount' checkOnly 'StringFormatInvalid', 'StringFormatMatches', 'StringFormatCount'

@ -475,7 +475,7 @@
</activity> </activity>
<activity <activity
android:name=".ActivityHTML" android:name=".ActivityCode"
android:description="@string/app_name" android:description="@string/app_name"
android:exported="false" android:exported="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"

@ -482,7 +482,7 @@
</activity> </activity>
<activity <activity
android:name=".ActivityHTML" android:name=".ActivityCode"
android:description="@string/app_name" android:description="@string/app_name"
android:exported="false" android:exported="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"

@ -481,7 +481,7 @@
</activity> </activity>
<activity <activity
android:name=".ActivityHTML" android:name=".ActivityCode"
android:description="@string/app_name" android:description="@string/app_name"
android:exported="false" android:exported="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"

@ -481,7 +481,7 @@
</activity> </activity>
<activity <activity
android:name=".ActivityHTML" android:name=".ActivityCode"
android:description="@string/app_name" android:description="@string/app_name"
android:exported="false" android:exported="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"

@ -477,7 +477,7 @@
</activity> </activity>
<activity <activity
android:name=".ActivityHTML" android:name=".ActivityCode"
android:description="@string/app_name" android:description="@string/app_name"
android:exported="false" android:exported="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"

@ -48,3 +48,4 @@ FairEmail uses parts or all of:
* [Send](https://github.com/timvisee/send). [Mozilla Public License 2.0](https://github.com/timvisee/send/blob/master/LICENSE). * [Send](https://github.com/timvisee/send). [Mozilla Public License 2.0](https://github.com/timvisee/send/blob/master/LICENSE).
* [DetectHtml](https://github.com/dbennett455/DetectHtml). [The MIT License](https://github.com/dbennett455/DetectHtml/blob/master/LICENSE). * [DetectHtml](https://github.com/dbennett455/DetectHtml). [The MIT License](https://github.com/dbennett455/DetectHtml/blob/master/LICENSE).
* [Liberation Sans Narrow font](https://github.com/liberationfonts/liberation-sans-narrow). Copyright (C) 1989, 1991 Free Software Foundation, Inc. [GNU General Public License version 2 with exceptions](https://fedoraproject.org/wiki/Licensing/LiberationFontLicense). * [Liberation Sans Narrow font](https://github.com/liberationfonts/liberation-sans-narrow). Copyright (C) 1989, 1991 Free Software Foundation, Inc. [GNU General Public License version 2 with exceptions](https://fedoraproject.org/wiki/Licensing/LiberationFontLicense).
* [Prism](https://github.com/PrismJS/prism). Copyright (c) 2012 Lea Verou. [MIT LICENSE](https://github.com/PrismJS/prism/blob/master/LICENSE).

@ -0,0 +1,3 @@
/* PrismJS 1.29.0
https://prismjs.com/download.html#themes=prism-solarizedlight&languages=markup+css+clike+javascript */
code[class*=language-],pre[class*=language-]{color:#657b83;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{background:#073642}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{background:#073642}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background-color:#fdf6e3}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#93a1a1}.token.punctuation{color:#586e75}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#268bd2}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string,.token.url{color:#2aa198}.token.entity{color:#657b83;background:#eee8d5}.token.atrule,.token.attr-value,.token.keyword{color:#859900}.token.class-name,.token.function{color:#b58900}.token.important,.token.regex,.token.variable{color:#cb4b16}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}

File diff suppressed because one or more lines are too long

@ -22,14 +22,20 @@ package eu.faircode.email;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.text.Html;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.activity.OnBackPressedCallback; import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -41,10 +47,11 @@ import org.jsoup.nodes.Element;
import org.w3c.dom.css.CSSStyleSheet; import org.w3c.dom.css.CSSStyleSheet;
import java.io.File; import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
public class ActivityHTML extends ActivityBase { public class ActivityCode extends ActivityBase {
private TextView tvText; private WebView wvCode;
private ContentLoadingProgressBar pbWait; private ContentLoadingProgressBar pbWait;
private Group grpReady; private Group grpReady;
@ -66,13 +73,16 @@ public class ActivityHTML extends ActivityBase {
} }
}); });
View view = LayoutInflater.from(this).inflate(R.layout.activity_text, null); View view = LayoutInflater.from(this).inflate(R.layout.activity_code, null);
setContentView(view); setContentView(view);
tvText = findViewById(R.id.tvText); wvCode = findViewById(R.id.wvCode);
pbWait = findViewById(R.id.pbWait); pbWait = findViewById(R.id.pbWait);
grpReady = findViewById(R.id.grpReady); grpReady = findViewById(R.id.grpReady);
WebSettings settings = wvCode.getSettings();
settings.setJavaScriptEnabled(true);
// Initialize // Initialize
grpReady.setVisibility(View.GONE); grpReady.setVisibility(View.GONE);
@ -95,7 +105,7 @@ public class ActivityHTML extends ActivityBase {
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater(); MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_html, menu); inflater.inflate(R.menu.menu_code, menu);
return true; return true;
} }
@ -158,9 +168,9 @@ public class ActivityHTML extends ActivityBase {
args.putString("subject", message.subject); args.putString("subject", message.subject);
File file = message.getFile(context); File file = message.getFile(context);
if (sanitize) {
Document d = JsoupEx.parse(file); Document d = JsoupEx.parse(file);
if (sanitize) {
List<CSSStyleSheet> sheets = List<CSSStyleSheet> sheets =
HtmlHelper.parseStyles(d.head().select("style")); HtmlHelper.parseStyles(d.head().select("style"));
for (Element element : d.select("*")) { for (Element element : d.select("*")) {
@ -175,17 +185,30 @@ public class ActivityHTML extends ActivityBase {
d = HtmlHelper.sanitizeView(context, d, false); d = HtmlHelper.sanitizeView(context, d, false);
d.outputSettings().prettyPrint(true).outline(true).indentAmount(1); d.outputSettings().prettyPrint(true).outline(true).indentAmount(1);
}
return d.html(); return d.html();
} else
return Helper.readText(file);
} }
@Override @Override
protected void onExecuted(Bundle args, String text) { protected void onExecuted(Bundle args, String code) {
getSupportActionBar().setSubtitle(args.getString("subject")); getSupportActionBar().setSubtitle(args.getString("subject"));
tvText.setText(text); String html = "<!DOCTYPE html>" +
"<html>" +
"<head>" +
"<link href=\"file:///android_asset/prism.css\" rel=\"stylesheet\" />" +
"<style>" +
" code[class=\"language-html\"] { font-size: smaller !important; }" +
"</style>" +
"</head>" +
"<body>" +
"<script src=\"file:///android_asset/prism.js\"></script>" +
"<code class=\"language-html\">" + Html.escapeHtml(code) + "</code>" +
"</body>" +
"</html>";
wvCode.loadDataWithBaseURL("file:///android_asset/", html, "text/html", StandardCharsets.UTF_8.name(), null);
grpReady.setVisibility(View.VISIBLE); grpReady.setVisibility(View.VISIBLE);
} }

@ -7407,7 +7407,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
} }
private void onMenuShareHtml(TupleMessageEx message) { private void onMenuShareHtml(TupleMessageEx message) {
context.startActivity(new Intent(context, ActivityHTML.class) context.startActivity(new Intent(context, ActivityCode.class)
.putExtra("id", message.id)); .putExtra("id", message.id));
} }

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M11,3h2v8h-2z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
android:pathData="M16,13H8c-1.65,0 -3,1.35 -3,3v5h2v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h2v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h2v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3h2v-5C19,14.35 17.65,13 16,13z"
android:strokeAlpha="0.3"
android:fillAlpha="0.3"/>
<path
android:fillColor="@android:color/white"
android:pathData="M16,11h-1V3c0,-1.1 -0.9,-2 -2,-2h-2C9.9,1 9,1.9 9,3v8H8c-2.76,0 -5,2.24 -5,5v7h18v-7C21,13.24 18.76,11 16,11zM11,3h2v8h-2V3zM19,21h-2v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3h-2v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3H9v-3c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v3H5v-5c0,-1.65 1.35,-3 3,-3h8c1.65,0 3,1.35 3,3V21z"/>
</vector>

@ -3,26 +3,16 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="eu.faircode.email.ActivityHTML"> tools:context="eu.faircode.email.ActivityCode">
<ScrollView <WebView
android:id="@+id/wvCode"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:fillViewport="true"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fontFamily="monospace"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?android:attr/textColorPrimary"
android:textIsSelectable="true" />
</ScrollView>
<eu.faircode.email.ContentLoadingProgressBar <eu.faircode.email.ContentLoadingProgressBar
android:id="@+id/pbWait" android:id="@+id/pbWait"

@ -4,6 +4,7 @@
<item <item
android:id="@+id/menu_sanitize" android:id="@+id/menu_sanitize"
android:checkable="true" android:checkable="true"
android:icon="@drawable/twotone_cleaning_services_24"
android:title="@string/title_sanitize" android:title="@string/title_sanitize"
app:showAsAction="never" /> app:showAsAction="always" />
</menu> </menu>

@ -475,7 +475,7 @@
</activity> </activity>
<activity <activity
android:name=".ActivityHTML" android:name=".ActivityCode"
android:description="@string/app_name" android:description="@string/app_name"
android:exported="false" android:exported="false"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"

Loading…
Cancel
Save