mirror of https://github.com/M66B/FairEmail.git
Search improvements
This commit is contained in:
parent
e0393c9739
commit
24991d621b
File diff suppressed because it is too large
Load Diff
|
@ -35,7 +35,8 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
|
|||
private ViewModelBrowse model;
|
||||
private Handler handler;
|
||||
private IBoundaryCallbackMessages intf;
|
||||
private ExecutorService executor = Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory);
|
||||
|
||||
private static ExecutorService executor = Executors.newSingleThreadExecutor(Helper.backgroundThreadFactory);
|
||||
|
||||
interface IBoundaryCallbackMessages {
|
||||
void onLoading();
|
||||
|
|
|
@ -45,7 +45,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase;
|
|||
// https://developer.android.com/topic/libraries/architecture/room.html
|
||||
|
||||
@Database(
|
||||
version = 21,
|
||||
version = 22,
|
||||
entities = {
|
||||
EntityIdentity.class,
|
||||
EntityAccount.class,
|
||||
|
@ -265,6 +265,16 @@ public abstract class DB extends RoomDatabase {
|
|||
db.execSQL("CREATE INDEX `index_message_ui_ignored` ON `message` (`ui_ignored`)");
|
||||
}
|
||||
})
|
||||
.addMigrations(new Migration(21, 22) {
|
||||
@Override
|
||||
public void migrate(SupportSQLiteDatabase db) {
|
||||
Log.i(Helper.TAG, "DB migration from version " + startVersion + " to " + endVersion);
|
||||
db.execSQL("DROP INDEX `index_message_folder_uid`");
|
||||
db.execSQL("CREATE UNIQUE INDEX `index_message_folder_uid_ui_found` ON `message` (`folder`, `uid`, `ui_found`)");
|
||||
db.execSQL("DROP INDEX `index_message_msgid_folder`");
|
||||
db.execSQL("CREATE UNIQUE INDEX `index_message_msgid_folder_ui_found` ON `message` (`msgid`, `folder`, `ui_found`)");
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ public interface DaoMessage {
|
|||
" JOIN folder ON folder.id = message.folder" +
|
||||
" WHERE account.`synchronize`" +
|
||||
" AND (NOT message.ui_hide OR :debug)" +
|
||||
" AND NOT ui_found" +
|
||||
" GROUP BY account.id, CASE WHEN message.thread IS NULL THEN message.id ELSE message.thread END" +
|
||||
" HAVING SUM(unified) > 0" +
|
||||
" ORDER BY CASE" +
|
||||
|
@ -83,7 +84,7 @@ public interface DaoMessage {
|
|||
" JOIN folder f ON f.id = :folder" +
|
||||
" WHERE (message.account = f.account OR folder.type = '" + EntityFolder.OUTBOX + "')" +
|
||||
" AND (NOT message.ui_hide OR :debug)" +
|
||||
" AND (NOT :found OR ui_found = :found)" +
|
||||
" AND ui_found = :found" +
|
||||
" GROUP BY CASE WHEN message.thread IS NULL THEN message.id ELSE message.thread END" +
|
||||
" HAVING SUM(CASE WHEN folder.id = :folder THEN 1 ELSE 0 END) > 0" +
|
||||
" ORDER BY CASE" +
|
||||
|
@ -126,26 +127,30 @@ public interface DaoMessage {
|
|||
@Query("SELECT *" +
|
||||
" FROM message" +
|
||||
" WHERE folder = :folder" +
|
||||
" AND uid = :uid")
|
||||
EntityMessage getMessageByUid(long folder, long uid);
|
||||
" AND uid = :uid" +
|
||||
" AND ui_found = :found")
|
||||
EntityMessage getMessageByUid(long folder, long uid, boolean found);
|
||||
|
||||
@Query("SELECT *" +
|
||||
" FROM message" +
|
||||
" WHERE folder = :folder")
|
||||
" WHERE folder = :folder" +
|
||||
" AND NOT ui_found")
|
||||
List<EntityMessage> getMessageByFolder(long folder);
|
||||
|
||||
@Query("SELECT *" +
|
||||
" FROM message" +
|
||||
" WHERE account = :account" +
|
||||
" AND thread = :thread")
|
||||
" AND thread = :thread" +
|
||||
" AND NOT ui_found")
|
||||
List<EntityMessage> getMessageByThread(long account, String thread);
|
||||
|
||||
@Query("SELECT message.* FROM message" +
|
||||
" JOIN folder ON folder.id = message.folder" +
|
||||
" WHERE message.account = :account" +
|
||||
" AND (message.msgid = :msgid" +
|
||||
" OR message.msgid = :reference)")
|
||||
List<EntityMessage> getMessageByMsgId(long account, String msgid, String reference);
|
||||
" OR message.msgid = :reference)" +
|
||||
" AND ui_found = :found")
|
||||
List<EntityMessage> getMessageByMsgId(long account, String msgid, String reference, boolean found);
|
||||
|
||||
@Query("SELECT message.*" +
|
||||
", account.name AS accountName, account.color AS accountColor" +
|
||||
|
@ -167,6 +172,7 @@ public interface DaoMessage {
|
|||
" AND folder.unified" +
|
||||
" AND NOT message.ui_seen" +
|
||||
" AND NOT message.ui_hide" +
|
||||
" AND NOT message.ui_found" +
|
||||
" AND NOT message.ui_ignored" +
|
||||
" ORDER BY message.received")
|
||||
LiveData<List<EntityMessage>> liveUnseenUnified();
|
||||
|
@ -208,9 +214,6 @@ public interface DaoMessage {
|
|||
@Query("UPDATE message SET error = :error WHERE id = :id")
|
||||
int setMessageError(long id, String error);
|
||||
|
||||
@Query("UPDATE message SET ui_found = :found WHERE id = :id")
|
||||
int setMessageFound(long id, boolean found);
|
||||
|
||||
@Query("UPDATE message SET content = :content WHERE id = :id")
|
||||
int setMessageContent(long id, boolean content);
|
||||
|
||||
|
|
|
@ -58,8 +58,8 @@ import static androidx.room.ForeignKey.CASCADE;
|
|||
@Index(value = {"folder"}),
|
||||
@Index(value = {"identity"}),
|
||||
@Index(value = {"replying"}),
|
||||
@Index(value = {"folder", "uid"}, unique = true),
|
||||
@Index(value = {"msgid", "folder"}, unique = true),
|
||||
@Index(value = {"folder", "uid", "ui_found"}, unique = true),
|
||||
@Index(value = {"msgid", "folder", "ui_found"}, unique = true),
|
||||
@Index(value = {"thread"}),
|
||||
@Index(value = {"received"}),
|
||||
@Index(value = {"ui_seen"}),
|
||||
|
|
|
@ -644,15 +644,30 @@ public class FragmentMessages extends FragmentEx {
|
|||
menuSearch.collapseActionView();
|
||||
|
||||
if (Helper.isPro(getContext())) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("folder", folder);
|
||||
intent.putExtra("search", query);
|
||||
Bundle args = new Bundle();
|
||||
args.putLong("folder", folder);
|
||||
args.putString("search", query);
|
||||
|
||||
FragmentMessages fragment = new FragmentMessages();
|
||||
fragment.setArguments(intent.getExtras());
|
||||
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
|
||||
fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("search");
|
||||
fragmentTransaction.commit();
|
||||
new SimpleTask<Void>() {
|
||||
@Override
|
||||
protected Void onLoad(Context context, Bundle args) throws Throwable {
|
||||
DB.getInstance(context).message().deleteFoundMessages();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoaded(Bundle args, Void data) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("folder", args.getLong("folder", folder));
|
||||
intent.putExtra("search", args.getString("search"));
|
||||
|
||||
FragmentMessages fragment = new FragmentMessages();
|
||||
fragment.setArguments(intent.getExtras());
|
||||
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
|
||||
fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("search");
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
}.load(FragmentMessages.this, args);
|
||||
} else {
|
||||
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
|
||||
fragmentTransaction.replace(R.id.content_frame, new FragmentPro()).addToBackStack("pro");
|
||||
|
@ -741,7 +756,7 @@ public class FragmentMessages extends FragmentEx {
|
|||
private void loadMessages() {
|
||||
final DB db = DB.getInstance(getContext());
|
||||
|
||||
ViewModelBrowse model = ViewModelProviders.of(this).get(ViewModelBrowse.class);
|
||||
ViewModelBrowse model = ViewModelProviders.of(getActivity()).get(ViewModelBrowse.class);
|
||||
model.set(getContext(), folder, search, REMOTE_PAGE_SIZE);
|
||||
|
||||
// Observe folder/messages/search
|
||||
|
@ -760,8 +775,7 @@ public class FragmentMessages extends FragmentEx {
|
|||
break;
|
||||
case FOLDER:
|
||||
if (searchCallback == null)
|
||||
searchCallback = new BoundaryCallbackMessages(
|
||||
this, model,
|
||||
searchCallback = new BoundaryCallbackMessages(this, model,
|
||||
new BoundaryCallbackMessages.IBoundaryCallbackMessages() {
|
||||
@Override
|
||||
public void onLoading() {
|
||||
|
@ -802,8 +816,7 @@ public class FragmentMessages extends FragmentEx {
|
|||
}
|
||||
} else {
|
||||
if (searchCallback == null)
|
||||
searchCallback = new BoundaryCallbackMessages(
|
||||
this, model,
|
||||
searchCallback = new BoundaryCallbackMessages(this, model,
|
||||
new BoundaryCallbackMessages.IBoundaryCallbackMessages() {
|
||||
@Override
|
||||
public void onLoading() {
|
||||
|
|
|
@ -1596,7 +1596,7 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
List<Message> full = new ArrayList<>();
|
||||
for (Message imessage : isub) {
|
||||
long uid = ifolder.getUID(imessage);
|
||||
EntityMessage message = db.message().getMessageByUid(folder.id, uid);
|
||||
EntityMessage message = db.message().getMessageByUid(folder.id, uid, false);
|
||||
if (message == null)
|
||||
full.add(imessage);
|
||||
}
|
||||
|
@ -1695,7 +1695,7 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
DB db = DB.getInstance(context);
|
||||
|
||||
// Find message by uid (fast, no headers required)
|
||||
EntityMessage message = db.message().getMessageByUid(folder.id, uid);
|
||||
EntityMessage message = db.message().getMessageByUid(folder.id, uid, found);
|
||||
|
||||
// Find message by Message-ID (slow, headers required)
|
||||
// - messages in inbox have same id as message sent to self
|
||||
|
@ -1706,7 +1706,7 @@ public class ServiceSynchronize extends LifecycleService {
|
|||
String[] refs = helper.getReferences();
|
||||
String reference = (refs.length == 1 && refs[0].indexOf(BuildConfig.APPLICATION_ID) > 0 ? refs[0] : msgid);
|
||||
Log.i(Helper.TAG, "Searching for " + msgid + " / " + reference);
|
||||
for (EntityMessage dup : db.message().getMessageByMsgId(folder.account, msgid, reference)) {
|
||||
for (EntityMessage dup : db.message().getMessageByMsgId(folder.account, msgid, reference, found)) {
|
||||
EntityFolder dfolder = db.folder().getFolder(dup.folder);
|
||||
boolean outbox = EntityFolder.OUTBOX.equals(dfolder.type);
|
||||
Log.i(Helper.TAG, folder.name + " found as id=" + dup.id + "/" + dup.uid +
|
||||
|
|
|
@ -8,9 +8,7 @@ import com.sun.mail.imap.IMAPMessage;
|
|||
import com.sun.mail.imap.IMAPStore;
|
||||
import com.sun.mail.util.FolderClosedIOException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.mail.FetchProfile;
|
||||
|
@ -38,7 +36,6 @@ public class ViewModelBrowse extends ViewModel {
|
|||
private IMAPStore istore = null;
|
||||
private IMAPFolder ifolder = null;
|
||||
private Message[] imessages = null;
|
||||
private List<Long> existing = new ArrayList<>();
|
||||
private int index;
|
||||
private boolean searching = false;
|
||||
private int loaded = 0;
|
||||
|
@ -48,6 +45,10 @@ public class ViewModelBrowse extends ViewModel {
|
|||
this.fid = folder;
|
||||
this.search = search;
|
||||
this.pageSize = pageSize;
|
||||
|
||||
this.index = -1;
|
||||
this.searching = false;
|
||||
this.loaded = 0;
|
||||
}
|
||||
|
||||
Context getContext() {
|
||||
|
@ -130,15 +131,9 @@ public class ViewModelBrowse extends ViewModel {
|
|||
try {
|
||||
long uid = ifolder.getUID(isub[j]);
|
||||
Log.i(Helper.TAG, "Boundary sync uid=" + uid);
|
||||
EntityMessage message = db.message().getMessageByUid(fid, uid);
|
||||
if (message == null) {
|
||||
ServiceSynchronize.synchronizeMessage(context, folder, ifolder, (IMAPMessage) isub[j], search != null);
|
||||
count++;
|
||||
loaded++;
|
||||
} else if (search != null) {
|
||||
existing.add(message.id);
|
||||
db.message().setMessageFound(message.id, true);
|
||||
}
|
||||
ServiceSynchronize.synchronizeMessage(context, folder, ifolder, (IMAPMessage) isub[j], search != null);
|
||||
count++;
|
||||
loaded++;
|
||||
} catch (MessageRemovedException ex) {
|
||||
Log.w(Helper.TAG, "Boundary " + ex + "\n" + Log.getStackTraceString(ex));
|
||||
} catch (FolderClosedException ex) {
|
||||
|
@ -164,24 +159,16 @@ public class ViewModelBrowse extends ViewModel {
|
|||
}
|
||||
|
||||
void clear() {
|
||||
Log.i(Helper.TAG, "Boundary close");
|
||||
|
||||
DB db = DB.getInstance(context);
|
||||
for (long id : existing)
|
||||
db.message().setMessageFound(id, false);
|
||||
db.message().deleteFoundMessages();
|
||||
|
||||
Log.i(Helper.TAG, "Boundary clear");
|
||||
try {
|
||||
if (istore != null)
|
||||
istore.close();
|
||||
} catch (Throwable ex) {
|
||||
Log.e(Helper.TAG, "Boundary " + ex + "\n" + Log.getStackTraceString(ex));
|
||||
} finally {
|
||||
context = null;
|
||||
istore = null;
|
||||
ifolder = null;
|
||||
imessages = null;
|
||||
existing.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue