From caf90aac6fc49c7ad3fbaaba500fdc08e21caa1c Mon Sep 17 00:00:00 2001 From: M66B Date: Sat, 11 Nov 2023 22:58:51 +0100 Subject: [PATCH] Added integrations settings tab page --- .../eu/faircode/email/FragmentOptions.java | 8 +- .../email/FragmentOptionsIntegrations.java | 602 +++++++++++++++++ .../faircode/email/FragmentOptionsMisc.java | 457 +------------ .../res/drawable/twotone_extension_24.xml | 15 + .../layout/fragment_options_integrations.xml | 619 ++++++++++++++++++ .../main/res/layout/fragment_options_misc.xml | 600 +---------------- 6 files changed, 1246 insertions(+), 1055 deletions(-) create mode 100644 app/src/main/java/eu/faircode/email/FragmentOptionsIntegrations.java create mode 100644 app/src/main/res/drawable/twotone_extension_24.xml create mode 100644 app/src/main/res/layout/fragment_options_integrations.xml diff --git a/app/src/main/java/eu/faircode/email/FragmentOptions.java b/app/src/main/java/eu/faircode/email/FragmentOptions.java index 0739c238db..55d90dd776 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptions.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptions.java @@ -82,6 +82,7 @@ public class FragmentOptions extends FragmentBase { R.layout.fragment_options_privacy, R.layout.fragment_options_encryption, R.layout.fragment_options_notifications, + R.layout.fragment_options_integrations, R.layout.fragment_options_misc, R.layout.fragment_options_backup }; @@ -96,6 +97,7 @@ public class FragmentOptions extends FragmentBase { R.string.title_advanced_section_privacy, R.string.title_advanced_section_encryption, R.string.title_advanced_section_notifications, + R.string.title_advanced_caption_integrations, R.string.title_advanced_section_misc, R.string.title_advanced_section_backup }; @@ -110,6 +112,7 @@ public class FragmentOptions extends FragmentBase { R.drawable.twotone_account_circle_24, R.drawable.twotone_lock_24, R.drawable.twotone_notifications_24, + R.drawable.twotone_extension_24, R.drawable.twotone_more_24, R.drawable.twotone_save_alt_24 }; @@ -124,6 +127,7 @@ public class FragmentOptions extends FragmentBase { "privacy", "encryption", "notifications", + "integrations", "misc", "backup" )); @@ -529,8 +533,10 @@ public class FragmentOptions extends FragmentBase { case 8: return new FragmentOptionsNotifications(); case 9: - return new FragmentOptionsMisc(); + return new FragmentOptionsIntegrations(); case 10: + return new FragmentOptionsMisc(); + case 11: return new FragmentOptionsBackup(); default: throw new IllegalArgumentException(); diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsIntegrations.java b/app/src/main/java/eu/faircode/email/FragmentOptionsIntegrations.java new file mode 100644 index 0000000000..8ee545a35e --- /dev/null +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsIntegrations.java @@ -0,0 +1,602 @@ +package eu.faircode.email; + +/* + This file is part of FairEmail. + + FairEmail is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + FairEmail is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with FairEmail. If not, see . + + Copyright 2018-2023 by Marcel Bokhorst (M66B) +*/ + +import android.app.ActivityManager; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Bundle; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.SeekBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.SwitchCompat; +import androidx.cardview.widget.CardView; +import androidx.preference.PreferenceManager; + +import com.google.android.material.textfield.TextInputLayout; + +import java.text.NumberFormat; + +public class FragmentOptionsIntegrations extends FragmentBase implements SharedPreferences.OnSharedPreferenceChangeListener { + private View view; + private ImageButton ibHelp; + + private SwitchCompat swLanguageTool; + private TextView tvLanguageToolPrivacy; + private SwitchCompat swLanguageToolSentence; + private SwitchCompat swLanguageToolAuto; + private SwitchCompat swLanguageToolPicky; + private SwitchCompat swLanguageToolHighlight; + private SwitchCompat swLanguageToolDescription; + private EditText etLanguageTool; + private EditText etLanguageToolUser; + private TextInputLayout tilLanguageToolKey; + private ImageButton ibLanguageTool; + private SwitchCompat swDeepL; + private TextView tvDeepLPrivacy; + private ImageButton ibDeepL; + private SwitchCompat swVirusTotal; + private TextView tvVirusTotalPrivacy; + private TextInputLayout tilVirusTotal; + private ImageButton ibVirusTotal; + private SwitchCompat swSend; + private EditText etSend; + private ImageButton ibSend; + private SwitchCompat swOpenAi; + private TextView tvOpenAiPrivacy; + private EditText etOpenAi; + private TextInputLayout tilOpenAi; + private EditText etOpenAiModel; + private TextView tvOpenAiTemperature; + private SeekBar sbOpenAiTemperature; + private SwitchCompat swOpenAiModeration; + private ImageButton ibOpenAi; + + private CardView cardVirusTotal; + private CardView cardSend; + private CardView cardOpenAi; + + private NumberFormat NF = NumberFormat.getNumberInstance(); + + private final static String[] RESET_OPTIONS = new String[]{ + "lt_enabled", "lt_sentence", "lt_auto", "lt_picky", "lt_highlight", "lt_description", "lt_uri", "lt_user", "lt_key", + "deepl_enabled", + "vt_enabled", "vt_apikey", + "send_enabled", "send_host", "send_dlimit", "send_tlimit", + "openai_enabled", "openai_uri", "openai_apikey", "openai_model", "openai_temperature", "openai_moderation" + }; + + @Override + @Nullable + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + setSubtitle(R.string.title_setup); + setHasOptionsMenu(true); + + view = inflater.inflate(R.layout.fragment_options_integrations, container, false); + + // Get controls + + ibHelp = view.findViewById(R.id.ibHelp); + + swLanguageTool = view.findViewById(R.id.swLanguageTool); + tvLanguageToolPrivacy = view.findViewById(R.id.tvLanguageToolPrivacy); + swLanguageToolSentence = view.findViewById(R.id.swLanguageToolSentence); + swLanguageToolAuto = view.findViewById(R.id.swLanguageToolAuto); + swLanguageToolPicky = view.findViewById(R.id.swLanguageToolPicky); + swLanguageToolHighlight = view.findViewById(R.id.swLanguageToolHighlight); + swLanguageToolDescription = view.findViewById(R.id.swLanguageToolDescription); + etLanguageTool = view.findViewById(R.id.etLanguageTool); + etLanguageToolUser = view.findViewById(R.id.etLanguageToolUser); + tilLanguageToolKey = view.findViewById(R.id.tilLanguageToolKey); + ibLanguageTool = view.findViewById(R.id.ibLanguageTool); + swDeepL = view.findViewById(R.id.swDeepL); + tvDeepLPrivacy = view.findViewById(R.id.tvDeepLPrivacy); + ibDeepL = view.findViewById(R.id.ibDeepL); + swVirusTotal = view.findViewById(R.id.swVirusTotal); + tvVirusTotalPrivacy = view.findViewById(R.id.tvVirusTotalPrivacy); + tilVirusTotal = view.findViewById(R.id.tilVirusTotal); + ibVirusTotal = view.findViewById(R.id.ibVirusTotal); + swSend = view.findViewById(R.id.swSend); + etSend = view.findViewById(R.id.etSend); + ibSend = view.findViewById(R.id.ibSend); + swOpenAi = view.findViewById(R.id.swOpenAi); + tvOpenAiPrivacy = view.findViewById(R.id.tvOpenAiPrivacy); + etOpenAi = view.findViewById(R.id.etOpenAi); + tilOpenAi = view.findViewById(R.id.tilOpenAi); + etOpenAiModel = view.findViewById(R.id.etOpenAiModel); + tvOpenAiTemperature = view.findViewById(R.id.tvOpenAiTemperature); + sbOpenAiTemperature = view.findViewById(R.id.sbOpenAiTemperature); + swOpenAiModeration = view.findViewById(R.id.swOpenAiModeration); + ibOpenAi = view.findViewById(R.id.ibOpenAi); + + cardVirusTotal = view.findViewById(R.id.cardVirusTotal); + cardSend = view.findViewById(R.id.cardSend); + cardOpenAi = view.findViewById(R.id.cardOpenAi); + + setOptions(); + + // Wire controls + + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + + ibHelp.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Helper.view(v.getContext(), Helper.getSupportUri(v.getContext(), "Options:misc"), false); + } + }); + + + swLanguageTool.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("lt_enabled", checked).apply(); + swLanguageToolSentence.setEnabled(checked); + swLanguageToolAuto.setEnabled(checked); + swLanguageToolPicky.setEnabled(checked); + swLanguageToolHighlight.setEnabled(checked); + swLanguageToolDescription.setEnabled(checked); + } + }); + + tvLanguageToolPrivacy.getPaint().setUnderlineText(true); + tvLanguageToolPrivacy.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Helper.view(v.getContext(), Uri.parse(Helper.LT_PRIVACY_URI), true); + } + }); + + swLanguageToolSentence.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("lt_sentence", checked).apply(); + } + }); + + swLanguageToolAuto.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("lt_auto", checked).apply(); + } + }); + + swLanguageToolPicky.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("lt_picky", checked).apply(); + } + }); + + swLanguageToolHighlight.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("lt_highlight", checked).apply(); + } + }); + + swLanguageToolDescription.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("lt_description", checked).apply(); + } + }); + + etLanguageTool.setHint(LanguageTool.LT_URI); + etLanguageTool.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 apikey = s.toString().trim(); + if (TextUtils.isEmpty(apikey)) + prefs.edit().remove("lt_uri").apply(); + else + prefs.edit().putString("lt_uri", apikey).apply(); + } + }); + + etLanguageToolUser.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 apikey = s.toString().trim(); + if (TextUtils.isEmpty(apikey)) + prefs.edit().remove("lt_user").apply(); + else + prefs.edit().putString("lt_user", apikey).apply(); + } + }); + + tilLanguageToolKey.getEditText().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 apikey = s.toString().trim(); + if (TextUtils.isEmpty(apikey)) + prefs.edit().remove("lt_key").apply(); + else + prefs.edit().putString("lt_key", apikey).apply(); + } + }); + + ibLanguageTool.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Helper.viewFAQ(v.getContext(), 180); + } + }); + + tvDeepLPrivacy.getPaint().setUnderlineText(true); + tvDeepLPrivacy.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Helper.view(v.getContext(), Uri.parse(DeepL.PRIVACY_URI), true); + } + }); + + swDeepL.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("deepl_enabled", checked).apply(); + } + }); + + ibDeepL.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + DeepL.FragmentDialogDeepL fragment = new DeepL.FragmentDialogDeepL(); + fragment.show(getParentFragmentManager(), "deepl:configure"); + } + }); + + swVirusTotal.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("vt_enabled", checked).apply(); + } + }); + + tvVirusTotalPrivacy.getPaint().setUnderlineText(true); + tvVirusTotalPrivacy.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Helper.view(v.getContext(), Uri.parse(VirusTotal.URI_PRIVACY), true); + } + }); + + tilVirusTotal.getEditText().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 apikey = s.toString().trim(); + if (TextUtils.isEmpty(apikey)) + prefs.edit().remove("vt_apikey").apply(); + else + prefs.edit().putString("vt_apikey", apikey).apply(); + } + }); + + ibVirusTotal.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Helper.viewFAQ(v.getContext(), 181); + } + }); + + swSend.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("send_enabled", checked).apply(); + } + }); + + etSend.setHint(Send.DEFAULT_SERVER); + etSend.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 apikey = s.toString().trim(); + if (TextUtils.isEmpty(apikey)) + prefs.edit().remove("send_host").apply(); + else + prefs.edit().putString("send_host", apikey).apply(); + } + }); + + ibSend.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Helper.viewFAQ(v.getContext(), 183); + } + }); + + swOpenAi.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("openai_enabled", checked).apply(); + etOpenAiModel.setEnabled(checked); + sbOpenAiTemperature.setEnabled(checked); + swOpenAiModeration.setEnabled(checked); + } + }); + + tvOpenAiPrivacy.getPaint().setUnderlineText(true); + tvOpenAiPrivacy.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Helper.view(v.getContext(), Uri.parse(BuildConfig.OPENAI_PRIVACY), true); + } + }); + + etOpenAi.setHint(BuildConfig.OPENAI_ENDPOINT); + etOpenAi.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 apikey = s.toString().trim(); + if (TextUtils.isEmpty(apikey)) + prefs.edit().remove("openai_uri").apply(); + else + prefs.edit().putString("openai_uri", apikey).apply(); + } + }); + + tilOpenAi.getEditText().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 apikey = s.toString().trim(); + if (TextUtils.isEmpty(apikey)) + prefs.edit().remove("openai_apikey").apply(); + else + prefs.edit().putString("openai_apikey", apikey).apply(); + } + }); + + etOpenAiModel.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 model = s.toString().trim(); + if (TextUtils.isEmpty(model)) + prefs.edit().remove("openai_model").apply(); + else + prefs.edit().putString("openai_model", model).apply(); + } + }); + + sbOpenAiTemperature.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + float temp = progress / 10f; + prefs.edit().putFloat("openai_temperature", temp).apply(); + } + + @Override + public void onStartTrackingTouch(SeekBar seekBar) { + // Do nothing + } + + @Override + public void onStopTrackingTouch(SeekBar seekBar) { + // Do nothing + } + }); + + swOpenAiModeration.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { + prefs.edit().putBoolean("openai_moderation", checked).apply(); + } + }); + + ibOpenAi.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Helper.viewFAQ(v.getContext(), 190); + } + }); + + // Initialize + FragmentDialogTheme.setBackground(getContext(), view, false); + + cardVirusTotal.setVisibility(BuildConfig.PLAY_STORE_RELEASE ? View.GONE : View.VISIBLE); + cardSend.setVisibility(BuildConfig.PLAY_STORE_RELEASE ? View.GONE : View.VISIBLE); + cardOpenAi.setVisibility(TextUtils.isEmpty(BuildConfig.OPENAI_ENDPOINT) ? View.GONE : View.VISIBLE); + + PreferenceManager.getDefaultSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this); + + return view; + } + + @Override + public void onDestroyView() { + PreferenceManager.getDefaultSharedPreferences(getContext()).unregisterOnSharedPreferenceChangeListener(this); + super.onDestroyView(); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + if ("lt_uri".equals(key) || + "lt_user".equals(key) || + "lt_key".equals(key) || + "vt_apikey".equals(key) || + "send_host".equals(key) || + "openai_uri".equals(key) || + "openai_apikey".equals(key) || + "openai_model".equals(key)) + return; + + getMainHandler().removeCallbacks(update); + getMainHandler().postDelayed(update, FragmentOptions.DELAY_SETOPTIONS); + } + + private Runnable update = new RunnableEx("misc") { + @Override + protected void delegate() { + setOptions(); + } + }; + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.menu_options, menu); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.menu_default) { + FragmentOptions.reset(getContext(), RESET_OPTIONS, null); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void setOptions() { + try { + if (view == null || getContext() == null) + return; + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + + swLanguageTool.setChecked(prefs.getBoolean("lt_enabled", false)); + swLanguageToolSentence.setChecked(prefs.getBoolean("lt_sentence", false)); + swLanguageToolSentence.setEnabled(swLanguageTool.isChecked()); + swLanguageToolAuto.setChecked(prefs.getBoolean("lt_auto", true)); + swLanguageToolAuto.setEnabled(swLanguageTool.isChecked()); + swLanguageToolPicky.setChecked(prefs.getBoolean("lt_picky", false)); + swLanguageToolPicky.setEnabled(swLanguageTool.isChecked()); + swLanguageToolHighlight.setChecked(prefs.getBoolean("lt_highlight", !BuildConfig.PLAY_STORE_RELEASE)); + swLanguageToolHighlight.setEnabled(swLanguageTool.isChecked()); + swLanguageToolDescription.setChecked(prefs.getBoolean("lt_description", false)); + swLanguageToolDescription.setEnabled(swLanguageTool.isChecked()); + etLanguageTool.setText(prefs.getString("lt_uri", null)); + etLanguageToolUser.setText(prefs.getString("lt_user", null)); + tilLanguageToolKey.getEditText().setText(prefs.getString("lt_key", null)); + swDeepL.setChecked(prefs.getBoolean("deepl_enabled", false)); + swVirusTotal.setChecked(prefs.getBoolean("vt_enabled", false)); + tilVirusTotal.getEditText().setText(prefs.getString("vt_apikey", null)); + swSend.setChecked(prefs.getBoolean("send_enabled", false)); + etSend.setText(prefs.getString("send_host", null)); + swOpenAi.setChecked(prefs.getBoolean("openai_enabled", false)); + etOpenAi.setText(prefs.getString("openai_uri", null)); + tilOpenAi.getEditText().setText(prefs.getString("openai_apikey", null)); + etOpenAiModel.setText(prefs.getString("openai_model", null)); + etOpenAiModel.setEnabled(swOpenAi.isChecked()); + + float temperature = prefs.getFloat("openai_temperature", 0.5f); + tvOpenAiTemperature.setText(getString(R.string.title_advanced_openai_temperature, NF.format(temperature))); + sbOpenAiTemperature.setProgress(Math.round(temperature * 10)); + sbOpenAiTemperature.setEnabled(swOpenAi.isChecked()); + + swOpenAiModeration.setChecked(prefs.getBoolean("openai_moderation", false)); + swOpenAiModeration.setEnabled(swOpenAi.isChecked()); + } catch (Throwable ex) { + Log.e(ex); + } + } +} diff --git a/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java b/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java index ca8e1b29e6..a3b4a80f21 100644 --- a/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java +++ b/app/src/main/java/eu/faircode/email/FragmentOptionsMisc.java @@ -82,8 +82,6 @@ import androidx.lifecycle.Observer; import androidx.preference.PreferenceManager; import androidx.work.WorkManager; -import com.google.android.material.textfield.TextInputLayout; - import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -108,6 +106,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc private View view; private ImageButton ibHelp; + private SwitchCompat swPowerMenu; private SwitchCompat swSendSelf; private SwitchCompat swExternalSearch; @@ -147,37 +146,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc private TextView tvLastCleanup; private TextView tvSdcard; - private SwitchCompat swLanguageTool; - private TextView tvLanguageToolPrivacy; - private SwitchCompat swLanguageToolSentence; - private SwitchCompat swLanguageToolAuto; - private SwitchCompat swLanguageToolPicky; - private SwitchCompat swLanguageToolHighlight; - private SwitchCompat swLanguageToolDescription; - private EditText etLanguageTool; - private EditText etLanguageToolUser; - private TextInputLayout tilLanguageToolKey; - private ImageButton ibLanguageTool; - private SwitchCompat swDeepL; - private TextView tvDeepLPrivacy; - private ImageButton ibDeepL; - private SwitchCompat swVirusTotal; - private TextView tvVirusTotalPrivacy; - private TextInputLayout tilVirusTotal; - private ImageButton ibVirusTotal; - private SwitchCompat swSend; - private EditText etSend; - private ImageButton ibSend; - private SwitchCompat swOpenAi; - private TextView tvOpenAiPrivacy; - private EditText etOpenAi; - private TextInputLayout tilOpenAi; - private EditText etOpenAiModel; - private TextView tvOpenAiTemperature; - private SeekBar sbOpenAiTemperature; - private SwitchCompat swOpenAiModeration; - private ImageButton ibOpenAi; - private CardView cardAdvanced; private SwitchCompat swWatchdog; private SwitchCompat swExperiments; @@ -286,9 +254,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc private Group grpAnnouncements; private Group grpTest; - private CardView cardVirusTotal; - private CardView cardSend; - private CardView cardOpenAi; private CardView cardDebug; private NumberFormat NF = NumberFormat.getNumberInstance(); @@ -301,11 +266,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc "classification", "class_min_probability", "class_min_difference", "show_filtered", "haptic_feedback", "language", - "lt_enabled", "lt_sentence", "lt_auto", "lt_picky", "lt_highlight", "lt_description", "lt_uri", "lt_user", "lt_key", - "deepl_enabled", - "vt_enabled", "vt_apikey", - "send_enabled", "send_host", "send_dlimit", "send_tlimit", - "openai_enabled", "openai_uri", "openai_apikey", "openai_model", "openai_temperature", "openai_moderation", "updates", "weekly", "beta", "show_changelog", "announcements", "crash_reports", "cleanup_attachments", "watchdog", "experiments", "main_log", "main_log_memory", "protocol", "log_level", "debug", "leak_canary", @@ -420,37 +380,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc tvLastCleanup = view.findViewById(R.id.tvLastCleanup); tvSdcard = view.findViewById(R.id.tvSdcard); - swLanguageTool = view.findViewById(R.id.swLanguageTool); - tvLanguageToolPrivacy = view.findViewById(R.id.tvLanguageToolPrivacy); - swLanguageToolSentence = view.findViewById(R.id.swLanguageToolSentence); - swLanguageToolAuto = view.findViewById(R.id.swLanguageToolAuto); - swLanguageToolPicky = view.findViewById(R.id.swLanguageToolPicky); - swLanguageToolHighlight = view.findViewById(R.id.swLanguageToolHighlight); - swLanguageToolDescription = view.findViewById(R.id.swLanguageToolDescription); - etLanguageTool = view.findViewById(R.id.etLanguageTool); - etLanguageToolUser = view.findViewById(R.id.etLanguageToolUser); - tilLanguageToolKey = view.findViewById(R.id.tilLanguageToolKey); - ibLanguageTool = view.findViewById(R.id.ibLanguageTool); - swDeepL = view.findViewById(R.id.swDeepL); - tvDeepLPrivacy = view.findViewById(R.id.tvDeepLPrivacy); - ibDeepL = view.findViewById(R.id.ibDeepL); - swVirusTotal = view.findViewById(R.id.swVirusTotal); - tvVirusTotalPrivacy = view.findViewById(R.id.tvVirusTotalPrivacy); - tilVirusTotal = view.findViewById(R.id.tilVirusTotal); - ibVirusTotal = view.findViewById(R.id.ibVirusTotal); - swSend = view.findViewById(R.id.swSend); - etSend = view.findViewById(R.id.etSend); - ibSend = view.findViewById(R.id.ibSend); - swOpenAi = view.findViewById(R.id.swOpenAi); - tvOpenAiPrivacy = view.findViewById(R.id.tvOpenAiPrivacy); - etOpenAi = view.findViewById(R.id.etOpenAi); - tilOpenAi = view.findViewById(R.id.tilOpenAi); - etOpenAiModel = view.findViewById(R.id.etOpenAiModel); - tvOpenAiTemperature = view.findViewById(R.id.tvOpenAiTemperature); - sbOpenAiTemperature = view.findViewById(R.id.sbOpenAiTemperature); - swOpenAiModeration = view.findViewById(R.id.swOpenAiModeration); - ibOpenAi = view.findViewById(R.id.ibOpenAi); - cardAdvanced = view.findViewById(R.id.cardAdvanced); swWatchdog = view.findViewById(R.id.swWatchdog); swExperiments = view.findViewById(R.id.swExperiments); @@ -559,9 +488,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc grpAnnouncements = view.findViewById(R.id.grpAnnouncements); grpTest = view.findViewById(R.id.grpTest); - cardVirusTotal = view.findViewById(R.id.cardVirusTotal); - cardSend = view.findViewById(R.id.cardSend); - cardOpenAi = view.findViewById(R.id.cardOpenAi); cardDebug = view.findViewById(R.id.cardDebug); setOptions(); @@ -924,345 +850,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc } }); - swLanguageTool.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - prefs.edit().putBoolean("lt_enabled", checked).apply(); - swLanguageToolSentence.setEnabled(checked); - swLanguageToolAuto.setEnabled(checked); - swLanguageToolPicky.setEnabled(checked); - swLanguageToolHighlight.setEnabled(checked); - swLanguageToolDescription.setEnabled(checked); - } - }); - - tvLanguageToolPrivacy.getPaint().setUnderlineText(true); - tvLanguageToolPrivacy.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Helper.view(v.getContext(), Uri.parse(Helper.LT_PRIVACY_URI), true); - } - }); - - swLanguageToolSentence.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - prefs.edit().putBoolean("lt_sentence", checked).apply(); - } - }); - - swLanguageToolAuto.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - prefs.edit().putBoolean("lt_auto", checked).apply(); - } - }); - - swLanguageToolPicky.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - prefs.edit().putBoolean("lt_picky", checked).apply(); - } - }); - - swLanguageToolHighlight.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - prefs.edit().putBoolean("lt_highlight", checked).apply(); - } - }); - - swLanguageToolDescription.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - prefs.edit().putBoolean("lt_description", checked).apply(); - } - }); - - etLanguageTool.setHint(LanguageTool.LT_URI); - etLanguageTool.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 apikey = s.toString().trim(); - if (TextUtils.isEmpty(apikey)) - prefs.edit().remove("lt_uri").apply(); - else - prefs.edit().putString("lt_uri", apikey).apply(); - } - }); - - etLanguageToolUser.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 apikey = s.toString().trim(); - if (TextUtils.isEmpty(apikey)) - prefs.edit().remove("lt_user").apply(); - else - prefs.edit().putString("lt_user", apikey).apply(); - } - }); - - tilLanguageToolKey.getEditText().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 apikey = s.toString().trim(); - if (TextUtils.isEmpty(apikey)) - prefs.edit().remove("lt_key").apply(); - else - prefs.edit().putString("lt_key", apikey).apply(); - } - }); - - ibLanguageTool.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Helper.viewFAQ(v.getContext(), 180); - } - }); - - tvDeepLPrivacy.getPaint().setUnderlineText(true); - tvDeepLPrivacy.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Helper.view(v.getContext(), Uri.parse(DeepL.PRIVACY_URI), true); - } - }); - - swDeepL.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - prefs.edit().putBoolean("deepl_enabled", checked).apply(); - } - }); - - ibDeepL.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - DeepL.FragmentDialogDeepL fragment = new DeepL.FragmentDialogDeepL(); - fragment.show(getParentFragmentManager(), "deepl:configure"); - } - }); - - swVirusTotal.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - prefs.edit().putBoolean("vt_enabled", checked).apply(); - } - }); - - tvVirusTotalPrivacy.getPaint().setUnderlineText(true); - tvVirusTotalPrivacy.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Helper.view(v.getContext(), Uri.parse(VirusTotal.URI_PRIVACY), true); - } - }); - - tilVirusTotal.getEditText().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 apikey = s.toString().trim(); - if (TextUtils.isEmpty(apikey)) - prefs.edit().remove("vt_apikey").apply(); - else - prefs.edit().putString("vt_apikey", apikey).apply(); - } - }); - - ibVirusTotal.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Helper.viewFAQ(v.getContext(), 181); - } - }); - - swSend.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - prefs.edit().putBoolean("send_enabled", checked).apply(); - } - }); - - etSend.setHint(Send.DEFAULT_SERVER); - etSend.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 apikey = s.toString().trim(); - if (TextUtils.isEmpty(apikey)) - prefs.edit().remove("send_host").apply(); - else - prefs.edit().putString("send_host", apikey).apply(); - } - }); - - ibSend.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Helper.viewFAQ(v.getContext(), 183); - } - }); - - swOpenAi.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - prefs.edit().putBoolean("openai_enabled", checked).apply(); - } - }); - - tvOpenAiPrivacy.getPaint().setUnderlineText(true); - tvOpenAiPrivacy.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Helper.view(v.getContext(), Uri.parse(BuildConfig.OPENAI_PRIVACY), true); - } - }); - - etOpenAi.setHint(BuildConfig.OPENAI_ENDPOINT); - etOpenAi.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 apikey = s.toString().trim(); - if (TextUtils.isEmpty(apikey)) - prefs.edit().remove("openai_uri").apply(); - else - prefs.edit().putString("openai_uri", apikey).apply(); - } - }); - - tilOpenAi.getEditText().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 apikey = s.toString().trim(); - if (TextUtils.isEmpty(apikey)) - prefs.edit().remove("openai_apikey").apply(); - else - prefs.edit().putString("openai_apikey", apikey).apply(); - } - }); - - etOpenAiModel.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 model = s.toString().trim(); - if (TextUtils.isEmpty(model)) - prefs.edit().remove("openai_model").apply(); - else - prefs.edit().putString("openai_model", model).apply(); - } - }); - - sbOpenAiTemperature.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - float temp = progress / 10f; - prefs.edit().putFloat("openai_temperature", temp).apply(); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - // Do nothing - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - // Do nothing - } - }); - - swOpenAiModeration.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { - prefs.edit().putBoolean("openai_moderation", checked).apply(); - } - }); - - ibOpenAi.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Helper.viewFAQ(v.getContext(), 190); - } - }); - swWatchdog.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton compoundButton, boolean checked) { @@ -2395,9 +1982,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc grpBitbucket.setVisibility(View.GONE); grpAnnouncements.setVisibility(TextUtils.isEmpty(BuildConfig.ANNOUNCEMENT_URI) ? View.GONE : View.VISIBLE); - cardVirusTotal.setVisibility(BuildConfig.PLAY_STORE_RELEASE ? View.GONE : View.VISIBLE); - cardSend.setVisibility(BuildConfig.PLAY_STORE_RELEASE ? View.GONE : View.VISIBLE); - cardOpenAi.setVisibility(TextUtils.isEmpty(BuildConfig.OPENAI_ENDPOINT) ? View.GONE : View.VISIBLE); grpTest.setVisibility(BuildConfig.TEST_RELEASE ? View.VISIBLE : View.GONE); setLastCleanup(prefs.getLong("last_cleanup", -1)); @@ -2492,15 +2076,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc if ("last_daily".equals(key)) tvLastDaily.setText(new Date(prefs.getLong(key, 0)).toString()); - if ("lt_uri".equals(key) || - "lt_user".equals(key) || - "lt_key".equals(key) || - "vt_apikey".equals(key) || - "send_host".equals(key) || - "openai_uri".equals(key) || - "openai_apikey".equals(key) || - "openai_model".equals(key) || - "viewport_height".equals(key)) + if ("viewport_height".equals(key)) return; if ("global_keywords".equals(key)) @@ -2690,35 +2266,6 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc if (selected >= 0) spLanguage.setSelection(selected); - swLanguageTool.setChecked(prefs.getBoolean("lt_enabled", false)); - swLanguageToolSentence.setChecked(prefs.getBoolean("lt_sentence", false)); - swLanguageToolSentence.setEnabled(swLanguageTool.isChecked()); - swLanguageToolAuto.setChecked(prefs.getBoolean("lt_auto", true)); - swLanguageToolAuto.setEnabled(swLanguageTool.isChecked()); - swLanguageToolPicky.setChecked(prefs.getBoolean("lt_picky", false)); - swLanguageToolPicky.setEnabled(swLanguageTool.isChecked()); - swLanguageToolHighlight.setChecked(prefs.getBoolean("lt_highlight", !BuildConfig.PLAY_STORE_RELEASE)); - swLanguageToolHighlight.setEnabled(swLanguageTool.isChecked()); - swLanguageToolDescription.setChecked(prefs.getBoolean("lt_description", false)); - swLanguageToolDescription.setEnabled(swLanguageTool.isChecked()); - etLanguageTool.setText(prefs.getString("lt_uri", null)); - etLanguageToolUser.setText(prefs.getString("lt_user", null)); - tilLanguageToolKey.getEditText().setText(prefs.getString("lt_key", null)); - swDeepL.setChecked(prefs.getBoolean("deepl_enabled", false)); - swVirusTotal.setChecked(prefs.getBoolean("vt_enabled", false)); - tilVirusTotal.getEditText().setText(prefs.getString("vt_apikey", null)); - swSend.setChecked(prefs.getBoolean("send_enabled", false)); - etSend.setText(prefs.getString("send_host", null)); - swOpenAi.setChecked(prefs.getBoolean("openai_enabled", false)); - etOpenAi.setText(prefs.getString("openai_uri", null)); - tilOpenAi.getEditText().setText(prefs.getString("openai_apikey", null)); - etOpenAiModel.setText(prefs.getString("openai_model", null)); - - float temperature = prefs.getFloat("openai_temperature", 0.5f); - tvOpenAiTemperature.setText(getString(R.string.title_advanced_openai_temperature, NF.format(temperature))); - sbOpenAiTemperature.setProgress(Math.round(temperature * 10)); - swOpenAiModeration.setChecked(prefs.getBoolean("openai_moderation", false)); - swWatchdog.setChecked(prefs.getBoolean("watchdog", true)); swMainLog.setChecked(prefs.getBoolean("main_log", true)); swMainLogMem.setChecked(prefs.getBoolean("main_log_memory", false)); diff --git a/app/src/main/res/drawable/twotone_extension_24.xml b/app/src/main/res/drawable/twotone_extension_24.xml new file mode 100644 index 0000000000..a1d6829807 --- /dev/null +++ b/app/src/main/res/drawable/twotone_extension_24.xml @@ -0,0 +1,15 @@ + + + + diff --git a/app/src/main/res/layout/fragment_options_integrations.xml b/app/src/main/res/layout/fragment_options_integrations.xml new file mode 100644 index 0000000000..9b96b55d03 --- /dev/null +++ b/app/src/main/res/layout/fragment_options_integrations.xml @@ -0,0 +1,619 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_options_misc.xml b/app/src/main/res/layout/fragment_options_misc.xml index 1083b6ed44..07ac1578c9 100644 --- a/app/src/main/res/layout/fragment_options_misc.xml +++ b/app/src/main/res/layout/fragment_options_misc.xml @@ -643,604 +643,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + app:layout_constraintTop_toBottomOf="@id/cardGeneral">