Allow enabling classification per folder

pull/191/head
M66B 5 years ago
parent b117d0a3df
commit ed11ddbb27

@ -3424,9 +3424,12 @@ Message classification will attempt to automatically group emails into classes,
using [Bayesian statistics](https://en.wikipedia.org/wiki/Bayesian_statistics). using [Bayesian statistics](https://en.wikipedia.org/wiki/Bayesian_statistics).
In the context of FairEmail, a folder is a class. So, for example, the inbox, the spam folder, a 'marketing' folder, etc, etc. In the context of FairEmail, a folder is a class. So, for example, the inbox, the spam folder, a 'marketing' folder, etc, etc.
You can enable message classification in the miscellaneous settings. This will enable 'learning mode' only. You can enable message classification in the miscellaneous settings. This will enable 'learning' mode only.
The classifier will 'learn' from new messages in the inbox and spam folder by default.
The folder property *Classify new messages in this folder* will enable or disable 'learning' mode for a folder.
You can clear local messages (long press a folder in the folder list of an account) and synchronize the messages again to classify existing messages.
Each folder has an option to enable automatic message classification. Each folder has an option *Automatically move classified messages to this folder* ('auto classification' for short).
When this is turned on, new messages in other folders which the classifier thinks belong to that folder will be automatically moved. When this is turned on, new messages in other folders which the classifier thinks belong to that folder will be automatically moved.
The option *Use local spam filter* in the report spam dialog will turn on message classification in the miscellaneous settings The option *Use local spam filter* in the report spam dialog will turn on message classification in the miscellaneous settings
@ -3445,14 +3448,11 @@ This will work best with messages with similar content (email addresses, subject
Classification should be considered as a best guess - it might be a wrong guess, or the classifier might not be confident enough to make any guess. Classification should be considered as a best guess - it might be a wrong guess, or the classifier might not be confident enough to make any guess.
If the classifier is unsure, it will simply leave an email where it is. If the classifier is unsure, it will simply leave an email where it is.
Classification will be done for new messages in the inbox, spam folder and user folders only.
You can clear local messages (long press a folder in the folder list of an account) and synchronize the messages again to classify existing messages.
To prevent the email server from moving a message into the spam folder again and again, To prevent the email server from moving a message into the spam folder again and again,
auto classification out of the spam folder will not be done. auto classification out of the spam folder will not be done.
The message classifier calculates the probability a message belongs in a folder (class). The message classifier calculates the probability a message belongs in a folder (class).
There are two options in miscellaneous settings that control if a message will be automatically moved into a folder, There are two options in the miscellaneous settings which control if a message will be automatically moved into a folder,
provided that auto classification is enabled for the folder: provided that auto classification is enabled for the folder:
* *Minimum class probability*: a message will only be moved when the confidence it belongs in a folder is greater than this value (default 20 %) * *Minimum class probability*: a message will only be moved when the confidence it belongs in a folder is greater than this value (default 20 %)
@ -3468,7 +3468,7 @@ Considering the defaults option values:
Classification is optimized to use as little resources as possible, but will inevitably use some extra battery power. Classification is optimized to use as little resources as possible, but will inevitably use some extra battery power.
You can delete all classification data by turning classification three times off. You can delete all classification data by turning classification in the miscellaneous settings three times off.
[Filter rules](#user-content-faq71) will be executed before classification. [Filter rules](#user-content-faq71) will be executed before classification.

File diff suppressed because it is too large Load Diff

@ -6454,9 +6454,13 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
EntityFolder inbox = db.folder().getFolderByType(account, EntityFolder.INBOX);
EntityFolder junk = db.folder().getFolderByType(account, EntityFolder.JUNK); EntityFolder junk = db.folder().getFolderByType(account, EntityFolder.JUNK);
if (junk != null) { if (inbox != null && junk != null) {
db.folder().setFolderAutoClassify(junk.id, filter); db.folder().setFolderAutoClassify(
inbox.id, inbox.auto_classify_source || filter, inbox.auto_classify_target);
db.folder().setFolderAutoClassify(
junk.id, junk.auto_classify_source || filter, filter);
prefs.edit().putBoolean("classification", true).apply(); prefs.edit().putBoolean("classification", true).apply();
} }
@ -6494,11 +6498,17 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
boolean classification = prefs.getBoolean("classification", false); boolean classification = prefs.getBoolean("classification", false);
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
EntityFolder inbox = db.folder().getFolderByType(account, EntityFolder.INBOX);
if (inbox == null)
return false;
EntityFolder junk = db.folder().getFolderByType(account, EntityFolder.JUNK); EntityFolder junk = db.folder().getFolderByType(account, EntityFolder.JUNK);
if (junk == null) if (junk == null)
return false; return false;
return classification && junk.auto_classify; return (classification &&
inbox.auto_classify_source &&
junk.auto_classify_source && junk.auto_classify_target);
} }
@Override @Override

@ -2973,7 +2973,7 @@ class Core {
runRules(context, imessage, account, folder, message, rules); runRules(context, imessage, account, folder, message, rules);
if (download && !message.ui_hide && if (download && !message.ui_hide &&
MessageClassifier.isEnabled(context) && MessageClassifier.canClassify(folder.type)) MessageClassifier.isEnabled(context) && folder.auto_classify_source)
db.message().setMessageUiHide(message.id, true); db.message().setMessageUiHide(message.id, true);
db.setTransactionSuccessful(); db.setTransactionSuccessful();
@ -3006,7 +3006,7 @@ class Core {
} }
if ((message.size != null && message.size < maxSize) || if ((message.size != null && message.size < maxSize) ||
(MessageClassifier.isEnabled(context)) && MessageClassifier.canClassify(folder.type)) { (MessageClassifier.isEnabled(context)) && folder.auto_classify_source) {
String body = parts.getHtml(context); String body = parts.getHtml(context);
File file = message.getFile(context); File file = message.getFile(context);
Helper.writeText(file, body); Helper.writeText(file, body);

@ -64,7 +64,7 @@ import static eu.faircode.email.ServiceAuthenticator.AUTH_TYPE_PASSWORD;
// https://developer.android.com/topic/libraries/architecture/room.html // https://developer.android.com/topic/libraries/architecture/room.html
@Database( @Database(
version = 183, version = 184,
entities = { entities = {
EntityIdentity.class, EntityIdentity.class,
EntityAccount.class, EntityAccount.class,
@ -1795,6 +1795,20 @@ public abstract class DB extends RoomDatabase {
Log.i("DB migration from version " + startVersion + " to " + endVersion); Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("ALTER TABLE `message` ADD COLUMN `auto_classified` INTEGER NOT NULL DEFAULT 0"); db.execSQL("ALTER TABLE `message` ADD COLUMN `auto_classified` INTEGER NOT NULL DEFAULT 0");
} }
})
.addMigrations(new Migration(183, 184) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("ALTER TABLE `folder` ADD COLUMN `auto_classify_source` INTEGER NOT NULL DEFAULT 0");
db.execSQL("ALTER TABLE `folder` RENAME COLUMN `auto_classify` TO 'auto_classify_target'");
db.execSQL("UPDATE `folder`" +
" SET auto_classify_source = 1" +
" WHERE (SELECT pop FROM account WHERE id = folder.account) = " + EntityAccount.TYPE_IMAP +
" AND (auto_classify_target" +
" OR type = '" + EntityFolder.INBOX + "'" +
" OR type = '" + EntityFolder.JUNK + "')");
}
}); });
} }

