Added search options to exclude trash and junk folder

pull/199/head
M66B 4 years ago
parent b52c3171c4
commit bce33a421a

@ -224,12 +224,30 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
" index=" + state.index + " index=" + state.index +
" matches=" + (state.matches == null ? null : state.matches.size())); " matches=" + (state.matches == null ? null : state.matches.size()));
long[] exclude = new long[0];
if (account == null) {
List<Long> folders = new ArrayList<>();
if (!criteria.in_trash) {
List<EntityFolder> trash = db.folder().getFoldersByType(EntityFolder.TRASH);
if (trash != null)
for (EntityFolder folder : trash)
folders.add(folder.id);
}
if (!criteria.in_junk) {
List<EntityFolder> junk = db.folder().getFoldersByType(EntityFolder.JUNK);
if (junk != null)
for (EntityFolder folder : junk)
folders.add(folder.id);
}
exclude = Helper.toLongArray(folders);
}
int found = 0; int found = 0;
if (criteria.fts && criteria.query != null) { if (criteria.fts && criteria.query != null) {
if (state.ids == null) { if (state.ids == null) {
SQLiteDatabase sdb = FtsDbHelper.getInstance(context); SQLiteDatabase sdb = FtsDbHelper.getInstance(context);
state.ids = FtsDbHelper.match(sdb, account, folder, criteria); state.ids = FtsDbHelper.match(sdb, account, folder, exclude, criteria);
EntityLog.log(context, "Boundary FTS " + EntityLog.log(context, "Boundary FTS " +
" account=" + account + " account=" + account +
" folder=" + folder + " folder=" + folder +
@ -258,7 +276,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
if (state.matches == null || if (state.matches == null ||
(state.matches.size() > 0 && state.index >= state.matches.size())) { (state.matches.size() > 0 && state.index >= state.matches.size())) {
state.matches = db.message().matchMessages( state.matches = db.message().matchMessages(
account, folder, account, folder, exclude,
criteria.query == null ? null : "%" + criteria.query + "%", criteria.query == null ? null : "%" + criteria.query + "%",
criteria.in_senders, criteria.in_senders,
criteria.in_recipients, criteria.in_recipients,
@ -692,6 +710,8 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
boolean with_notes; boolean with_notes;
String[] with_types; String[] with_types;
Integer with_size = null; Integer with_size = null;
boolean in_trash = true;
boolean in_junk = true;
Long after = null; Long after = null;
Long before = null; Long before = null;

@ -226,6 +226,9 @@ public interface DaoFolder {
" WHERE account = :account AND type = :type") " WHERE account = :account AND type = :type")
EntityFolder getFolderByType(long account, String type); EntityFolder getFolderByType(long account, String type);
@Query("SELECT * FROM folder WHERE type = :type")
List<EntityFolder> getFoldersByType(String type);
@Query("SELECT folder.* FROM folder" + @Query("SELECT folder.* FROM folder" +
" JOIN account ON account.id = folder.account" + " JOIN account ON account.id = folder.account" +
" WHERE account.synchronize" + " WHERE account.synchronize" +

@ -346,11 +346,12 @@ public interface DaoMessage {
" AND (:size IS NULL OR total > :size)" + " AND (:size IS NULL OR total > :size)" +
" AND (:after IS NULL OR received > :after)" + " AND (:after IS NULL OR received > :after)" +
" AND (:before IS NULL OR received < :before)" + " AND (:before IS NULL OR received < :before)" +
" AND NOT message.folder IN (:exclude)" +
" GROUP BY message.id" + " GROUP BY message.id" +
" ORDER BY matched DESC, received DESC" + " ORDER BY matched DESC, received DESC" +
" LIMIT :limit OFFSET :offset") " LIMIT :limit OFFSET :offset")
List<TupleMatch> matchMessages( List<TupleMatch> matchMessages(
Long account, Long folder, String find, Long account, Long folder, long[] exclude, String find,
boolean senders, boolean recipients, boolean subject, boolean keywords, boolean message, boolean notes, boolean headers, boolean senders, boolean recipients, boolean subject, boolean keywords, boolean message, boolean notes, boolean headers,
boolean unseen, boolean flagged, boolean hidden, boolean encrypted, boolean with_attachments, boolean with_notes, boolean unseen, boolean flagged, boolean hidden, boolean encrypted, boolean with_attachments, boolean with_notes,
int type_count, String[] types, int type_count, String[] types,

@ -78,6 +78,8 @@ public class FragmentDialogSearch extends FragmentDialogBase {
boolean last_search_keywords = prefs.getBoolean("last_search_keywords", false); boolean last_search_keywords = prefs.getBoolean("last_search_keywords", false);
boolean last_search_message = prefs.getBoolean("last_search_message", true); boolean last_search_message = prefs.getBoolean("last_search_message", true);
boolean last_search_notes = prefs.getBoolean("last_search_notes", true); boolean last_search_notes = prefs.getBoolean("last_search_notes", true);
boolean last_search_trash = prefs.getBoolean("last_search_trash", true);
boolean last_search_junk = prefs.getBoolean("last_search_junk", true);
View dview = LayoutInflater.from(context).inflate(R.layout.dialog_search, null); View dview = LayoutInflater.from(context).inflate(R.layout.dialog_search, null);
@ -110,6 +112,8 @@ public class FragmentDialogSearch extends FragmentDialogBase {
final CheckBox cbEncrypted = dview.findViewById(R.id.cbEncrypted); final CheckBox cbEncrypted = dview.findViewById(R.id.cbEncrypted);
final CheckBox cbAttachments = dview.findViewById(R.id.cbAttachments); final CheckBox cbAttachments = dview.findViewById(R.id.cbAttachments);
final Spinner spMessageSize = dview.findViewById(R.id.spMessageSize); final Spinner spMessageSize = dview.findViewById(R.id.spMessageSize);
final CheckBox cbSearchTrash = dview.findViewById(R.id.cbSearchTrash);
final CheckBox cbSearchJunk = dview.findViewById(R.id.cbSearchJunk);
final Button btnBefore = dview.findViewById(R.id.btnBefore); final Button btnBefore = dview.findViewById(R.id.btnBefore);
final Button btnAfter = dview.findViewById(R.id.btnAfter); final Button btnAfter = dview.findViewById(R.id.btnAfter);
final TextView tvBefore = dview.findViewById(R.id.tvBefore); final TextView tvBefore = dview.findViewById(R.id.tvBefore);
@ -214,6 +218,8 @@ public class FragmentDialogSearch extends FragmentDialogBase {
grpMore.setVisibility(View.GONE); grpMore.setVisibility(View.GONE);
cbHeaders.setVisibility(View.GONE); cbHeaders.setVisibility(View.GONE);
cbHtml.setVisibility(View.GONE); cbHtml.setVisibility(View.GONE);
cbSearchTrash.setVisibility(View.GONE);
cbSearchJunk.setVisibility(View.GONE);
} else { } else {
ibMore.setImageLevel(0); ibMore.setImageLevel(0);
grpMore.setVisibility(View.VISIBLE); grpMore.setVisibility(View.VISIBLE);
@ -221,6 +227,10 @@ public class FragmentDialogSearch extends FragmentDialogBase {
cbHeaders.setVisibility(View.VISIBLE); cbHeaders.setVisibility(View.VISIBLE);
cbHtml.setVisibility(View.VISIBLE); cbHtml.setVisibility(View.VISIBLE);
} }
if (account < 0) {
cbSearchTrash.setVisibility(View.VISIBLE);
cbSearchJunk.setVisibility(View.VISIBLE);
}
} }
} }
}; };
@ -308,6 +318,20 @@ public class FragmentDialogSearch extends FragmentDialogBase {
} }
}); });
cbSearchTrash.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
prefs.edit().putBoolean("last_search_trash", isChecked).apply();
}
});
cbSearchJunk.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
prefs.edit().putBoolean("last_search_junk", isChecked).apply();
}
});
btnAfter.setOnClickListener(new View.OnClickListener() { btnAfter.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@ -333,10 +357,14 @@ public class FragmentDialogSearch extends FragmentDialogBase {
cbNotes.setChecked(last_search_notes); cbNotes.setChecked(last_search_notes);
tvAfter.setText(null); tvAfter.setText(null);
tvBefore.setText(null); tvBefore.setText(null);
cbSearchTrash.setChecked(last_search_trash);
cbSearchJunk.setChecked(last_search_junk);
grpMore.setVisibility(View.GONE); grpMore.setVisibility(View.GONE);
cbHeaders.setVisibility(View.GONE); cbHeaders.setVisibility(View.GONE);
cbHtml.setVisibility(View.GONE); cbHtml.setVisibility(View.GONE);
cbSearchTrash.setVisibility(View.GONE);
cbSearchJunk.setVisibility(View.GONE);
final AlertDialog dialog = new AlertDialog.Builder(context) final AlertDialog dialog = new AlertDialog.Builder(context)
.setView(dview) .setView(dview)
@ -390,6 +418,9 @@ public class FragmentDialogSearch extends FragmentDialogBase {
} }
} }
criteria.in_trash = cbSearchTrash.isChecked();
criteria.in_junk = cbSearchJunk.isChecked();
Object after = tvAfter.getTag(); Object after = tvAfter.getTag();
Object before = tvBefore.getTag(); Object before = tvBefore.getTag();

