Added definable placeholders

pull/209/head
M66B 3 years ago
parent 4b353d9c07
commit 93a512c0f7

@ -83,7 +83,7 @@ public class ActivityAnswer extends ActivityBase {
} }
}); });
String html = answer.getHtml(null); String html = answer.getHtml(context, null);
String text = HtmlHelper.getText(context, html); String text = HtmlHelper.getText(context, html);
ClipboardManager cbm = Helper.getSystemService(ActivityAnswer.this, ClipboardManager.class); ClipboardManager cbm = Helper.getSystemService(ActivityAnswer.this, ClipboardManager.class);

@ -242,7 +242,7 @@ public class EditTextCompose extends FixedEditText {
for (EntityAnswer snippet : snippets) for (EntityAnswer snippet : snippets)
if (snippet.id.equals(id)) { if (snippet.id.equals(id)) {
String html = snippet.getHtml(to); String html = snippet.getHtml(context, to);
executor.submit(new Runnable() { executor.submit(new Runnable() {
@Override @Override

@ -99,11 +99,13 @@ public class EntityAnswer implements Serializable {
public Integer applied = 0; public Integer applied = 0;
public Long last_applied; public Long last_applied;
String getHtml(Address[] address) { static final String PREF_PLACEHOLDER = "answer.value.";
return replacePlaceholders(text, address);
String getHtml(Context context, Address[] address) {
return replacePlaceholders(context, text, address);
} }
static String replacePlaceholders(String text, Address[] address) { static String replacePlaceholders(Context context, String text, Address[] address) {
String fullName = null; String fullName = null;
String email = null; String email = null;
if (address != null && address.length > 0) { if (address != null && address.length > 0) {
@ -173,6 +175,19 @@ public class EntityAnswer implements Serializable {
text = text.replace("$lastname$", last == null ? "" : Html.escapeHtml(last)); text = text.replace("$lastname$", last == null ? "" : Html.escapeHtml(last));
text = text.replace("$email$", email == null ? "" : Html.escapeHtml(email)); text = text.replace("$email$", email == null ? "" : Html.escapeHtml(email));
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
for (String key : prefs.getAll().keySet())
if (key.startsWith(PREF_PLACEHOLDER)) {
String name = key.substring(PREF_PLACEHOLDER.length());
String value = prefs.getString(key, null);
String[] lines = (value == null ? new String[0] : value.split("\n"));
for (int i = 0; i < lines.length; i++)
lines[i] = Html.escapeHtml(lines[i]);
text = text.replace("$" + name + "$", TextUtils.join("<br>", lines));
}
return text; return text;
} }

@ -805,7 +805,7 @@ public class EntityRule {
if (resend) if (resend)
body = Helper.readText(message.getFile(context)); body = Helper.readText(message.getFile(context));
else { else {
body = answer.getHtml(message.from); body = answer.getHtml(context, message.from);
if (original_text) { if (original_text) {
Document msg = JsoupEx.parse(body); Document msg = JsoupEx.parse(body);

@ -56,6 +56,13 @@ import com.google.android.material.snackbar.Snackbar;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
public class FragmentAnswer extends FragmentBase { public class FragmentAnswer extends FragmentBase {
private ViewGroup view; private ViewGroup view;
private EditText etName; private EditText etName;
@ -279,6 +286,26 @@ public class FragmentAnswer extends FragmentBase {
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_answer, menu); inflater.inflate(R.menu.menu_answer, menu);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
List<String> names = new ArrayList<>();
for (String key : prefs.getAll().keySet())
if (key.startsWith(EntityAnswer.PREF_PLACEHOLDER))
names.add(key.substring(EntityAnswer.PREF_PLACEHOLDER.length()));
final Collator collator = Collator.getInstance(Locale.getDefault());
collator.setStrength(Collator.SECONDARY); // Case insensitive, process accents etc
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String n1, String n2) {
return collator.compare(n1, n2);
}
});
Menu smenu = menu.findItem(R.id.menu_placeholders).getSubMenu();
for (int i = 0; i < names.size(); i++)
smenu.add(Menu.FIRST, i + 1, i + 1, names.get(i));
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
} }
@ -291,22 +318,28 @@ public class FragmentAnswer extends FragmentBase {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId(); if (item.getGroupId() == Menu.FIRST) {
if (itemId == R.id.menu_help) { String name = item.getTitle().toString();
onMenuHelp(); onMenuPlaceholder("$" + name + "$");
return true;
} else if (itemId == R.id.menu_placeholder_name) {
onMenuPlaceholder("$name$");
return true;
} else if (itemId == R.id.menu_placeholder_email) {
onMenuPlaceholder("$email$");
return true;
} else if (itemId == R.id.menu_placeholder_firstname) {
onMenuPlaceholder("$firstname$");
return true;
} else if (itemId == R.id.menu_placeholder_lastname) {
onMenuPlaceholder("$lastname$");
return true; return true;
} else {
int itemId = item.getItemId();
if (itemId == R.id.menu_help) {
onMenuHelp();
return true;
} else if (itemId == R.id.menu_placeholder_name) {
onMenuPlaceholder("$name$");
return true;
} else if (itemId == R.id.menu_placeholder_email) {
onMenuPlaceholder("$email$");
return true;
} else if (itemId == R.id.menu_placeholder_firstname) {
onMenuPlaceholder("$firstname$");
return true;
} else if (itemId == R.id.menu_placeholder_lastname) {
onMenuPlaceholder("$lastname$");
return true;
}
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }

@ -21,21 +21,27 @@ package eu.faircode.email;
import static androidx.recyclerview.widget.RecyclerView.NO_POSITION; import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Bundle; import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.TextWatcher;
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.view.ViewGroup; import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.SearchView;
import androidx.constraintlayout.widget.Group; import androidx.constraintlayout.widget.Group;
import androidx.fragment.app.FragmentTransaction; import androidx.fragment.app.FragmentTransaction;
@ -275,4 +281,60 @@ public class FragmentAnswers extends FragmentBase {
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
} }
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
int id = item.getItemId();
if (id == R.id.menu_define) {
onDefine();
return true;
} else
return super.onOptionsItemSelected(item);
}
private void onDefine() {
final Context context = getContext();
View view = LayoutInflater.from(context).inflate(R.layout.dialog_placeholder, null);
final EditText etName = view.findViewById(R.id.etName);
final EditText etValue = view.findViewById(R.id.etValue);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
etName.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// Do nothing
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Do nothing
}
@Override
public void afterTextChanged(Editable s) {
String value = prefs.getString(EntityAnswer.PREF_PLACEHOLDER + s.toString().trim(), null);
if (!TextUtils.isEmpty(value))
etValue.setText(value);
}
});
new AlertDialog.Builder(context)
.setView(view)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String name = etName.getText().toString().trim();
String value = etValue.getText().toString();
if (TextUtils.isEmpty(name))
return;
if (TextUtils.isEmpty(value))
prefs.edit().remove(EntityAnswer.PREF_PLACEHOLDER + name).apply();
else
prefs.edit().putString(EntityAnswer.PREF_PLACEHOLDER + name, value).apply();
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
}
} }

@ -2230,7 +2230,7 @@ public class FragmentCompose extends FragmentBase {
} catch (AddressException ignored) { } catch (AddressException ignored) {
} }
String html = EntityAnswer.replacePlaceholders(answer.text, to); String html = EntityAnswer.replacePlaceholders(context, answer.text, to);
Spanned spanned = HtmlHelper.fromHtml(html, new HtmlHelper.ImageGetterEx() { Spanned spanned = HtmlHelper.fromHtml(html, new HtmlHelper.ImageGetterEx() {
@Override @Override
@ -4821,7 +4821,7 @@ public class FragmentCompose extends FragmentBase {
if (answer > 0) if (answer > 0)
data.draft.subject = a.name; data.draft.subject = a.name;
if (TextUtils.isEmpty(external_body)) { if (TextUtils.isEmpty(external_body)) {
Document d = JsoupEx.parse(a.getHtml(null)); Document d = JsoupEx.parse(a.getHtml(context, null));
document.body().append(d.body().html()); document.body().append(d.body().html());
} }
} }
@ -5004,7 +5004,7 @@ public class FragmentCompose extends FragmentBase {
else { else {
db.answer().applyAnswer(receipt.id, new Date().getTime()); db.answer().applyAnswer(receipt.id, new Date().getTime());
texts = new String[0]; texts = new String[0];
Document d = JsoupEx.parse(receipt.getHtml(null)); Document d = JsoupEx.parse(receipt.getHtml(context, null));
document.body().append(d.body().html()); document.body().append(d.body().html());
} }
} }
@ -5066,7 +5066,7 @@ public class FragmentCompose extends FragmentBase {
if (a != null) { if (a != null) {
db.answer().applyAnswer(a.id, new Date().getTime()); db.answer().applyAnswer(a.id, new Date().getTime());
Document d = JsoupEx.parse(a.getHtml(data.draft.to)); Document d = JsoupEx.parse(a.getHtml(context, data.draft.to));
document.body().append(d.body().html()); document.body().append(d.body().html());
} }

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp">
<TextView
android:id="@+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:labelFor="@+id/etName"
android:text="@string/title_answer_define"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvBefore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="9dp"
android:paddingEnd="6dp"
android:text="$"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintBottom_toBottomOf="@id/etName"
app:layout_constraintStart_toStartOf="parent" />
<EditText
android:id="@+id/etName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:hint="@string/title_answer_define_name"
android:imeOptions="actionDone"
android:inputType="text"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toStartOf="@+id/tvAfter"
app:layout_constraintStart_toEndOf="@+id/tvBefore"
app:layout_constraintTop_toBottomOf="@id/tvName">
<requestFocus />
</EditText>
<TextView
android:id="@+id/tvAfter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="9dp"
android:paddingStart="6dp"
android:text="$"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintBottom_toBottomOf="@id/etName"
app:layout_constraintEnd_toEndOf="parent" />
<EditText
android:id="@+id/etValue"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:hint="@string/title_answer_define_value"
android:imeOptions="actionDone"
android:inputType="textMultiLine|textCapSentences|textAutoCorrect"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/etName" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -6,7 +6,9 @@
android:icon="@drawable/twotone_help_24" android:icon="@drawable/twotone_help_24"
android:title="" android:title=""
app:showAsAction="always" /> app:showAsAction="always" />
<item android:title="@string/title_answer_placeholder"> <item
android:id="@+id/menu_placeholders"
android:title="@string/title_answer_placeholder">
<menu> <menu>
<item <item
android:id="@+id/menu_placeholder_name" android:id="@+id/menu_placeholder_name"

@ -7,4 +7,9 @@
android:title="@string/title_search" android:title="@string/title_search"
app:actionViewClass="androidx.appcompat.widget.SearchView" app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="collapseActionView|always" /> app:showAsAction="collapseActionView|always" />
<item
android:id="@+id/menu_define"
android:icon="@drawable/twotone_add_24"
android:title="@string/title_answer_define" />
</menu> </menu>

@ -1652,6 +1652,9 @@
So, don\'t delete the image file! So, don\'t delete the image file!
</string> </string>
<string name="title_answer_define">Define placeholder</string>
<string name="title_answer_define_name">Name</string>
<string name="title_answer_define_value">Value</string>
<string name="title_answer_caption">Edit template</string> <string name="title_answer_caption">Edit template</string>
<string name="title_answer_reply">Reply template</string> <string name="title_answer_reply">Reply template</string>
<string name="title_answer_name">Template name</string> <string name="title_answer_name">Template name</string>

Loading…
Cancel
Save