mirror of
https://github.com/M66B/FairEmail.git
synced 2026-01-06 04:45:50 +01:00
Improved search performance
This commit is contained in:
@@ -263,7 +263,8 @@ public class AdapterRule extends RecyclerView.Adapter<AdapterRule.ViewHolder> {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
int applied = 0;
|
int applied = 0;
|
||||||
List<Long> ids = db.message().getMessageIdsByFolder(rule.folder);
|
List<Long> ids =
|
||||||
|
db.message().getMessageIdsByFolder(rule.folder, null, null, null);
|
||||||
for (long mid : ids)
|
for (long mid : ids)
|
||||||
try {
|
try {
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import com.sun.mail.imap.IMAPMessage;
|
|||||||
import com.sun.mail.imap.protocol.IMAPProtocol;
|
import com.sun.mail.imap.protocol.IMAPProtocol;
|
||||||
import com.sun.mail.imap.protocol.IMAPResponse;
|
import com.sun.mail.imap.protocol.IMAPResponse;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.Normalizer;
|
import java.text.Normalizer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -46,7 +47,6 @@ import java.util.Locale;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import javax.mail.Address;
|
|
||||||
import javax.mail.FetchProfile;
|
import javax.mail.FetchProfile;
|
||||||
import javax.mail.Flags;
|
import javax.mail.Flags;
|
||||||
import javax.mail.Folder;
|
import javax.mail.Folder;
|
||||||
@@ -55,7 +55,6 @@ import javax.mail.Message;
|
|||||||
import javax.mail.MessageRemovedException;
|
import javax.mail.MessageRemovedException;
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
import javax.mail.UIDFolder;
|
import javax.mail.UIDFolder;
|
||||||
import javax.mail.internet.InternetAddress;
|
|
||||||
import javax.mail.internet.MimeMessage;
|
import javax.mail.internet.MimeMessage;
|
||||||
import javax.mail.search.AndTerm;
|
import javax.mail.search.AndTerm;
|
||||||
import javax.mail.search.BodyTerm;
|
import javax.mail.search.BodyTerm;
|
||||||
@@ -165,74 +164,60 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
|
|||||||
private int load_device(State state) {
|
private int load_device(State state) {
|
||||||
DB db = DB.getInstance(context);
|
DB db = DB.getInstance(context);
|
||||||
|
|
||||||
|
Boolean seen = null;
|
||||||
|
Boolean flagged = null;
|
||||||
|
Boolean snoozed = null;
|
||||||
|
|
||||||
|
String find = (TextUtils.isEmpty(query) ? null : query.toLowerCase(Locale.ROOT));
|
||||||
|
if (find != null && find.startsWith(context.getString(R.string.title_search_special_prefix) + ":")) {
|
||||||
|
String special = find.split(":")[1];
|
||||||
|
if (context.getString(R.string.title_search_special_unseen).equals(special))
|
||||||
|
seen = false;
|
||||||
|
else if (context.getString(R.string.title_search_special_flagged).equals(special))
|
||||||
|
flagged = true;
|
||||||
|
else if (context.getString(R.string.title_search_special_snoozed).equals(special))
|
||||||
|
snoozed = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (state.messages == null) {
|
if (state.messages == null) {
|
||||||
state.messages = db.message().getMessageIdsByFolder(folder);
|
state.messages = db.message().getMessageIdsByFolder(folder, seen, flagged, snoozed);
|
||||||
Log.i("Boundary device folder=" + folder + " query=" + query + " messages=" + state.messages.size());
|
Log.i("Boundary device folder=" + folder +
|
||||||
|
" query=" + query +
|
||||||
|
" seen=" + seen +
|
||||||
|
" flagged=" + flagged +
|
||||||
|
" snoozed=" + snoozed +
|
||||||
|
" messages=" + state.messages.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
int found = 0;
|
int found = 0;
|
||||||
try {
|
try {
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
|
|
||||||
String find = (TextUtils.isEmpty(query) ? null : query.toLowerCase(Locale.ROOT));
|
|
||||||
for (int i = state.index; i < state.messages.size() && found < pageSize && !state.destroyed; i++) {
|
for (int i = state.index; i < state.messages.size() && found < pageSize && !state.destroyed; i++) {
|
||||||
state.index = i + 1;
|
state.index = i + 1;
|
||||||
|
|
||||||
EntityMessage message = db.message().getMessage(state.messages.get(i));
|
long id = state.messages.get(i);
|
||||||
if (message == null)
|
EntityMessage message = null;
|
||||||
continue;
|
|
||||||
|
|
||||||
boolean match = false;
|
if (find == null || seen != null || flagged != null || snoozed != null)
|
||||||
if (find == null)
|
message = db.message().getMessage(id);
|
||||||
match = true;
|
|
||||||
else {
|
else {
|
||||||
if (find.startsWith(context.getString(R.string.title_search_special_prefix) + ":")) {
|
message = db.message().match(id, find);
|
||||||
String special = find.split(":")[1];
|
if (message == null)
|
||||||
if (context.getString(R.string.title_search_special_unseen).equals(special))
|
try {
|
||||||
match = !message.ui_seen;
|
File file = EntityMessage.getFile(context, id);
|
||||||
else if (context.getString(R.string.title_search_special_flagged).equals(special))
|
if (file.exists()) {
|
||||||
match = message.ui_flagged;
|
String body = Helper.readText(file);
|
||||||
else if (context.getString(R.string.title_search_special_snoozed).equals(special))
|
if (body.toLowerCase(Locale.ROOT).contains(find))
|
||||||
match = (message.ui_snoozed != null);
|
message = db.message().getMessage(id);
|
||||||
} else {
|
|
||||||
List<Address> addresses = new ArrayList<>();
|
|
||||||
if (message.from != null)
|
|
||||||
addresses.addAll(Arrays.asList(message.from));
|
|
||||||
if (message.to != null)
|
|
||||||
addresses.addAll(Arrays.asList(message.to));
|
|
||||||
if (message.cc != null)
|
|
||||||
addresses.addAll(Arrays.asList(message.cc));
|
|
||||||
|
|
||||||
for (Address address : addresses) {
|
|
||||||
String email = ((InternetAddress) address).getAddress();
|
|
||||||
String name = ((InternetAddress) address).getPersonal();
|
|
||||||
if (email != null && email.toLowerCase(Locale.ROOT).contains(find) ||
|
|
||||||
name != null && name.toLowerCase(Locale.ROOT).contains(find))
|
|
||||||
match = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!match && message.subject != null)
|
|
||||||
match = message.subject.toLowerCase(Locale.ROOT).contains(find);
|
|
||||||
|
|
||||||
if (!match && message.keywords != null && message.keywords.length > 0)
|
|
||||||
for (String keyword : message.keywords)
|
|
||||||
if (keyword.toLowerCase(Locale.ROOT).contains(find)) {
|
|
||||||
match = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!match && message.content) {
|
|
||||||
try {
|
|
||||||
String body = Helper.readText(message.getFile(context));
|
|
||||||
match = body.toLowerCase(Locale.ROOT).contains(find);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
Log.e(ex);
|
|
||||||
}
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Log.e(ex);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match) {
|
if (message != null) {
|
||||||
found++;
|
found++;
|
||||||
db.message().setMessageFound(message.account, message.thread);
|
db.message().setMessageFound(message.account, message.thread);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,8 +215,14 @@ public interface DaoMessage {
|
|||||||
" FROM message" +
|
" FROM message" +
|
||||||
" WHERE (:folder IS NULL OR folder = :folder)" +
|
" WHERE (:folder IS NULL OR folder = :folder)" +
|
||||||
" AND NOT ui_hide" +
|
" AND NOT ui_hide" +
|
||||||
|
" AND (:seen IS NULL OR message.ui_seen = :seen)" +
|
||||||
|
" AND (:flagged IS NULL OR message.ui_flagged = :flagged)" +
|
||||||
|
" AND CASE :snoozed" +
|
||||||
|
" WHEN 0 THEN message.ui_snoozed IS NULL" +
|
||||||
|
" WHEN 1 THEN message.ui_snoozed IS NOT NULL" +
|
||||||
|
" ELSE 1 END" + // NULL: true
|
||||||
" ORDER BY message.received DESC")
|
" ORDER BY message.received DESC")
|
||||||
List<Long> getMessageIdsByFolder(Long folder);
|
List<Long> getMessageIdsByFolder(Long folder, Boolean seen, Boolean flagged, Boolean snoozed);
|
||||||
|
|
||||||
@Query("SELECT id" +
|
@Query("SELECT id" +
|
||||||
" FROM message" +
|
" FROM message" +
|
||||||
@@ -363,6 +369,16 @@ public interface DaoMessage {
|
|||||||
" WHERE folder = :folder")
|
" WHERE folder = :folder")
|
||||||
Long getMessageOldest(long folder);
|
Long getMessageOldest(long folder);
|
||||||
|
|
||||||
|
@Query("SELECT * FROM message" +
|
||||||
|
" WHERE id = :id" +
|
||||||
|
" AND (`from` LIKE :find COLLATE NOCASE" +
|
||||||
|
" OR `to` LIKE :find COLLATE NOCASE" +
|
||||||
|
" OR `cc` LIKE :find COLLATE NOCASE" +
|
||||||
|
" OR `subject` LIKE :find COLLATE NOCASE" +
|
||||||
|
" OR `keywords` LIKE :find COLLATE NOCASE" +
|
||||||
|
" OR `preview` LIKE :find COLLATE NOCASE)")
|
||||||
|
EntityMessage match(long id, String find);
|
||||||
|
|
||||||
@Insert
|
@Insert
|
||||||
long insertMessage(EntityMessage message);
|
long insertMessage(EntityMessage message);
|
||||||
|
|
||||||
|
|||||||
@@ -1076,7 +1076,8 @@ public class FragmentRule extends FragmentBase {
|
|||||||
int applied = 0;
|
int applied = 0;
|
||||||
|
|
||||||
DB db = DB.getInstance(context);
|
DB db = DB.getInstance(context);
|
||||||
List<Long> ids = db.message().getMessageIdsByFolder(rule.folder);
|
List<Long> ids =
|
||||||
|
db.message().getMessageIdsByFolder(rule.folder, null, null, null);
|
||||||
for (long mid : ids)
|
for (long mid : ids)
|
||||||
try {
|
try {
|
||||||
db.beginTransaction();
|
db.beginTransaction();
|
||||||
@@ -1121,7 +1122,8 @@ public class FragmentRule extends FragmentBase {
|
|||||||
List<EntityMessage> matching = new ArrayList<>();
|
List<EntityMessage> matching = new ArrayList<>();
|
||||||
|
|
||||||
DB db = DB.getInstance(context);
|
DB db = DB.getInstance(context);
|
||||||
List<Long> ids = db.message().getMessageIdsByFolder(rule.folder);
|
List<Long> ids =
|
||||||
|
db.message().getMessageIdsByFolder(rule.folder, null, null, null);
|
||||||
for (long id : ids) {
|
for (long id : ids) {
|
||||||
EntityMessage message = db.message().getMessage(id);
|
EntityMessage message = db.message().getMessage(id);
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ public class ViewModelMessages extends ViewModel {
|
|||||||
|
|
||||||
private static final int LOCAL_PAGE_SIZE = 100;
|
private static final int LOCAL_PAGE_SIZE = 100;
|
||||||
private static final int REMOTE_PAGE_SIZE = 10;
|
private static final int REMOTE_PAGE_SIZE = 10;
|
||||||
|
private static final int SEARCH_PAGE_SIZE = 1;
|
||||||
private static final int LOW_MEM_MB = 32;
|
private static final int LOW_MEM_MB = 32;
|
||||||
|
|
||||||
Model getModel(
|
Model getModel(
|
||||||
@@ -77,10 +78,13 @@ public class ViewModelMessages extends ViewModel {
|
|||||||
DB db = DB.getInstance(context);
|
DB db = DB.getInstance(context);
|
||||||
|
|
||||||
BoundaryCallbackMessages boundary = null;
|
BoundaryCallbackMessages boundary = null;
|
||||||
if (viewType == AdapterMessage.ViewType.FOLDER || viewType == AdapterMessage.ViewType.SEARCH)
|
if (viewType == AdapterMessage.ViewType.FOLDER)
|
||||||
boundary = new BoundaryCallbackMessages(context,
|
boundary = new BoundaryCallbackMessages(context,
|
||||||
args.folder, args.server || viewType == AdapterMessage.ViewType.FOLDER,
|
args.folder, true, args.query, REMOTE_PAGE_SIZE);
|
||||||
args.query, REMOTE_PAGE_SIZE);
|
else if (viewType == AdapterMessage.ViewType.SEARCH)
|
||||||
|
boundary = new BoundaryCallbackMessages(context,
|
||||||
|
args.folder, args.server, args.query,
|
||||||
|
args.server ? REMOTE_PAGE_SIZE : SEARCH_PAGE_SIZE);
|
||||||
|
|
||||||
LivePagedListBuilder<Integer, TupleMessageEx> builder = null;
|
LivePagedListBuilder<Integer, TupleMessageEx> builder = null;
|
||||||
switch (viewType) {
|
switch (viewType) {
|
||||||
|
|||||||
Reference in New Issue
Block a user