mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-23 18:15:22 +00:00
Fixes #1346 - properly this time!
This commit is contained in:
parent
d65705c845
commit
04fb296787
@ -12,6 +12,7 @@ import android.os.Build
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
@ -21,20 +22,25 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.collect
|
import kotlinx.coroutines.flow.collect
|
||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import network.loki.messenger.databinding.ActivityHomeBinding
|
import network.loki.messenger.databinding.ActivityHomeBinding
|
||||||
import network.loki.messenger.databinding.ViewMessageRequestBannerBinding
|
import network.loki.messenger.databinding.ViewMessageRequestBannerBinding
|
||||||
import network.loki.messenger.libsession_util.ConfigBase
|
import network.loki.messenger.libsession_util.ConfigBase
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import org.greenrobot.eventbus.Subscribe
|
import org.greenrobot.eventbus.Subscribe
|
||||||
import org.greenrobot.eventbus.ThreadMode
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
|
|
||||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||||
import org.session.libsession.messaging.jobs.JobQueue
|
import org.session.libsession.messaging.jobs.JobQueue
|
||||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||||
@ -47,6 +53,7 @@ import org.session.libsession.utilities.recipients.Recipient
|
|||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
import org.session.libsignal.utilities.ThreadUtils
|
import org.session.libsignal.utilities.ThreadUtils
|
||||||
import org.session.libsignal.utilities.toHexString
|
import org.session.libsignal.utilities.toHexString
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.ApplicationContext
|
import org.thoughtcrime.securesms.ApplicationContext
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
import org.thoughtcrime.securesms.conversation.start.NewConversationFragment
|
import org.thoughtcrime.securesms.conversation.start.NewConversationFragment
|
||||||
@ -82,8 +89,10 @@ import org.thoughtcrime.securesms.util.disableClipping
|
|||||||
import org.thoughtcrime.securesms.util.push
|
import org.thoughtcrime.securesms.util.push
|
||||||
import org.thoughtcrime.securesms.util.show
|
import org.thoughtcrime.securesms.util.show
|
||||||
import org.thoughtcrime.securesms.util.themeState
|
import org.thoughtcrime.securesms.util.themeState
|
||||||
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
|
@ -2,7 +2,9 @@ package org.thoughtcrime.securesms.home.search
|
|||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.channels.BufferOverflow
|
import kotlinx.coroutines.channels.BufferOverflow
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@ -13,11 +15,14 @@ import kotlinx.coroutines.flow.launchIn
|
|||||||
import kotlinx.coroutines.flow.mapLatest
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.plus
|
import kotlinx.coroutines.plus
|
||||||
import org.session.libsignal.utilities.Log
|
|
||||||
import org.session.libsignal.utilities.SettableFuture
|
import org.session.libsignal.utilities.SettableFuture
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.search.SearchRepository
|
import org.thoughtcrime.securesms.search.SearchRepository
|
||||||
import org.thoughtcrime.securesms.search.model.SearchResult
|
import org.thoughtcrime.securesms.search.model.SearchResult
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
@ -25,8 +30,7 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se
|
|||||||
|
|
||||||
private val executor = viewModelScope + SupervisorJob()
|
private val executor = viewModelScope + SupervisorJob()
|
||||||
|
|
||||||
private val _result: MutableStateFlow<GlobalSearchResult> =
|
private val _result: MutableStateFlow<GlobalSearchResult> = MutableStateFlow(GlobalSearchResult.EMPTY)
|
||||||
MutableStateFlow(GlobalSearchResult.EMPTY)
|
|
||||||
|
|
||||||
val result: StateFlow<GlobalSearchResult> = _result
|
val result: StateFlow<GlobalSearchResult> = _result
|
||||||
|
|
||||||
@ -34,7 +38,6 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se
|
|||||||
|
|
||||||
private var settableFuture = SettableFuture<SearchResult>()
|
private var settableFuture = SettableFuture<SearchResult>()
|
||||||
|
|
||||||
|
|
||||||
fun postQuery(charSequence: CharSequence?) {
|
fun postQuery(charSequence: CharSequence?) {
|
||||||
charSequence ?: return
|
charSequence ?: return
|
||||||
_queryText.value = charSequence
|
_queryText.value = charSequence
|
||||||
@ -45,7 +48,7 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se
|
|||||||
_queryText
|
_queryText
|
||||||
.buffer(onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
.buffer(onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||||
.mapLatest { query ->
|
.mapLatest { query ->
|
||||||
// Minimum search term is 2 characters - for a single char we do nothing
|
// Minimum search term is 2 characters
|
||||||
if (query.trim().length < 2) {
|
if (query.trim().length < 2) {
|
||||||
SearchResult.EMPTY
|
SearchResult.EMPTY
|
||||||
} else {
|
} else {
|
||||||
@ -55,9 +58,7 @@ class GlobalSearchViewModel @Inject constructor(private val searchRepository: Se
|
|||||||
delay(300)
|
delay(300)
|
||||||
|
|
||||||
// If we already have a search running then stop it
|
// If we already have a search running then stop it
|
||||||
if (!settableFuture.isDone) {
|
if (!settableFuture.isDone) { settableFuture.cancel(true) }
|
||||||
Log.w("[ACL]", "Cancelling settable future..")
|
|
||||||
settableFuture.cancel(true); }
|
|
||||||
|
|
||||||
settableFuture = SettableFuture<SearchResult>()
|
settableFuture = SettableFuture<SearchResult>()
|
||||||
searchRepository.query(query.toString(), settableFuture::set)
|
searchRepository.query(query.toString(), settableFuture::set)
|
||||||
|
@ -4,7 +4,6 @@ import android.content.Context;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.DatabaseUtils;
|
import android.database.DatabaseUtils;
|
||||||
import android.database.MergeCursor;
|
import android.database.MergeCursor;
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
@ -36,28 +35,18 @@ import java.util.concurrent.Executor;
|
|||||||
|
|
||||||
import kotlin.Pair;
|
import kotlin.Pair;
|
||||||
|
|
||||||
/**
|
// Class to manage data retrieval for search
|
||||||
* Manages data retrieval for search.
|
|
||||||
*/
|
|
||||||
public class SearchRepository {
|
public class SearchRepository {
|
||||||
|
|
||||||
private static final String TAG = SearchRepository.class.getSimpleName();
|
private static final String TAG = SearchRepository.class.getSimpleName();
|
||||||
|
|
||||||
private static final Set<Character> BANNED_CHARACTERS = new HashSet<>();
|
private static final Set<Character> BANNED_CHARACTERS = new HashSet<>();
|
||||||
static {
|
static {
|
||||||
// Several ranges of invalid ASCII characters
|
// Construct a list containing several ranges of invalid ASCII characters
|
||||||
for (int i = 33; i <= 47; i++) {
|
// See: https://www.ascii-code.com/
|
||||||
BANNED_CHARACTERS.add((char) i);
|
for (int i = 33; i <= 47; i++) { BANNED_CHARACTERS.add((char) i); } // !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /
|
||||||
}
|
for (int i = 58; i <= 64; i++) { BANNED_CHARACTERS.add((char) i); } // :, ;, <, =, >, ?, @
|
||||||
for (int i = 58; i <= 64; i++) {
|
for (int i = 91; i <= 96; i++) { BANNED_CHARACTERS.add((char) i); } // [, \, ], ^, _, `
|
||||||
BANNED_CHARACTERS.add((char) i);
|
for (int i = 123; i <= 126; i++) { BANNED_CHARACTERS.add((char) i); } // {, |, }, ~
|
||||||
}
|
|
||||||
for (int i = 91; i <= 96; i++) {
|
|
||||||
BANNED_CHARACTERS.add((char) i);
|
|
||||||
}
|
|
||||||
for (int i = 123; i <= 126; i++) {
|
|
||||||
BANNED_CHARACTERS.add((char) i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
@ -86,54 +75,25 @@ public class SearchRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void query(@NonNull String query, @NonNull Callback<SearchResult> callback) {
|
public void query(@NonNull String query, @NonNull Callback<SearchResult> callback) {
|
||||||
|
|
||||||
Log.w("[ACL]", "Hit SearchRepository.query - query string is: \"" + query + "\"");
|
|
||||||
|
|
||||||
String cleanQuery = sanitizeQuery(query).trim();
|
|
||||||
Log.w("[ACL]", "When sanitized and trimmed this is: \"" + cleanQuery + "\"");
|
|
||||||
|
|
||||||
// If the sanitized search is empty or is less than 2 chars then abort
|
// If the sanitized search is empty or is less than 2 chars then abort
|
||||||
|
String cleanQuery = sanitizeQuery(query).trim();
|
||||||
if (cleanQuery.isEmpty() || cleanQuery.length() < 2) {
|
if (cleanQuery.isEmpty() || cleanQuery.length() < 2) {
|
||||||
Log.w("[ACL]", "Trimmed query is empty or less than 2 chars so returning empty SearchResult");
|
|
||||||
callback.onResult(SearchResult.EMPTY);
|
callback.onResult(SearchResult.EMPTY);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
executor.execute(() -> {
|
executor.execute(() -> {
|
||||||
Stopwatch timer = new Stopwatch("FtsQuery");
|
Stopwatch timer = new Stopwatch("FtsQuery");
|
||||||
|
|
||||||
// ACL
|
|
||||||
//String cleanQuery = sanitizeQuery(query).trim();
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (cleanQuery.isEmpty())
|
|
||||||
{
|
|
||||||
Log.w("[ACL]", "Aborting empty search query.");
|
|
||||||
Log.d(TAG, "Aborting empty search query.");
|
|
||||||
timer.stop(TAG);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Log.w("[ACL]", "Clean query is non-empty and is: \"" + cleanQuery + "\"");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
timer.split("clean");
|
timer.split("clean");
|
||||||
|
|
||||||
Log.w("[ACL]", "About to query contacts.");
|
|
||||||
Pair<CursorList<Contact>, List<String>> contacts = queryContacts(cleanQuery);
|
Pair<CursorList<Contact>, List<String>> contacts = queryContacts(cleanQuery);
|
||||||
timer.split("contacts");
|
timer.split("Contacts");
|
||||||
|
|
||||||
|
|
||||||
Log.w("[ACL]", "About to query conversations.");
|
|
||||||
CursorList<GroupRecord> conversations = queryConversations(cleanQuery, contacts.getSecond());
|
CursorList<GroupRecord> conversations = queryConversations(cleanQuery, contacts.getSecond());
|
||||||
timer.split("conversations");
|
timer.split("Conversations");
|
||||||
|
|
||||||
Log.w("[ACL]", "About to query messages.");
|
|
||||||
CursorList<MessageResult> messages = queryMessages(cleanQuery);
|
CursorList<MessageResult> messages = queryMessages(cleanQuery);
|
||||||
timer.split("messages");
|
timer.split("Messages");
|
||||||
|
|
||||||
timer.stop(TAG);
|
timer.stop(TAG);
|
||||||
|
|
||||||
@ -182,11 +142,10 @@ public class SearchRepository {
|
|||||||
MergeCursor merged = new MergeCursor(new Cursor[]{addressThreads, individualRecipients});
|
MergeCursor merged = new MergeCursor(new Cursor[]{addressThreads, individualRecipients});
|
||||||
|
|
||||||
return new Pair<>(new CursorList<>(merged, new ContactModelBuilder(contactDatabase, threadDatabase)), contactStrings);
|
return new Pair<>(new CursorList<>(merged, new ContactModelBuilder(contactDatabase, threadDatabase)), contactStrings);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CursorList<GroupRecord> queryConversations(@NonNull String query, List<String> matchingAddresses) {
|
private CursorList<GroupRecord> queryConversations(@NonNull String query, List<String> matchingAddresses) {
|
||||||
List<String> numbers = contactAccessor.getNumbersForThreadSearchFilter(context, query);
|
List<String> numbers = contactAccessor.getNumbersForThreadSearchFilter(context, query);
|
||||||
String localUserNumber = TextSecurePreferences.getLocalNumber(context);
|
String localUserNumber = TextSecurePreferences.getLocalNumber(context);
|
||||||
if (localUserNumber != null) {
|
if (localUserNumber != null) {
|
||||||
matchingAddresses.remove(localUserNumber);
|
matchingAddresses.remove(localUserNumber);
|
||||||
@ -270,9 +229,7 @@ public class SearchRepository {
|
|||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
RecipientModelBuilder(@NonNull Context context) {
|
RecipientModelBuilder(@NonNull Context context) { this.context = context; }
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Recipient build(@NonNull Cursor cursor) {
|
public Recipient build(@NonNull Cursor cursor) {
|
||||||
@ -315,9 +272,7 @@ public class SearchRepository {
|
|||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
MessageModelBuilder(@NonNull Context context) {
|
MessageModelBuilder(@NonNull Context context) { this.context = context; }
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MessageResult build(@NonNull Cursor cursor) {
|
public MessageResult build(@NonNull Cursor cursor) {
|
||||||
|
@ -39,13 +39,9 @@ public class Stopwatch {
|
|||||||
out.append(splits.get(i).time - splits.get(i - 1).time);
|
out.append(splits.get(i).time - splits.get(i - 1).time);
|
||||||
out.append("ms ");
|
out.append("ms ");
|
||||||
}
|
}
|
||||||
|
|
||||||
out.append("total: ").append(splits.get(splits.size() - 1).time - startTime).append("ms.");
|
out.append("total: ").append(splits.get(splits.size() - 1).time - startTime).append("ms.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d(tag, out.toString());
|
Log.d(tag, out.toString());
|
||||||
|
|
||||||
Log.w("[ACL]", out.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Split {
|
private static class Split {
|
||||||
|
Loading…
Reference in New Issue
Block a user