Inline full message display

This commit is contained in:
M66B
2019-10-04 15:25:04 +02:00
parent f590613292
commit c4c0d2a80b
14 changed files with 537 additions and 526 deletions

View File

@@ -139,7 +139,7 @@ public class ActivityEML extends ActivityBase {
result.html = parts.getHtml(context);
if (result.html != null) {
result.body = HtmlHelper.fromHtml(HtmlHelper.sanitize(context, result.html, false, false));
result.body = HtmlHelper.fromHtml(HtmlHelper.sanitize(context, result.html, false));
if (result.html.length() > 100 * 1024)
result.html = null;
}

File diff suppressed because it is too large Load Diff

View File

@@ -68,7 +68,7 @@ public class EditTextCompose extends AppCompatEditText {
ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0);
String html = item.coerceToHtmlText(context);
html = HtmlHelper.sanitize(context, html, true, false);
html = HtmlHelper.sanitize(context, html, false);
Spanned paste = HtmlHelper.fromHtml(html);
int start = getSelectionStart();

View File

@@ -2026,7 +2026,6 @@ public class FragmentCompose extends FragmentBase {
long answer = args.getLong("answer", -1);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean text_color = prefs.getBoolean("text_color", true);
boolean plain_only = prefs.getBoolean("plain_only", false);
boolean encrypt_default = prefs.getBoolean("encrypt_default", false);
boolean receipt_default = prefs.getBoolean("receipt_default", false);
@@ -2096,7 +2095,7 @@ public class FragmentCompose extends FragmentBase {
data.draft.subject = args.getString("subject", "");
body = args.getString("body", "");
if (!TextUtils.isEmpty(body))
body = HtmlHelper.sanitize(context, body, text_color, false);
body = HtmlHelper.sanitize(context, body, false);
if (answer > 0) {
EntityAnswer a = db.answer().getAnswer(answer);
@@ -2164,7 +2163,7 @@ public class FragmentCompose extends FragmentBase {
data.draft.subject = ref.subject;
if (ref.content) {
String html = Helper.readText(ref.getFile(context));
body = HtmlHelper.sanitize(context, html, text_color, true);
body = HtmlHelper.sanitize(context, html, true);
}
} else if ("list".equals(action)) {
data.draft.subject = ref.subject;
@@ -2411,7 +2410,7 @@ public class FragmentCompose extends FragmentBase {
if (data.draft.content) {
File file = data.draft.getFile(context);
String html = Helper.readText(file);
html = HtmlHelper.sanitize(context, html, true, true);
html = HtmlHelper.sanitize(context, html, true);
Helper.writeText(file, html);
} else {
if (data.draft.uid == null)
@@ -3114,9 +3113,6 @@ public class FragmentCompose extends FragmentBase {
final long id = args.getLong("id");
final boolean show_images = args.getBoolean("show_images", false);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean text_color = prefs.getBoolean("text_color", true);
int colorPrimary = Helper.resolveColor(context, R.attr.colorPrimary);
DB db = DB.getInstance(context);
@@ -3143,7 +3139,7 @@ public class FragmentCompose extends FragmentBase {
Spanned spannedRef = null;
File refFile = draft.getRefFile(context);
if (refFile.exists()) {
String quote = HtmlHelper.sanitize(context, Helper.readText(refFile), text_color, show_images);
String quote = HtmlHelper.sanitize(context, Helper.readText(refFile), show_images);
Spanned spannedQuote = HtmlHelper.fromHtml(quote,
new Html.ImageGetter() {
@Override

View File

@@ -48,7 +48,6 @@ import android.os.Parcelable;
import android.print.PrintAttributes;
import android.print.PrintDocumentAdapter;
import android.print.PrintManager;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.LongSparseArray;
@@ -232,7 +231,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
private boolean autoExpanded = true;
private Map<String, List<Long>> values = new HashMap<>();
private LongSparseArray<Float> sizes = new LongSparseArray<>();
private LongSparseArray<Spanned> bodies = new LongSparseArray<>();
private LongSparseArray<Integer> heights = new LongSparseArray<>();
private LongSparseArray<List<EntityAttachment>> attachments = new LongSparseArray<>();
private LongSparseArray<TupleAccountSwipes> accountSwipes = new LongSparseArray<>();
@@ -258,8 +257,7 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
static final int REQUEST_PRINT = 17;
private static final int REQUEST_SEARCH = 18;
private static final int REQUEST_ACCOUNT = 19;
static final int REQUEST_MESSAGE_PROPERTY = 20;
private static final int REQUEST_EMPTY_FOLDER = 21;
private static final int REQUEST_EMPTY_FOLDER = 20;
static final String ACTION_STORE_RAW = BuildConfig.APPLICATION_ID + ".STORE_RAW";
static final String ACTION_DECRYPT = BuildConfig.APPLICATION_ID + ".DECRYPT";
@@ -1253,16 +1251,13 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
}
@Override
public void setBody(long id, Spanned value) {
if (value == null)
bodies.remove(id);
else
bodies.put(id, value);
public void setHeight(long id, int height) {
heights.put(id, height);
}
@Override
public Spanned getBody(long id) {
return bodies.get(id);
public int getHeight(long id, int defaultHeight) {
return heights.get(id, defaultHeight);
}
@Override
@@ -1285,16 +1280,6 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
});
}
@Override
public void scrollBy(final int dx, final int dy) {
new Handler().post(new Runnable() {
@Override
public void run() {
rvMessage.scrollBy(dx, dy);
}
});
}
@Override
public void move(long id, String type) {
Bundle args = new Bundle();
@@ -2187,6 +2172,15 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
outState.putLongArray("fair:sizes:keys", skeys);
outState.putFloatArray("fair:sizes:values", svalues);
long[] hkeys = new long[heights.size()];
int[] hvalues = new int[heights.size()];
for (int i = 0; i < heights.size(); i++) {
hkeys[i] = heights.keyAt(i);
hvalues[i] = heights.valueAt(i);
}
outState.putLongArray("fair:heights:keys", hkeys);
outState.putIntArray("fair:heights:values", hvalues);
if (rvMessage != null) {
Parcelable rv = rvMessage.getLayoutManager().onSaveInstanceState();
outState.putParcelable("fair:rv", rv);
@@ -2221,6 +2215,12 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
for (int i = 0; i < skeys.length; i++)
sizes.put(skeys[i], svalues[i]);
long[] hkeys = savedInstanceState.getLongArray("fair:heights:keys");
int[] hvalues = savedInstanceState.getIntArray("fair:heights:values");
for (int i = 0; i < hkeys.length; i++)
heights.put(hkeys[i], hvalues[i]);
if (rvMessage != null) {
Parcelable rv = savedInstanceState.getBundle("fair:rv");
rvMessage.getLayoutManager().onRestoreInstanceState(rv);
@@ -2338,7 +2338,8 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
Log.i("Hidden id=" + id);
for (String key : values.keySet())
values.get(key).remove(id);
bodies.remove(id);
sizes.remove(id);
heights.remove(id);
attachments.remove(id);
}
updateExpanded();
@@ -3706,10 +3707,6 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
onMenuFolders(args.getLong("account"));
}
break;
case REQUEST_MESSAGE_PROPERTY:
if (resultCode == RESULT_OK)
onPropertySet(data.getBundleExtra("args"));
break;
case REQUEST_EMPTY_FOLDER:
if (resultCode == RESULT_OK)
onEmptyFolder(data.getBundleExtra("args"));
@@ -4440,14 +4437,6 @@ public class FragmentMessages extends FragmentBase implements SharedPreferences.
}.execute(this, pargs, "message:print");
}
private void onPropertySet(Bundle args) {
long id = args.getLong("id");
String name = args.getString("name");
boolean value = args.getBoolean("value");
Log.i("Set property " + name + "=" + value + " id=" + id);
iProperties.setValue(name, id, value);
}
private void onEmptyFolder(Bundle args) {
new SimpleTask<Void>() {
@Override

View File

@@ -46,7 +46,7 @@ public class FragmentOptions extends FragmentBase {
"flags", "flags_background", "preview", "preview_italic",
"addresses", "attachments_alt",
"contrast", "monospaced", "text_color",
"inline_images", "collapse_quotes", "autocontent", "seekbar", "actionbar",
"inline_images", "collapse_quotes", "seekbar", "actionbar",
"autoscroll", "swipenav", "autoexpand", "autoclose", "onclose",
"experiments", "debug",
"biometrics"

View File

@@ -71,7 +71,6 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
private SwitchCompat swTextColor;
private SwitchCompat swCollapseQuotes;
private SwitchCompat swImagesInline;
private SwitchCompat swRemoteContent;
private SwitchCompat swSeekbar;
private SwitchCompat swActionbar;
@@ -81,7 +80,7 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
"subject_top", "subject_italic", "subject_ellipsize",
"flags", "flags_background", "preview", "preview_italic", "addresses", "attachments_alt",
"contrast", "monospaced", "text_color",
"inline_images", "collapse_quotes", "autocontent", "seekbar", "actionbar",
"inline_images", "collapse_quotes", "seekbar", "actionbar",
};
@Override
@@ -121,7 +120,6 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
swTextColor = view.findViewById(R.id.swTextColor);
swCollapseQuotes = view.findViewById(R.id.swCollapseQuotes);
swImagesInline = view.findViewById(R.id.swImagesInline);
swRemoteContent = view.findViewById(R.id.swRemoteContent);
swSeekbar = view.findViewById(R.id.swSeekbar);
swActionbar = view.findViewById(R.id.swActionbar);
@@ -341,13 +339,6 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
}
});
swRemoteContent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("autocontent", checked).apply();
}
});
swSeekbar.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
@@ -451,7 +442,6 @@ public class FragmentOptionsDisplay extends FragmentBase implements SharedPrefer
swTextColor.setChecked(prefs.getBoolean("text_color", true));
swCollapseQuotes.setChecked(prefs.getBoolean("collapse_quotes", false));
swImagesInline.setChecked(prefs.getBoolean("inline_images", false));
swRemoteContent.setChecked(prefs.getBoolean("autocontent", false));
swSeekbar.setChecked(prefs.getBoolean("seekbar", false));
swActionbar.setChecked(prefs.getBoolean("actionbar", true));
}

View File

@@ -255,7 +255,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
for (String option : RESET_QUESTIONS)
editor.remove(option);
for (String key : prefs.getAll().keySet())
if (key.endsWith(".show_images"))
if (key.endsWith(".show_full") || key.endsWith(".show_images"))
editor.remove(key);
editor.apply();
ToastEx.makeText(getContext(), R.string.title_setup_done, Toast.LENGTH_LONG).show();

View File

@@ -96,7 +96,11 @@ public class HtmlHelper {
private static final ExecutorService executor =
Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory);
static String sanitize(Context context, String html, boolean text_color, boolean show_images) {
static String sanitize(Context context, String html, boolean show_images) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean text_color = prefs.getBoolean("text_color", true);
boolean disable_tracking = prefs.getBoolean("disable_tracking", true);
Document parsed = JsoupEx.parse(html);
// <html xmlns:v="urn:schemas-microsoft-com:vml"
@@ -349,40 +353,12 @@ public class HtmlHelper {
else
table.tagName("div");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean disable_tracking = prefs.getBoolean("disable_tracking", true);
// Build list of allowed hosts
List<String> hosts = new ArrayList<>();
// Remove tracking pixels
if (disable_tracking)
for (Element img : document.select("img")) {
String src = img.attr("src");
if (!TextUtils.isEmpty(src) && !isTrackingPixel(img)) {
Uri uri = Uri.parse(img.attr("src"));
String host = uri.getHost();
if (host != null && !hosts.contains(host))
hosts.add(host);
}
}
removeTrackingPixels(context, document);
// Images
for (Element img : document.select("img")) {
// Remove link tracking pixels
if (disable_tracking) {
String src = img.attr("src");
if (!TextUtils.isEmpty(src) && isTrackingPixel(img)) {
Uri uri = Uri.parse(img.attr("src"));
String host = uri.getHost();
if (host == null || !hosts.contains(host)) {
img.removeAttr("src");
img.tagName("a");
img.attr("href", src);
img.appendText(context.getString(R.string.title_hint_tracking_image,
img.attr("width"), img.attr("height")));
}
}
}
if (!show_images) {
String alt = img.attr("alt");
if (!TextUtils.isEmpty(alt)) {
@@ -515,6 +491,36 @@ public class HtmlHelper {
return false;
}
static void removeTrackingPixels(Context context, Document document) {
// Build list of allowed hosts
List<String> hosts = new ArrayList<>();
for (Element img : document.select("img")) {
String src = img.attr("src");
if (!TextUtils.isEmpty(src) && !isTrackingPixel(img)) {
Uri uri = Uri.parse(img.attr("src"));
String host = uri.getHost();
if (host != null && !hosts.contains(host))
hosts.add(host);
}
}
// Images
for (Element img : document.select("img")) {
String src = img.attr("src");
if (!TextUtils.isEmpty(src) && isTrackingPixel(img)) {
Uri uri = Uri.parse(img.attr("src"));
String host = uri.getHost();
if (host == null || !hosts.contains(host)) {
img.removeAttr("src");
img.tagName("a");
img.attr("href", src);
img.appendText(context.getString(R.string.title_hint_tracking_image,
img.attr("width"), img.attr("height")));
}
}
}
}
static Drawable decodeImage(final Context context, final long id, String source, boolean show, final TextView view) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean compact = prefs.getBoolean("compact", false);