Added option for local spam filter

This commit is contained in:
M66B 2021-01-05 10:18:02 +01:00
parent 82a629e7d1
commit e7cce96751
5 changed files with 114 additions and 7 deletions

4
FAQ.md
View File

@ -3423,6 +3423,10 @@ This will enable learning mode only.
Each folder has an option to enable automatic message classification.
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* turns on message classification and auto classification for the spam folder.
Please understand that this is not a replacement for the spam filter of the email server.
See also [this FAQ](#user-content-faq92).
A practical example: suppose there is a folder 'marketing' and auto message classification is enabled for this folder.
Each time you move a message into this folder you'll train FairEmail that similar messages belong in this folder.
Each time you move a message out of this folder you'll train FairEmail that similar messages do not belong in this folder.

View File

@ -6355,7 +6355,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
Bundle args = getArguments();
final Bundle args = getArguments();
final long account = args.getLong("account");
final int protocol = args.getInt("protocol");
final long folder = args.getLong("folder");
@ -6365,15 +6365,17 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_junk, null);
final TextView tvMessage = view.findViewById(R.id.tvMessage);
final ImageButton ibInfo = view.findViewById(R.id.ibInfo);
final ImageButton ibInfoProvider = view.findViewById(R.id.ibInfoProvider);
final CheckBox cbBlockSender = view.findViewById(R.id.cbBlockSender);
final CheckBox cbBlockDomain = view.findViewById(R.id.cbBlockDomain);
final Button btnEditRules = view.findViewById(R.id.btnEditRules);
final CheckBox cbJunkFilter = view.findViewById(R.id.cbJunkFilter);
final ImageButton ibInfoFilter = view.findViewById(R.id.ibInfoFilter);
final Group grpInJunk = view.findViewById(R.id.grpInJunk);
tvMessage.setText(getString(R.string.title_ask_spam_who, from));
ibInfo.setOnClickListener(new View.OnClickListener() {
ibInfoProvider.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.viewFAQ(v.getContext(), 92);
@ -6424,7 +6426,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentDialogJunk.this, getArguments(), "junk");
}.execute(FragmentDialogJunk.this, args, "junk:rules");
} else {
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(getContext());
lbm.sendBroadcast(
@ -6438,8 +6440,81 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
}
});
cbJunkFilter.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
args.putBoolean("filter", isChecked);
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) throws Throwable {
long account = args.getLong("account");
boolean filter = args.getBoolean("filter");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
DB db = DB.getInstance(context);
EntityFolder junk = db.folder().getFolderByType(account, EntityFolder.JUNK);
if (junk != null) {
db.folder().setFolderAutoClassify(junk.id, filter);
prefs.edit().putBoolean("classification", true).apply();
}
return null;
}
@Override
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentDialogJunk.this, args, "junk:filter");
}
});
ibInfoFilter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Helper.viewFAQ(v.getContext(), 163);
}
});
grpInJunk.setVisibility(inJunk ? View.GONE : View.VISIBLE);
new SimpleTask<Boolean>() {
@Override
protected void onPreExecute(Bundle args) {
cbJunkFilter.setEnabled(false);
}
@Override
protected Boolean onExecute(Context context, Bundle args) throws Throwable {
long account = args.getLong("account");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean classification = prefs.getBoolean("classification", false);
DB db = DB.getInstance(context);
EntityFolder junk = db.folder().getFolderByType(account, EntityFolder.JUNK);
if (junk == null)
return false;
return classification && junk.auto_classify;
}
@Override
protected void onExecuted(Bundle args, Boolean filter) {
if (filter != null) {
cbJunkFilter.setChecked(filter);
cbJunkFilter.setEnabled(true);
}
}
@Override
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentDialogJunk.this, args, "junk:filter");
return new AlertDialog.Builder(getContext())
.setView(view)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

View File

@ -344,6 +344,9 @@ public interface DaoFolder {
@Query("UPDATE folder SET poll_count = :count WHERE id = :id AND NOT (poll_count IS :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)")
int setFolderAutoClassify(long id, boolean auto_classify);
@Query("DELETE FROM folder WHERE id = :id")
void deleteFolder(long id);

View File

@ -29,12 +29,12 @@
android:text="@string/title_junk_hint"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="italic"
app:layout_constraintEnd_toStartOf="@+id/ibInfo"
app:layout_constraintEnd_toStartOf="@+id/ibInfoProvider"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvMessage" />
<ImageButton
android:id="@+id/ibInfo"
android:id="@+id/ibInfoProvider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/title_info"
@ -84,10 +84,33 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvBlockHint" />
<CheckBox
android:id="@+id/cbJunkFilter"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_junk_filter"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toStartOf="@+id/ibInfoFilter"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnEditRules" />
<ImageButton
android:id="@+id/ibInfoFilter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/title_info"
android:tooltipText="@string/title_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/cbJunkFilter"
app:srcCompat="@drawable/twotone_info_24" />
<androidx.constraintlayout.widget.Group
android:id="@+id/grpInJunk"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="tvMessage,tvJunkHint,ibInfo" />
app:constraint_referenced_ids="
tvMessage,tvJunkHint,ibInfoProvider,
cbJunkFilter,ibInfoFilter" />
</androidx.constraintlayout.widget.ConstraintLayout>
</eu.faircode.email.ScrollViewEx>

View File

@ -99,6 +99,8 @@
Creating and using rules is a pro feature.
</string>
<string name="title_junk_filter">Use local spam filter</string>
<string name="title_notification_sending">Sending messages</string>
<string name="title_notification_waiting">Waiting for suitable connection</string>
<string name="title_notification_idle">Idle</string>