mirror of
https://github.com/M66B/FairEmail.git
synced 2025-02-22 14:11:00 +00:00
Use FAB for compose/translate
This commit is contained in:
parent
eca6a97f3e
commit
21923526bc
2 changed files with 135 additions and 127 deletions
|
@ -121,6 +121,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||||
import com.google.android.material.bottomnavigation.LabelVisibilityMode;
|
import com.google.android.material.bottomnavigation.LabelVisibilityMode;
|
||||||
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
|
||||||
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
import org.bouncycastle.cert.jcajce.JcaCertStore;
|
||||||
|
@ -241,7 +242,6 @@ public class FragmentCompose extends FragmentBase {
|
||||||
private TextView tvDsn;
|
private TextView tvDsn;
|
||||||
private TextView tvPlainTextOnly;
|
private TextView tvPlainTextOnly;
|
||||||
private EditTextCompose etBody;
|
private EditTextCompose etBody;
|
||||||
private ImageButton ibTranslate;
|
|
||||||
private TextView tvNoInternet;
|
private TextView tvNoInternet;
|
||||||
private TextView tvSignature;
|
private TextView tvSignature;
|
||||||
private CheckBox cbSignature;
|
private CheckBox cbSignature;
|
||||||
|
@ -250,6 +250,7 @@ public class FragmentCompose extends FragmentBase {
|
||||||
private ImageButton ibCloseRefHint;
|
private ImageButton ibCloseRefHint;
|
||||||
private ImageButton ibReferenceEdit;
|
private ImageButton ibReferenceEdit;
|
||||||
private ImageButton ibReferenceImages;
|
private ImageButton ibReferenceImages;
|
||||||
|
private FloatingActionButton fabTranslate;
|
||||||
private BottomNavigationView style_bar;
|
private BottomNavigationView style_bar;
|
||||||
private BottomNavigationView media_bar;
|
private BottomNavigationView media_bar;
|
||||||
private BottomNavigationView bottom_navigation;
|
private BottomNavigationView bottom_navigation;
|
||||||
|
@ -358,7 +359,6 @@ public class FragmentCompose extends FragmentBase {
|
||||||
tvDsn = view.findViewById(R.id.tvDsn);
|
tvDsn = view.findViewById(R.id.tvDsn);
|
||||||
tvPlainTextOnly = view.findViewById(R.id.tvPlainTextOnly);
|
tvPlainTextOnly = view.findViewById(R.id.tvPlainTextOnly);
|
||||||
etBody = view.findViewById(R.id.etBody);
|
etBody = view.findViewById(R.id.etBody);
|
||||||
ibTranslate = view.findViewById(R.id.ibTranslate);
|
|
||||||
tvNoInternet = view.findViewById(R.id.tvNoInternet);
|
tvNoInternet = view.findViewById(R.id.tvNoInternet);
|
||||||
tvSignature = view.findViewById(R.id.tvSignature);
|
tvSignature = view.findViewById(R.id.tvSignature);
|
||||||
cbSignature = view.findViewById(R.id.cbSignature);
|
cbSignature = view.findViewById(R.id.cbSignature);
|
||||||
|
@ -367,6 +367,7 @@ public class FragmentCompose extends FragmentBase {
|
||||||
ibCloseRefHint = view.findViewById(R.id.ibCloseRefHint);
|
ibCloseRefHint = view.findViewById(R.id.ibCloseRefHint);
|
||||||
ibReferenceEdit = view.findViewById(R.id.ibReferenceEdit);
|
ibReferenceEdit = view.findViewById(R.id.ibReferenceEdit);
|
||||||
ibReferenceImages = view.findViewById(R.id.ibReferenceImages);
|
ibReferenceImages = view.findViewById(R.id.ibReferenceImages);
|
||||||
|
fabTranslate = view.findViewById(R.id.fabTranslate);
|
||||||
style_bar = view.findViewById(R.id.style_bar);
|
style_bar = view.findViewById(R.id.style_bar);
|
||||||
media_bar = view.findViewById(R.id.media_bar);
|
media_bar = view.findViewById(R.id.media_bar);
|
||||||
bottom_navigation = view.findViewById(R.id.bottom_navigation);
|
bottom_navigation = view.findViewById(R.id.bottom_navigation);
|
||||||
|
@ -716,116 +717,6 @@ public class FragmentCompose extends FragmentBase {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ibTranslate.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
List<DeepL.Language> languages = DeepL.getTargetLanguages(getContext());
|
|
||||||
if (languages == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
boolean canTranslate =
|
|
||||||
(DeepL.canTranslate(getContext()) &&
|
|
||||||
DeepL.getParagraph(etBody) != null);
|
|
||||||
|
|
||||||
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(getContext(), getViewLifecycleOwner(), v);
|
|
||||||
|
|
||||||
popupMenu.getMenu().add(Menu.NONE, 1, 1, R.string.title_translate_configure);
|
|
||||||
|
|
||||||
for (int i = 0; i < languages.size(); i++) {
|
|
||||||
DeepL.Language lang = languages.get(i);
|
|
||||||
MenuItem item = popupMenu.getMenu().add(Menu.NONE, i + 2, i + 2, lang.name)
|
|
||||||
.setIntent(new Intent().putExtra("target", lang.target));
|
|
||||||
if (lang.icon != null)
|
|
||||||
item.setIcon(lang.icon);
|
|
||||||
item.setEnabled(canTranslate);
|
|
||||||
}
|
|
||||||
|
|
||||||
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onMenuItemClick(MenuItem item) {
|
|
||||||
if (item.getItemId() == 1) {
|
|
||||||
DeepL.FragmentDialogDeepL fragment = new DeepL.FragmentDialogDeepL();
|
|
||||||
fragment.show(getParentFragmentManager(), "deepl:configure");
|
|
||||||
} else {
|
|
||||||
String target = item.getIntent().getStringExtra("target");
|
|
||||||
onMenuTranslate(target);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
popupMenu.showWithIcons(getContext(), v);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onMenuTranslate(String target) {
|
|
||||||
final Pair<Integer, Integer> paragraph = DeepL.getParagraph(etBody);
|
|
||||||
if (paragraph == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Editable edit = etBody.getText();
|
|
||||||
String text = edit.subSequence(paragraph.first, paragraph.second).toString();
|
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putString("target", target);
|
|
||||||
args.putString("text", text);
|
|
||||||
|
|
||||||
new SimpleTask<DeepL.Translation>() {
|
|
||||||
@Override
|
|
||||||
protected void onPreExecute(Bundle args) {
|
|
||||||
ToastEx.makeText(getContext(), R.string.title_translating, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected DeepL.Translation onExecute(Context context, Bundle args) throws Throwable {
|
|
||||||
String target = args.getString("target");
|
|
||||||
String text = args.getString("text");
|
|
||||||
return DeepL.translate(text, target, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onExecuted(Bundle args, DeepL.Translation translation) {
|
|
||||||
if (paragraph.second > edit.length())
|
|
||||||
return;
|
|
||||||
|
|
||||||
FragmentActivity activity = getActivity();
|
|
||||||
if (activity == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Context context = getContext();
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
||||||
|
|
||||||
// Insert translated text
|
|
||||||
edit.insert(paragraph.second, "\n\n" + translation.translated_text);
|
|
||||||
etBody.setSelection(paragraph.second + 2 + translation.translated_text.length());
|
|
||||||
|
|
||||||
boolean small = prefs.getBoolean("deepl_small", false);
|
|
||||||
if (small) {
|
|
||||||
RelativeSizeSpan[] spans = edit.getSpans(
|
|
||||||
paragraph.first, paragraph.second, RelativeSizeSpan.class);
|
|
||||||
for (RelativeSizeSpan span : spans)
|
|
||||||
edit.removeSpan(span);
|
|
||||||
edit.setSpan(new RelativeSizeSpan(HtmlHelper.FONT_SMALL),
|
|
||||||
paragraph.first, paragraph.second,
|
|
||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updated frequency
|
|
||||||
String key = "translated_" + args.getString("target");
|
|
||||||
int count = prefs.getInt(key, 0);
|
|
||||||
prefs.edit().putInt(key, count + 1).apply();
|
|
||||||
|
|
||||||
activity.invalidateOptionsMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onException(Bundle args, Throwable ex) {
|
|
||||||
Throwable exex = new Throwable("DeepL", ex);
|
|
||||||
Log.unexpectedError(getParentFragmentManager(), exex, false);
|
|
||||||
}
|
|
||||||
}.execute(FragmentCompose.this, args, "compose:translate");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
tvSignature.setTypeface(monospaced ? Typeface.MONOSPACE : Typeface.DEFAULT);
|
tvSignature.setTypeface(monospaced ? Typeface.MONOSPACE : Typeface.DEFAULT);
|
||||||
|
|
||||||
cbSignature.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
cbSignature.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||||
|
@ -924,6 +815,13 @@ public class FragmentCompose extends FragmentBase {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fabTranslate.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
onTranslate(v);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
style_bar.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
|
style_bar.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
|
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
|
||||||
|
@ -1006,13 +904,13 @@ public class FragmentCompose extends FragmentBase {
|
||||||
grpAttachments.setVisibility(View.GONE);
|
grpAttachments.setVisibility(View.GONE);
|
||||||
tvNoInternet.setVisibility(View.GONE);
|
tvNoInternet.setVisibility(View.GONE);
|
||||||
grpBody.setVisibility(View.GONE);
|
grpBody.setVisibility(View.GONE);
|
||||||
ibTranslate.setVisibility(
|
|
||||||
DeepL.isAvailable(getContext()) ? View.VISIBLE : View.GONE);
|
|
||||||
grpSignature.setVisibility(View.GONE);
|
grpSignature.setVisibility(View.GONE);
|
||||||
grpReferenceHint.setVisibility(View.GONE);
|
grpReferenceHint.setVisibility(View.GONE);
|
||||||
ibReferenceEdit.setVisibility(View.GONE);
|
ibReferenceEdit.setVisibility(View.GONE);
|
||||||
ibReferenceImages.setVisibility(View.GONE);
|
ibReferenceImages.setVisibility(View.GONE);
|
||||||
tvReference.setVisibility(View.GONE);
|
tvReference.setVisibility(View.GONE);
|
||||||
|
fabTranslate.setVisibility(
|
||||||
|
DeepL.isAvailable(getContext()) ? View.VISIBLE : View.GONE);
|
||||||
style_bar.setVisibility(View.GONE);
|
style_bar.setVisibility(View.GONE);
|
||||||
media_bar.setVisibility(View.GONE);
|
media_bar.setVisibility(View.GONE);
|
||||||
bottom_navigation.setVisibility(View.GONE);
|
bottom_navigation.setVisibility(View.GONE);
|
||||||
|
@ -2065,6 +1963,113 @@ public class FragmentCompose extends FragmentBase {
|
||||||
fragmentTransaction.commit();
|
fragmentTransaction.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onTranslate(View anchor) {
|
||||||
|
final Context context = anchor.getContext();
|
||||||
|
|
||||||
|
List<DeepL.Language> languages = DeepL.getTargetLanguages(context);
|
||||||
|
if (languages == null)
|
||||||
|
languages = new ArrayList<>();
|
||||||
|
|
||||||
|
Pair<Integer, Integer> paragraph = DeepL.getParagraph(etBody);
|
||||||
|
boolean canTranslate = (DeepL.canTranslate(context) && paragraph != null);
|
||||||
|
|
||||||
|
PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, getViewLifecycleOwner(), anchor);
|
||||||
|
|
||||||
|
popupMenu.getMenu().add(Menu.NONE, 1, 1, R.string.title_translate_configure);
|
||||||
|
|
||||||
|
for (int i = 0; i < languages.size(); i++) {
|
||||||
|
DeepL.Language lang = languages.get(i);
|
||||||
|
MenuItem item = popupMenu.getMenu().add(Menu.NONE, i + 2, i + 2, lang.name)
|
||||||
|
.setIntent(new Intent().putExtra("target", lang.target));
|
||||||
|
if (lang.icon != null)
|
||||||
|
item.setIcon(lang.icon);
|
||||||
|
item.setEnabled(canTranslate);
|
||||||
|
}
|
||||||
|
|
||||||
|
popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onMenuItemClick(MenuItem item) {
|
||||||
|
if (item.getItemId() == 1) {
|
||||||
|
DeepL.FragmentDialogDeepL fragment = new DeepL.FragmentDialogDeepL();
|
||||||
|
fragment.show(getParentFragmentManager(), "deepl:configure");
|
||||||
|
} else {
|
||||||
|
String target = item.getIntent().getStringExtra("target");
|
||||||
|
onMenuTranslate(target);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onMenuTranslate(String target) {
|
||||||
|
final Pair<Integer, Integer> paragraph = DeepL.getParagraph(etBody);
|
||||||
|
if (paragraph == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Editable edit = etBody.getText();
|
||||||
|
String text = edit.subSequence(paragraph.first, paragraph.second).toString();
|
||||||
|
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString("target", target);
|
||||||
|
args.putString("text", text);
|
||||||
|
|
||||||
|
new SimpleTask<DeepL.Translation>() {
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute(Bundle args) {
|
||||||
|
ToastEx.makeText(context, R.string.title_translating, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DeepL.Translation onExecute(Context context, Bundle args) throws Throwable {
|
||||||
|
String target = args.getString("target");
|
||||||
|
String text = args.getString("text");
|
||||||
|
return DeepL.translate(text, target, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onExecuted(Bundle args, DeepL.Translation translation) {
|
||||||
|
if (paragraph.second > edit.length())
|
||||||
|
return;
|
||||||
|
|
||||||
|
FragmentActivity activity = getActivity();
|
||||||
|
if (activity == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
|
// Insert translated text
|
||||||
|
edit.insert(paragraph.second, "\n\n" + translation.translated_text);
|
||||||
|
etBody.setSelection(paragraph.second + 2 + translation.translated_text.length());
|
||||||
|
|
||||||
|
boolean small = prefs.getBoolean("deepl_small", false);
|
||||||
|
if (small) {
|
||||||
|
RelativeSizeSpan[] spans = edit.getSpans(
|
||||||
|
paragraph.first, paragraph.second, RelativeSizeSpan.class);
|
||||||
|
for (RelativeSizeSpan span : spans)
|
||||||
|
edit.removeSpan(span);
|
||||||
|
edit.setSpan(new RelativeSizeSpan(HtmlHelper.FONT_SMALL),
|
||||||
|
paragraph.first, paragraph.second,
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updated frequency
|
||||||
|
String key = "translated_" + args.getString("target");
|
||||||
|
int count = prefs.getInt(key, 0);
|
||||||
|
prefs.edit().putInt(key, count + 1).apply();
|
||||||
|
|
||||||
|
activity.invalidateOptionsMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onException(Bundle args, Throwable ex) {
|
||||||
|
Throwable exex = new Throwable("DeepL", ex);
|
||||||
|
Log.unexpectedError(getParentFragmentManager(), exex, false);
|
||||||
|
}
|
||||||
|
}.execute(FragmentCompose.this, args, "compose:translate");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
popupMenu.showWithIcons(context, anchor);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean onActionStyle(int action, View anchor) {
|
private boolean onActionStyle(int action, View anchor) {
|
||||||
Log.i("Style action=" + action);
|
Log.i("Style action=" + action);
|
||||||
return StyleHelper.apply(action, getViewLifecycleOwner(), anchor, etBody);
|
return StyleHelper.apply(action, getViewLifecycleOwner(), anchor, etBody);
|
||||||
|
|
|
@ -307,18 +307,6 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/tvPlainTextOnly" />
|
app:layout_constraintTop_toBottomOf="@id/tvPlainTextOnly" />
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/ibTranslate"
|
|
||||||
android:layout_width="36dp"
|
|
||||||
android:layout_height="36dp"
|
|
||||||
android:layout_marginEnd="6dp"
|
|
||||||
android:background="?attr/selectableItemBackground"
|
|
||||||
android:padding="3dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/etBody"
|
|
||||||
app:srcCompat="@drawable/outline_translate_24"
|
|
||||||
app:tint="?attr/colorSeparator" />
|
|
||||||
|
|
||||||
<eu.faircode.email.FixedTextView
|
<eu.faircode.email.FixedTextView
|
||||||
android:id="@+id/tvNoInternet"
|
android:id="@+id/tvNoInternet"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -340,7 +328,7 @@
|
||||||
android:background="?attr/colorSeparator"
|
android:background="?attr/colorSeparator"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/ibTranslate" />
|
app:layout_constraintTop_toBottomOf="@+id/etBody" />
|
||||||
|
|
||||||
<eu.faircode.email.FixedTextView
|
<eu.faircode.email.FixedTextView
|
||||||
android:id="@+id/tvSignature"
|
android:id="@+id/tvSignature"
|
||||||
|
@ -512,6 +500,21 @@
|
||||||
app:layout_constraintBottom_toTopOf="@+id/style_bar"
|
app:layout_constraintBottom_toTopOf="@+id/style_bar"
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/fabTranslate"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end|bottom"
|
||||||
|
android:layout_margin="@dimen/fab_padding"
|
||||||
|
android:contentDescription="@string/title_translate"
|
||||||
|
app:backgroundTint="?attr/colorActionBackground"
|
||||||
|
app:fabSize="mini"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/style_bar"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:srcCompat="@drawable/outline_translate_24"
|
||||||
|
app:tint="@color/action_foreground"
|
||||||
|
app:tooltipText="@string/title_translate" />
|
||||||
|
|
||||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||||
android:id="@+id/style_bar"
|
android:id="@+id/style_bar"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
Loading…
Reference in a new issue