@ -137,7 +137,7 @@ public class FtsDbHelper extends SQLiteOpenHelper {
static List<Long> match( static List<Long> match(
SQLiteDatabase db, SQLiteDatabase db,
Long account, Long folder, Long account, Long folder, long[] exclude,
BoundaryCallbackMessages.SearchCriteria criteria) { BoundaryCallbackMessages.SearchCriteria criteria) {
List<String> word = new ArrayList<>(); List<String> word = new ArrayList<>();
@ -200,6 +200,15 @@ public class FtsDbHelper extends SQLiteOpenHelper {
select += "account = " + account + " AND "; select += "account = " + account + " AND ";
if (folder != null) if (folder != null)
select += "folder = " + folder + " AND "; select += "folder = " + folder + " AND ";
if (exclude.length > 0) {
select += "NOT folder IN (";
for (int i = 0; i < exclude.length; i++) {
if (i > 0)
select += ", ";
select += exclude[i];
}
select += ") AND ";
}
if (criteria.after != null) if (criteria.after != null)
select += "time > " + criteria.after + " AND "; select += "time > " + criteria.after + " AND ";
if (criteria.before != null) if (criteria.before != null)

@ -470,6 +470,28 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/spMessageSize" /> app:layout_constraintTop_toBottomOf="@id/spMessageSize" />
<CheckBox
android:id="@+id/cbSearchTrash"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_search_in_trash"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSizeHint" />
<CheckBox
android:id="@+id/cbSearchJunk"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_search_in_junk"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/cbSearchTrash" />
<Button <Button
android:id="@+id/btnAfter" android:id="@+id/btnAfter"
style="?android:attr/buttonStyleSmall" style="?android:attr/buttonStyleSmall"
@ -480,7 +502,7 @@
android:text="@string/title_search_with_after" android:text="@string/title_search_with_after"
app:layout_constraintEnd_toStartOf="@id/btnBefore" app:layout_constraintEnd_toStartOf="@id/btnBefore"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSizeHint" /> app:layout_constraintTop_toBottomOf="@id/cbSearchJunk" />
<Button <Button
android:id="@+id/btnBefore" android:id="@+id/btnBefore"
@ -492,7 +514,7 @@
android:text="@string/title_search_with_before" android:text="@string/title_search_with_before"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/btnAfter" app:layout_constraintStart_toEndOf="@id/btnAfter"
app:layout_constraintTop_toBottomOf="@id/tvSizeHint" /> app:layout_constraintTop_toBottomOf="@id/cbSearchJunk" />
<eu.faircode.email.FixedTextView <eu.faircode.email.FixedTextView
android:id="@+id/tvAfter" android:id="@+id/tvAfter"

@ -1212,6 +1212,8 @@
<string name="title_search_with_encrypted">Encrypted (on device only)</string> <string name="title_search_with_encrypted">Encrypted (on device only)</string>
<string name="title_search_with_attachments">With attachments (on device only)</string> <string name="title_search_with_attachments">With attachments (on device only)</string>
<string name="title_search_with_size">Message size larger than</string> <string name="title_search_with_size">Message size larger than</string>
<string name="title_search_in_trash">In trash</string>
<string name="title_search_in_junk">In spam</string>
<string name="title_search_with_before">Before</string> <string name="title_search_with_before">Before</string>
<string name="title_search_with_after">After</string> <string name="title_search_with_after">After</string>
<string name="title_search_flag_unseen">unread</string> <string name="title_search_flag_unseen">unread</string>

Loading…
Cancel
Save