diff --git a/app/src/main/java/eu/faircode/email/FragmentAnswer.java b/app/src/main/java/eu/faircode/email/FragmentAnswer.java index 053b49c256..d947ecfef3 100644 --- a/app/src/main/java/eu/faircode/email/FragmentAnswer.java +++ b/app/src/main/java/eu/faircode/email/FragmentAnswer.java @@ -23,10 +23,14 @@ import android.app.Dialog; import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; +import android.text.Html; +import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextUtils; +import android.text.style.ImageSpan; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -61,8 +65,9 @@ public class FragmentAnswer extends FragmentBase { private long id = -1; private long copy = -1; - private static final int REQUEST_LINK = 1; - private final static int REQUEST_DELETE = 2; + private static final int REQUEST_IMAGE = 1; + private static final int REQUEST_LINK = 2; + private final static int REQUEST_DELETE = 3; @Override public void onCreate(Bundle savedInstanceState) { @@ -115,6 +120,9 @@ public class FragmentAnswer extends FragmentBase { @Override public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { switch (menuItem.getItemId()) { + case R.id.action_insert_image: + onInsertImage(); + return true; case R.id.action_delete: onActionDelete(); return true; @@ -154,7 +162,15 @@ public class FragmentAnswer extends FragmentBase { etName.setText(answer == null ? null : answer.name); cbFavorite.setChecked(answer == null ? false : answer.favorite); cbHide.setChecked(answer == null ? false : answer.hide); - etText.setText(answer == null ? null : HtmlHelper.fromHtml(answer.text)); + if (answer == null) + etText.setText(null); + else + etText.setText(HtmlHelper.fromHtml(answer.text, new Html.ImageGetter() { + @Override + public Drawable getDrawable(String source) { + return ImageHelper.decodeImage(getContext(), -1, source, true, 0, etText); + } + }, null)); bottom_navigation.findViewById(R.id.action_delete).setVisibility(answer == null ? View.GONE : View.VISIBLE); pbWait.setVisibility(View.GONE); @@ -189,6 +205,16 @@ public class FragmentAnswer extends FragmentBase { new FragmentInfo().show(getParentFragmentManager(), "answer:info"); } + private void onInsertImage() { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setType("image/*"); + Helper.openAdvanced(intent); + startActivityForResult(intent, REQUEST_IMAGE); + } + private void onActionDelete() { Bundle args = new Bundle(); args.putString("question", getString(R.string.title_ask_delete_answer)); @@ -272,6 +298,10 @@ public class FragmentAnswer extends FragmentBase { try { switch (requestCode) { + case REQUEST_IMAGE: + if (resultCode == RESULT_OK && data != null) + onImageSelected(data.getData()); + break; case REQUEST_LINK: if (resultCode == RESULT_OK && data != null) onLinkSelected(data.getBundleExtra("args")); @@ -286,6 +316,24 @@ public class FragmentAnswer extends FragmentBase { } } + private void onImageSelected(Uri uri) { + try { + getContext().getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + + int start = etText.getSelectionStart(); + SpannableStringBuilder ssb = new SpannableStringBuilder(etText.getText()); + ssb.insert(start, "\uFFFC"); // Object replacement character + String source = uri.toString(); + Drawable d = ImageHelper.decodeImage(getContext(), -1, source, true, 0, etText); + ImageSpan is = new ImageSpan(d, source); + ssb.setSpan(is, start, start + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + etText.setText(ssb); + etText.setSelection(start + 1); + } catch (Throwable ex) { + Log.unexpectedError(getParentFragmentManager(), ex); + } + } + private void onLinkSelected(Bundle args) { String link = args.getString("link"); StyleHelper.apply(R.id.menu_link, etText, link); diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index 29117a37fc..727beada6f 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -2634,7 +2634,12 @@ public class FragmentCompose extends FragmentBase { String text = EntityAnswer.replacePlaceholders(answer, to); - Spanned spanned = HtmlHelper.fromHtml(text); + Spanned spanned = HtmlHelper.fromHtml(text, new Html.ImageGetter() { + @Override + public Drawable getDrawable(String source) { + return ImageHelper.decodeImage(getContext(), -1, source, true, 0, etBody); + } + }, null); etBody.getText().insert(etBody.getSelectionStart(), spanned); } diff --git a/app/src/main/java/eu/faircode/email/HtmlHelper.java b/app/src/main/java/eu/faircode/email/HtmlHelper.java index 3d6a54c0d1..0b8611e957 100644 --- a/app/src/main/java/eu/faircode/email/HtmlHelper.java +++ b/app/src/main/java/eu/faircode/email/HtmlHelper.java @@ -448,8 +448,9 @@ public class HtmlHelper { .addProtocols("img", "src", "data") .addProtocols("a", "href", "full"); if (text_color) - whitelist - .addAttributes("font", "color"); + whitelist.addAttributes("font", "color"); + if (!view) + whitelist.addProtocols("img", "src", "content"); final Document document = new Cleaner(whitelist).clean(parsed); diff --git a/app/src/main/res/menu/action_answer.xml b/app/src/main/res/menu/action_answer.xml index f3bbeedb85..68ce9ec8b8 100644 --- a/app/src/main/res/menu/action_answer.xml +++ b/app/src/main/res/menu/action_answer.xml @@ -1,5 +1,10 @@