Search improvements

This commit is contained in:
M66B 2018-10-20 17:56:09 +00:00
parent e0393c9739
commit 24991d621b
8 changed files with 1081 additions and 51 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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();

View File

@ -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();
}

View File

@ -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);

View File

@ -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"}),

View File

@ -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() {

View File

@ -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 +

View File

@ -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();
}
}
}