@ -287,7 +287,8 @@ public interface DaoFolder {
", poll = :poll" + ", poll = :poll" +
", poll_factor = :poll_factor" + ", poll_factor = :poll_factor" +
", download = :download" + ", download = :download" +
", auto_classify = :auto_classify" + ", auto_classify_source = :auto_classify_source" +
", auto_classify_target = :auto_classify_target" +
", `sync_days` = :sync_days" + ", `sync_days` = :sync_days" +
", `keep_days` = :keep_days" + ", `keep_days` = :keep_days" +
", auto_delete = :auto_delete" + ", auto_delete = :auto_delete" +
@ -295,7 +296,8 @@ public interface DaoFolder {
int setFolderProperties( int setFolderProperties(
long id, String rename, long id, String rename,
String display, Integer color, boolean unified, boolean navigation, boolean notify, boolean hide, String display, Integer color, boolean unified, boolean navigation, boolean notify, boolean hide,
boolean synchronize, boolean poll, int poll_factor, boolean download, boolean auto_classify, boolean synchronize, boolean poll, int poll_factor, boolean download,
boolean auto_classify_source, boolean auto_classify_target,
int sync_days, int keep_days, boolean auto_delete); int sync_days, int keep_days, boolean auto_delete);
@Query("UPDATE folder" + @Query("UPDATE folder" +
@ -344,8 +346,11 @@ public interface DaoFolder {
@Query("UPDATE folder SET poll_count = :count WHERE id = :id AND NOT (poll_count IS :count)") @Query("UPDATE folder SET poll_count = :count WHERE id = :id AND NOT (poll_count IS :count)")
int setFolderPollCount(long id, int count); int setFolderPollCount(long id, int count);
@Query("UPDATE folder SET auto_classify = :auto_classify WHERE id = :id AND NOT (auto_classify IS :auto_classify)") @Query("UPDATE folder" +
int setFolderAutoClassify(long id, boolean auto_classify); " SET auto_classify_source = :source, auto_classify_target = :target" +
" WHERE id = :id" +
" AND NOT (auto_classify_source IS :source AND auto_classify_target IS :target)")
int setFolderAutoClassify(long id, boolean source, boolean target);
@Query("DELETE FROM folder WHERE id = :id") @Query("DELETE FROM folder WHERE id = :id")
void deleteFolder(long id); void deleteFolder(long id);

@ -90,7 +90,9 @@ public class EntityFolder extends EntityOrder implements Serializable {
@NonNull @NonNull
public Boolean download = true; public Boolean download = true;
@NonNull @NonNull
public Boolean auto_classify = false; public Boolean auto_classify_source = false;
@NonNull
public Boolean auto_classify_target = false;
public Boolean subscribed; public Boolean subscribed;
@NonNull @NonNull
public Integer sync_days; public Integer sync_days;
@ -257,12 +259,16 @@ public class EntityFolder extends EntityOrder implements Serializable {
if (EntityFolder.INBOX.equals(type)) { if (EntityFolder.INBOX.equals(type)) {
this.unified = true; this.unified = true;
this.notify = true; this.notify = true;
this.auto_classify_source = true;
} }
if (EntityFolder.DRAFTS.equals(type)) { if (EntityFolder.DRAFTS.equals(type)) {
this.initialize = EntityFolder.DEFAULT_KEEP_DRAFTS; this.initialize = EntityFolder.DEFAULT_KEEP_DRAFTS;
this.keep_days = EntityFolder.DEFAULT_KEEP_DRAFTS; this.keep_days = EntityFolder.DEFAULT_KEEP_DRAFTS;
} }
if (EntityFolder.JUNK.equals(type))
this.auto_classify_source = true;
} }
void setSpecials(EntityAccount account) { void setSpecials(EntityAccount account) {
@ -503,6 +509,8 @@ public class EntityFolder extends EntityOrder implements Serializable {
this.synchronize.equals(other.synchronize) && this.synchronize.equals(other.synchronize) &&
this.poll.equals(other.poll) && this.poll.equals(other.poll) &&
this.download.equals(other.download) && this.download.equals(other.download) &&
this.auto_classify_source.equals(other.auto_classify_source) &&
this.auto_classify_target.equals(other.auto_classify_target) &&
Objects.equals(this.subscribed, other.subscribed) && Objects.equals(this.subscribed, other.subscribed) &&
this.sync_days.equals(other.sync_days) && this.sync_days.equals(other.sync_days) &&
this.keep_days.equals(other.keep_days) && this.keep_days.equals(other.keep_days) &&
@ -547,7 +555,8 @@ public class EntityFolder extends EntityOrder implements Serializable {
json.put("poll", poll); json.put("poll", poll);
json.put("poll_factor", poll_factor); json.put("poll_factor", poll_factor);
json.put("download", download); json.put("download", download);
json.put("auto_classify", auto_classify); json.put("auto_classify_source", auto_classify_source);
json.put("auto_classify_target", auto_classify_target);
json.put("sync_days", sync_days); json.put("sync_days", sync_days);
json.put("keep_days", keep_days); json.put("keep_days", keep_days);
json.put("auto_delete", auto_delete); json.put("auto_delete", auto_delete);
@ -582,8 +591,14 @@ public class EntityFolder extends EntityOrder implements Serializable {
if (json.has("download")) if (json.has("download"))
folder.download = json.getBoolean("download"); folder.download = json.getBoolean("download");
if (json.has("auto_classify")) if (json.has("auto_classify_source"))
folder.auto_classify = json.getBoolean("auto_classify"); folder.auto_classify_source = json.getBoolean("auto_classify_source");
else
folder.auto_classify_source =
(EntityFolder.INBOX.equals(folder.type) ||
EntityFolder.JUNK.equals(folder.type));
if (json.has("auto_classify_target"))
folder.auto_classify_target = json.getBoolean("auto_classify_target");
if (json.has("after")) if (json.has("after"))
folder.sync_days = json.getInt("after"); folder.sync_days = json.getInt("after");

@ -69,7 +69,8 @@ public class FragmentFolder extends FragmentBase {
private EditText etPoll; private EditText etPoll;
private TextView tvPoll; private TextView tvPoll;
private CheckBox cbDownload; private CheckBox cbDownload;
private CheckBox cbAutoClassify; private CheckBox cbAutoClassifySource;
private CheckBox cbAutoClassifyTarget;
private TextView tvAutoClassifyPro; private TextView tvAutoClassifyPro;
private Button btnInfo; private Button btnInfo;
private EditText etSyncDays; private EditText etSyncDays;
@ -131,7 +132,8 @@ public class FragmentFolder extends FragmentBase {
etPoll = view.findViewById(R.id.etPoll); etPoll = view.findViewById(R.id.etPoll);
tvPoll = view.findViewById(R.id.tvPoll); tvPoll = view.findViewById(R.id.tvPoll);
cbDownload = view.findViewById(R.id.cbDownload); cbDownload = view.findViewById(R.id.cbDownload);
cbAutoClassify = view.findViewById(R.id.cbAutoClassify); cbAutoClassifySource = view.findViewById(R.id.cbAutoClassifySource);
cbAutoClassifyTarget = view.findViewById(R.id.cbAutoClassifyTarget);
tvAutoClassifyPro = view.findViewById(R.id.tvAutoClassifyPro); tvAutoClassifyPro = view.findViewById(R.id.tvAutoClassifyPro);
btnInfo = view.findViewById(R.id.btnInfo); btnInfo = view.findViewById(R.id.btnInfo);
etSyncDays = view.findViewById(R.id.etSyncDays); etSyncDays = view.findViewById(R.id.etSyncDays);
@ -179,6 +181,14 @@ public class FragmentFolder extends FragmentBase {
} }
}); });
cbAutoClassifyTarget.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked)
cbAutoClassifySource.setChecked(true);
}
});
Helper.linkPro(tvAutoClassifyPro); Helper.linkPro(tvAutoClassifyPro);
btnInfo.setOnClickListener(new View.OnClickListener() { btnInfo.setOnClickListener(new View.OnClickListener() {
@ -221,7 +231,8 @@ public class FragmentFolder extends FragmentBase {
grpImap.setVisibility(imap ? View.VISIBLE : View.GONE); grpImap.setVisibility(imap ? View.VISIBLE : View.GONE);
tvParent.setText(parent); tvParent.setText(parent);
grpParent.setVisibility(parent == null ? View.GONE : View.VISIBLE); grpParent.setVisibility(parent == null ? View.GONE : View.VISIBLE);
cbAutoClassify.setVisibility(View.GONE); cbAutoClassifySource.setVisibility(View.GONE);
cbAutoClassifyTarget.setVisibility(View.GONE);
tvAutoClassifyPro.setVisibility(View.GONE); tvAutoClassifyPro.setVisibility(View.GONE);
grpAutoDelete.setVisibility(View.GONE); grpAutoDelete.setVisibility(View.GONE);
btnSave.setEnabled(false); btnSave.setEnabled(false);
@ -293,7 +304,8 @@ public class FragmentFolder extends FragmentBase {
etPoll.setText(folder == null ? null : Integer.toString(folder.poll_factor)); etPoll.setText(folder == null ? null : Integer.toString(folder.poll_factor));
tvPoll.setText(getString(R.string.title_factor_minutes, interval)); tvPoll.setText(getString(R.string.title_factor_minutes, interval));
cbDownload.setChecked(folder == null ? true : folder.download); cbDownload.setChecked(folder == null ? true : folder.download);
cbAutoClassify.setChecked(folder == null ? false : folder.auto_classify); cbAutoClassifySource.setChecked(folder == null ? false : folder.auto_classify_source);
cbAutoClassifyTarget.setChecked(folder == null ? false : folder.auto_classify_target);
etSyncDays.setText(Integer.toString(folder == null ? EntityFolder.DEFAULT_SYNC : folder.sync_days)); etSyncDays.setText(Integer.toString(folder == null ? EntityFolder.DEFAULT_SYNC : folder.sync_days));
if (folder != null && folder.keep_days == Integer.MAX_VALUE) if (folder != null && folder.keep_days == Integer.MAX_VALUE)
cbKeepAll.setChecked(true); cbKeepAll.setChecked(true);
@ -305,9 +317,7 @@ public class FragmentFolder extends FragmentBase {
Helper.setViewsEnabled(view, true); Helper.setViewsEnabled(view, true);
boolean always = (!ondemand && (pollInterval == 0 || exempted)); boolean always = (!ondemand && (pollInterval == 0 || exempted));
boolean canAutoClassify = (imap && boolean canAutoClassify = (imap && MessageClassifier.isEnabled(getContext()));
MessageClassifier.isEnabled(getContext()) &&
(folder == null || MessageClassifier.canClassify(folder.type)));
boolean pro = (ActivityBilling.isPro(getContext()) || boolean pro = (ActivityBilling.isPro(getContext()) ||
(folder != null && EntityFolder.JUNK.equals(folder.type))); (folder != null && EntityFolder.JUNK.equals(folder.type)));
@ -316,8 +326,9 @@ public class FragmentFolder extends FragmentBase {
etPoll.setEnabled(cbSynchronize.isChecked() && always); etPoll.setEnabled(cbSynchronize.isChecked() && always);
tvPoll.setEnabled(cbSynchronize.isChecked() && always); tvPoll.setEnabled(cbSynchronize.isChecked() && always);
grpPoll.setVisibility(imap && cbPoll.isEnabled() && cbPoll.isChecked() ? View.VISIBLE : View.GONE); grpPoll.setVisibility(imap && cbPoll.isEnabled() && cbPoll.isChecked() ? View.VISIBLE : View.GONE);
cbAutoClassify.setEnabled(pro); cbAutoClassifyTarget.setEnabled(pro);
cbAutoClassify.setVisibility(canAutoClassify ? View.VISIBLE : View.GONE); cbAutoClassifySource.setVisibility(canAutoClassify ? View.VISIBLE : View.GONE);
cbAutoClassifyTarget.setVisibility(canAutoClassify ? View.VISIBLE : View.GONE);
tvAutoClassifyPro.setVisibility(canAutoClassify && !pro ? View.VISIBLE : View.GONE); tvAutoClassifyPro.setVisibility(canAutoClassify && !pro ? View.VISIBLE : View.GONE);
etKeepDays.setEnabled(!cbKeepAll.isChecked()); etKeepDays.setEnabled(!cbKeepAll.isChecked());
cbAutoDelete.setEnabled(!cbKeepAll.isChecked()); cbAutoDelete.setEnabled(!cbKeepAll.isChecked());
@ -426,7 +437,8 @@ public class FragmentFolder extends FragmentBase {
args.putBoolean("poll", cbPoll.isChecked()); args.putBoolean("poll", cbPoll.isChecked());
args.putString("factor", etPoll.getText().toString()); args.putString("factor", etPoll.getText().toString());
args.putBoolean("download", cbDownload.isChecked()); args.putBoolean("download", cbDownload.isChecked());
args.putBoolean("auto_classify", cbAutoClassify.isChecked()); args.putBoolean("auto_classify_source", cbAutoClassifySource.isChecked());
args.putBoolean("auto_classify_target", cbAutoClassifyTarget.isChecked());
args.putString("sync", etSyncDays.getText().toString()); args.putString("sync", etSyncDays.getText().toString());
args.putString("keep", cbKeepAll.isChecked() args.putString("keep", cbKeepAll.isChecked()
? Integer.toString(Integer.MAX_VALUE) ? Integer.toString(Integer.MAX_VALUE)
@ -469,7 +481,8 @@ public class FragmentFolder extends FragmentBase {
boolean poll = args.getBoolean("poll"); boolean poll = args.getBoolean("poll");
String factor = args.getString("factor"); String factor = args.getString("factor");
boolean download = args.getBoolean("download"); boolean download = args.getBoolean("download");
boolean auto_classify = args.getBoolean("auto_classify"); boolean auto_classify_source = args.getBoolean("auto_classify_source");
boolean auto_classify_target = args.getBoolean("auto_classify_target");
String sync = args.getString("sync"); String sync = args.getString("sync");
String keep = args.getString("keep"); String keep = args.getString("keep");
boolean auto_delete = args.getBoolean("auto_delete"); boolean auto_delete = args.getBoolean("auto_delete");
@ -530,7 +543,9 @@ public class FragmentFolder extends FragmentBase {
return true; return true;
if (!Objects.equals(folder.download, download)) if (!Objects.equals(folder.download, download))
return true; return true;
if (!Objects.equals(folder.auto_classify, auto_classify)) if (!Objects.equals(folder.auto_classify_source, auto_classify_source))
return true;
if (!Objects.equals(folder.auto_classify_target, auto_classify_target))
return true; return true;
if (!Objects.equals(folder.sync_days, sync_days)) if (!Objects.equals(folder.sync_days, sync_days))
return true; return true;
@ -575,7 +590,8 @@ public class FragmentFolder extends FragmentBase {
create.poll = poll; create.poll = poll;
create.poll_factor = poll_factor; create.poll_factor = poll_factor;
create.download = download; create.download = download;
create.auto_classify = auto_classify; create.auto_classify_source = auto_classify_source;
create.auto_classify_target = auto_classify_target;
create.sync_days = sync_days; create.sync_days = sync_days;
create.keep_days = keep_days; create.keep_days = keep_days;
create.auto_delete = auto_delete; create.auto_delete = auto_delete;
@ -595,7 +611,8 @@ public class FragmentFolder extends FragmentBase {
db.folder().setFolderProperties(id, db.folder().setFolderProperties(id,
folder.name.equals(name) ? null : name, folder.name.equals(name) ? null : name,
display, color, unified, navigation, notify, hide, display, color, unified, navigation, notify, hide,
synchronize, poll, poll_factor, download, auto_classify, synchronize, poll, poll_factor, download,
auto_classify_source, auto_classify_target,
sync_days, keep_days, auto_delete); sync_days, keep_days, auto_delete);
db.folder().setFolderError(id, null); db.folder().setFolderError(id, null);

@ -61,10 +61,7 @@ public class MessageClassifier {
if (!isEnabled(context)) if (!isEnabled(context))
return; return;
if (!canClassify(folder.type)) if (!folder.auto_classify_source)
return;
if (target != null && !canClassify(target.type))
return; return;
long start = new Date().getTime(); long start = new Date().getTime();
@ -111,7 +108,7 @@ public class MessageClassifier {
db.beginTransaction(); db.beginTransaction();
EntityFolder dest = db.folder().getFolderByName(folder.account, classified); EntityFolder dest = db.folder().getFolderByName(folder.account, classified);
if (dest != null && dest.auto_classify && if (dest != null && dest.auto_classify_target &&
(pro || EntityFolder.JUNK.equals(dest.type))) { (pro || EntityFolder.JUNK.equals(dest.type))) {
EntityOperation.queue(context, message, EntityOperation.MOVE, dest.id, false, true); EntityOperation.queue(context, message, EntityOperation.MOVE, dest.id, false, true);
message.ui_hide = true; message.ui_hide = true;
@ -443,12 +440,6 @@ public class MessageClassifier {
return prefs.getBoolean("classification", false); return prefs.getBoolean("classification", false);
} }
static boolean canClassify(@NonNull String folderType) {
return EntityFolder.INBOX.equals(folderType) ||
EntityFolder.JUNK.equals(folderType) ||
EntityFolder.USER.equals(folderType);
}
static File getFile(@NonNull Context context) { static File getFile(@NonNull Context context) {
return new File(context.getFilesDir(), "classifier.json"); return new File(context.getFilesDir(), "classifier.json");
} }

@ -198,14 +198,23 @@
app:layout_constraintTop_toBottomOf="@id/etPoll" /> app:layout_constraintTop_toBottomOf="@id/etPoll" />
<CheckBox <CheckBox
android:id="@+id/cbAutoClassify" android:id="@+id/cbAutoClassifySource"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:text="@string/title_auto_classify" android:text="@string/title_auto_classify_source"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbDownload" /> app:layout_constraintTop_toBottomOf="@id/cbDownload" />
<CheckBox
android:id="@+id/cbAutoClassifyTarget"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_auto_classify_target"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbAutoClassifySource" />
<eu.faircode.email.FixedTextView <eu.faircode.email.FixedTextView
android:id="@+id/tvAutoClassifyPro" android:id="@+id/tvAutoClassifyPro"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -214,7 +223,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small" android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?android:attr/textColorLink" android:textColor="?android:attr/textColorLink"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbAutoClassify" /> app:layout_constraintTop_toBottomOf="@id/cbAutoClassifyTarget" />
<!-- after --> <!-- after -->

@ -787,7 +787,8 @@
<string name="title_poll_folder">Check periodically instead of continuous synchronize</string> <string name="title_poll_folder">Check periodically instead of continuous synchronize</string>
<string name="title_download_folder">Automatically download message texts and attachments</string> <string name="title_download_folder">Automatically download message texts and attachments</string>
<string name="title_notify_folder">Notify on new messages</string> <string name="title_notify_folder">Notify on new messages</string>
<string name="title_auto_classify">Automatically move classified messages</string> <string name="title_auto_classify_source">Classify new messages in this folder</string>
<string name="title_auto_classify_target">Automatically move classified messages to this folder</string>
<string name="title_sync_days">Synchronize messages (days)</string> <string name="title_sync_days">Synchronize messages (days)</string>
<string name="title_sync_days_remark">Increasing this value will increase battery and data usage</string> <string name="title_sync_days_remark">Increasing this value will increase battery and data usage</string>
<string name="title_keep_days">Keep messages (days)</string> <string name="title_keep_days">Keep messages (days)</string>

Loading…
Cancel
Save