aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Schneppe <christian@pix-art.de>2018-04-30 23:51:01 +0200
committerChristian Schneppe <christian@pix-art.de>2018-04-30 23:51:01 +0200
commitbae77ff8fe587e981caa44ba27f5371b7a6664f6 (patch)
treee96fda7b564e18bc28bf04a5b4debf4c17e01113
parentce2ba629bd91897f74e2d1dee38f90671b0f28f8 (diff)
properly cancel pending searchs and scroll to bottom after refresh
-rw-r--r--src/main/java/de/pixart/messenger/Config.java1
-rw-r--r--src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java2
-rw-r--r--src/main/java/de/pixart/messenger/services/MessageSearchTask.java43
-rw-r--r--src/main/java/de/pixart/messenger/ui/ConversationFragment.java16
-rw-r--r--src/main/java/de/pixart/messenger/ui/SearchActivity.java10
-rw-r--r--src/main/java/de/pixart/messenger/ui/util/ListViewUtils.java52
-rw-r--r--src/main/java/de/pixart/messenger/utils/ReplacingSerialSingleThreadExecutor.java7
-rw-r--r--src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java37
8 files changed, 129 insertions, 39 deletions
diff --git a/src/main/java/de/pixart/messenger/Config.java b/src/main/java/de/pixart/messenger/Config.java
index 4e1c86372..3e946c397 100644
--- a/src/main/java/de/pixart/messenger/Config.java
+++ b/src/main/java/de/pixart/messenger/Config.java
@@ -92,6 +92,7 @@ public final class Config {
public static final int PAGE_SIZE = 50;
public static final int MAX_NUM_PAGES = 3;
+ public static final int MAX_SEARCH_RESULTS = 300;
public static final int REFRESH_UI_INTERVAL = 500;
diff --git a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
index d55f36bdf..b407de339 100644
--- a/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
+++ b/src/main/java/de/pixart/messenger/persistance/DatabaseBackend.java
@@ -719,7 +719,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
public Cursor getMessageSearchCursor(String term) {
SQLiteDatabase db = this.getReadableDatabase();
- String SQL = "SELECT " + Message.TABLENAME + ".*," + Conversation.TABLENAME + '.' + Conversation.CONTACTJID + ',' + Conversation.TABLENAME + '.' + Conversation.ACCOUNT + ',' + Conversation.TABLENAME + '.' + Conversation.MODE + " FROM " + Message.TABLENAME + " join " + Conversation.TABLENAME + " on " + Message.TABLENAME + '.' + Message.CONVERSATION + '=' + Conversation.TABLENAME + '.' + Conversation.UUID + " where " + Message.BODY + " LIKE ? limit 200";
+ String SQL = "SELECT " + Message.TABLENAME + ".*," + Conversation.TABLENAME + '.' + Conversation.CONTACTJID + ',' + Conversation.TABLENAME + '.' + Conversation.ACCOUNT + ',' + Conversation.TABLENAME + '.' + Conversation.MODE + " FROM " + Message.TABLENAME + " join " + Conversation.TABLENAME + " on " + Message.TABLENAME + '.' + Message.CONVERSATION + '=' + Conversation.TABLENAME + '.' + Conversation.UUID + " where " + Message.ENCRYPTION + " NOT IN(" + Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE + ',' + Message.ENCRYPTION_PGP + ',' + Message.ENCRYPTION_DECRYPTION_FAILED + ") AND " + Message.BODY + " LIKE ? ORDER BY " + Message.TIME_SENT + " DESC limit " + Config.MAX_SEARCH_RESULTS;
return db.rawQuery(SQL, new String[]{'%' + term + '%'});
}
diff --git a/src/main/java/de/pixart/messenger/services/MessageSearchTask.java b/src/main/java/de/pixart/messenger/services/MessageSearchTask.java
index 4911eff75..9a5c8b143 100644
--- a/src/main/java/de/pixart/messenger/services/MessageSearchTask.java
+++ b/src/main/java/de/pixart/messenger/services/MessageSearchTask.java
@@ -69,6 +69,10 @@ public class MessageSearchTask implements Runnable, Cancellable {
new MessageSearchTask(xmppConnectionService, term, onSearchResultsAvailable).executeInBackground();
}
+ public static void cancelRunningTasks() {
+ EXECUTOR.cancelRunningTasks();
+ }
+
@Override
public void cancel() {
this.isCancelled = true;
@@ -82,20 +86,31 @@ public class MessageSearchTask implements Runnable, Cancellable {
final HashMap<String, Conversational> conversationCache = new HashMap<>();
final List<Message> result = new ArrayList<>();
cursor = xmppConnectionService.databaseBackend.getMessageSearchCursor(term);
- while (cursor.moveToNext()) {
- final String conversationUuid = cursor.getString(cursor.getColumnIndex(Message.CONVERSATION));
- Conversational conversation;
- if (conversationCache.containsKey(conversationUuid)) {
- conversation = conversationCache.get(conversationUuid);
- } else {
- String accountUuid = cursor.getString(cursor.getColumnIndex(Conversation.ACCOUNT));
- String contactJid = cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID));
- int mode = cursor.getInt(cursor.getColumnIndex(Conversation.MODE));
- conversation = findOrGenerateStub(conversationUuid, accountUuid, contactJid, mode);
- conversationCache.put(conversationUuid, conversation);
- }
- Message message = IndividualMessage.fromCursor(cursor, conversation);
- result.add(message);
+ if (isCancelled) {
+ Log.d(Config.LOGTAG, "canceled search task");
+ return;
+ }
+ if (cursor != null && cursor.getCount() > 0) {
+ cursor.moveToLast();
+ do {
+ if (isCancelled) {
+ Log.d(Config.LOGTAG, "canceled search task");
+ return;
+ }
+ final String conversationUuid = cursor.getString(cursor.getColumnIndex(Message.CONVERSATION));
+ Conversational conversation;
+ if (conversationCache.containsKey(conversationUuid)) {
+ conversation = conversationCache.get(conversationUuid);
+ } else {
+ String accountUuid = cursor.getString(cursor.getColumnIndex(Conversation.ACCOUNT));
+ String contactJid = cursor.getString(cursor.getColumnIndex(Conversation.CONTACTJID));
+ int mode = cursor.getInt(cursor.getColumnIndex(Conversation.MODE));
+ conversation = findOrGenerateStub(conversationUuid, accountUuid, contactJid, mode);
+ conversationCache.put(conversationUuid, conversation);
+ }
+ Message message = IndividualMessage.fromCursor(cursor, conversation);
+ result.add(message);
+ } while (cursor.moveToPrevious());
}
long stopTimestamp = SystemClock.elapsedRealtime();
Log.d(Config.LOGTAG, "found " + result.size() + " messages in " + (stopTimestamp - startTimestamp) + "ms");
diff --git a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
index 4207a1b5e..6d45cf306 100644
--- a/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
+++ b/src/main/java/de/pixart/messenger/ui/ConversationFragment.java
@@ -97,6 +97,7 @@ import de.pixart.messenger.ui.adapter.MessageAdapter;
import de.pixart.messenger.ui.util.ActivityResult;
import de.pixart.messenger.ui.util.AttachmentTool;
import de.pixart.messenger.ui.util.ConversationMenuConfigurator;
+import de.pixart.messenger.ui.util.ListViewUtils;
import de.pixart.messenger.ui.util.PendingItem;
import de.pixart.messenger.ui.util.PresenceSelector;
import de.pixart.messenger.ui.util.ScrollState;
@@ -2253,22 +2254,11 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke
}
private void setSelection(int pos, boolean jumpToBottom) {
- setSelection(this.binding.messagesView, pos, jumpToBottom);
- this.binding.messagesView.post(() -> setSelection(this.binding.messagesView, pos, jumpToBottom));
+ ListViewUtils.setSelection(this.binding.messagesView, pos, jumpToBottom);
+ this.binding.messagesView.post(() -> ListViewUtils.setSelection(this.binding.messagesView, pos, jumpToBottom));
this.binding.messagesView.post(this::fireReadEvent);
}
- private static void setSelection(final ListView listView, int pos, boolean jumpToBottom) {
- if (jumpToBottom) {
- final View lastChild = listView.getChildAt(listView.getChildCount() - 1);
- if (lastChild != null) {
- listView.setSelectionFromTop(pos, -lastChild.getHeight());
- return;
- }
- }
- listView.setSelection(pos);
- }
-
private boolean scrolledToBottom() {
return this.binding != null && scrolledToBottom(this.binding.messagesView);
}
diff --git a/src/main/java/de/pixart/messenger/ui/SearchActivity.java b/src/main/java/de/pixart/messenger/ui/SearchActivity.java
index 2120cac3e..28e4ef5b4 100644
--- a/src/main/java/de/pixart/messenger/ui/SearchActivity.java
+++ b/src/main/java/de/pixart/messenger/ui/SearchActivity.java
@@ -33,6 +33,7 @@ import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
+import android.text.InputType;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuItem;
@@ -44,10 +45,12 @@ import java.util.List;
import de.pixart.messenger.R;
import de.pixart.messenger.databinding.ActivitySearchBinding;
import de.pixart.messenger.entities.Message;
+import de.pixart.messenger.services.MessageSearchTask;
import de.pixart.messenger.ui.adapter.MessageAdapter;
import de.pixart.messenger.ui.interfaces.OnSearchResultsAvailable;
import de.pixart.messenger.ui.util.Color;
import de.pixart.messenger.ui.util.Drawable;
+import de.pixart.messenger.ui.util.ListViewUtils;
import static de.pixart.messenger.ui.util.SoftKeyboardUtils.hideSoftKeyboard;
import static de.pixart.messenger.ui.util.SoftKeyboardUtils.showKeyboard;
@@ -75,6 +78,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
EditText searchField = searchActionMenuItem.getActionView().findViewById(R.id.search_field);
searchField.addTextChangedListener(this);
searchField.setHint(R.string.search_messages);
+ searchField.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE);
showKeyboard(searchField);
return super.onCreateOptionsMenu(menu);
}
@@ -125,6 +129,7 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
if (term.length() > 0) {
xmppConnectionService.search(s.toString().trim(), this);
} else {
+ MessageSearchTask.cancelRunningTasks();
this.messages.clear();
messageListAdapter.notifyDataSetChanged();
changeBackground(false, false);
@@ -133,11 +138,12 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
@Override
public void onSearchResultsAvailable(String term, List<Message> messages) {
- this.messages.clear();
- this.messages.addAll(messages);
runOnUiThread(() -> {
+ this.messages.clear();
+ this.messages.addAll(messages);
messageListAdapter.notifyDataSetChanged();
changeBackground(true, messages.size() > 0);
+ ListViewUtils.scrollToBottom(this.binding.searchResults);
});
}
diff --git a/src/main/java/de/pixart/messenger/ui/util/ListViewUtils.java b/src/main/java/de/pixart/messenger/ui/util/ListViewUtils.java
new file mode 100644
index 000000000..c35ec3724
--- /dev/null
+++ b/src/main/java/de/pixart/messenger/ui/util/ListViewUtils.java
@@ -0,0 +1,52 @@
+/*
+* Copyright (c) 2018, Daniel Gultsch All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without modification,
+* are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice, this
+* list of conditions and the following disclaimer.
+*
+* 2. Redistributions in binary form must reproduce the above copyright notice,
+* this list of conditions and the following disclaimer in the documentation and/or
+* other materials provided with the distribution.
+*
+* 3. Neither the name of the copyright holder nor the names of its contributors
+* may be used to endorse or promote products derived from this software without
+* specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package de.pixart.messenger.ui.util;
+
+import android.view.View;
+import android.widget.ListView;
+
+public class ListViewUtils {
+ public static void scrollToBottom(final ListView listView) {
+ int count = listView.getAdapter().getCount();
+ if (count > 0) {
+ setSelection(listView, count - 1, true);
+ }
+ }
+
+ public static void setSelection(final ListView listView, int pos, boolean jumpToBottom) {
+ if (jumpToBottom) {
+ final View lastChild = listView.getChildAt(listView.getChildCount() - 1);
+ if (lastChild != null) {
+ listView.setSelectionFromTop(pos, -lastChild.getHeight());
+ return;
+ }
+ }
+ listView.setSelection(pos);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/de/pixart/messenger/utils/ReplacingSerialSingleThreadExecutor.java b/src/main/java/de/pixart/messenger/utils/ReplacingSerialSingleThreadExecutor.java
index 7bd33eff4..bf4d6e8c2 100644
--- a/src/main/java/de/pixart/messenger/utils/ReplacingSerialSingleThreadExecutor.java
+++ b/src/main/java/de/pixart/messenger/utils/ReplacingSerialSingleThreadExecutor.java
@@ -18,4 +18,11 @@ public class ReplacingSerialSingleThreadExecutor extends SerialSingleThreadExecu
}
super.execute(r);
}
+
+ public synchronized void cancelRunningTasks() {
+ tasks.clear();
+ if (active != null && active instanceof Cancellable) {
+ ((Cancellable) active).cancel();
+ }
+ }
}
diff --git a/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java b/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java
index 1a1280d5a..500b03c5b 100644
--- a/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java
+++ b/src/main/java/de/pixart/messenger/utils/SerialSingleThreadExecutor.java
@@ -11,10 +11,10 @@ import de.pixart.messenger.Config;
public class SerialSingleThreadExecutor implements Executor {
+ final ArrayDeque<Runnable> tasks = new ArrayDeque<>();
private final Executor executor = Executors.newSingleThreadExecutor();
- final ArrayDeque<Runnable> tasks = new ArrayDeque<>();
- protected Runnable active;
private final String name;
+ protected Runnable active;
public SerialSingleThreadExecutor(String name) {
this(name, false);
@@ -28,13 +28,7 @@ public class SerialSingleThreadExecutor implements Executor {
}
public synchronized void execute(final Runnable r) {
- tasks.offer(() -> {
- try {
- r.run();
- } finally {
- scheduleNext();
- }
- });
+ tasks.offer(new Runner(r));
if (active == null) {
scheduleNext();
}
@@ -49,4 +43,29 @@ public class SerialSingleThreadExecutor implements Executor {
}
}
}
+
+ private class Runner implements Runnable, Cancellable {
+
+ private final Runnable runnable;
+
+ private Runner(Runnable runnable) {
+ this.runnable = runnable;
+ }
+
+ @Override
+ public void cancel() {
+ if (runnable instanceof Cancellable) {
+ ((Cancellable) runnable).cancel();
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ runnable.run();
+ } finally {
+ scheduleNext();
+ }
+ }
+ }
} \ No newline at end of file