forked from upstream-mirrors/quik
#1010 - Message content search
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
*
|
||||
* This file is part of QKSMS.
|
||||
*
|
||||
* QKSMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QKSMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package filter
|
||||
|
||||
import model.Contact
|
||||
import util.extensions.removeAccents
|
||||
import javax.inject.Inject
|
||||
|
||||
class ContactFilter @Inject constructor(private val phoneNumberFilter: PhoneNumberFilter) : Filter<Contact>() {
|
||||
|
||||
override fun filter(item: Contact, query: CharSequence): Boolean {
|
||||
return item.name.removeAccents().contains(query, true) || // Name
|
||||
item.numbers.map { it.address }.any { address -> phoneNumberFilter.filter(address, query) } // Number
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
*
|
||||
* This file is part of QKSMS.
|
||||
*
|
||||
* QKSMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QKSMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package filter
|
||||
|
||||
import model.Conversation
|
||||
import javax.inject.Inject
|
||||
|
||||
class ConversationFilter @Inject constructor(private val recipientFilter: RecipientFilter) : Filter<Conversation>() {
|
||||
|
||||
override fun filter(item: Conversation, query: CharSequence): Boolean {
|
||||
return item.recipients.any { recipient -> recipientFilter.filter(recipient, query) }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
*
|
||||
* This file is part of QKSMS.
|
||||
*
|
||||
* QKSMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QKSMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package filter
|
||||
|
||||
abstract class Filter<in T> {
|
||||
|
||||
abstract fun filter(item: T, query: CharSequence): Boolean
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
*
|
||||
* This file is part of QKSMS.
|
||||
*
|
||||
* QKSMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QKSMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package filter
|
||||
|
||||
import android.telephony.PhoneNumberUtils
|
||||
import javax.inject.Inject
|
||||
|
||||
class PhoneNumberFilter @Inject constructor() : Filter<String>() {
|
||||
|
||||
override fun filter(item: String, query: CharSequence): Boolean {
|
||||
val allCharactersDialable = query.all { PhoneNumberUtils.isReallyDialable(it) }
|
||||
|
||||
return allCharactersDialable && (PhoneNumberUtils.compare(item, query.toString()) ||
|
||||
PhoneNumberUtils.stripSeparators(item).contains(PhoneNumberUtils.stripSeparators(query.toString())))
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
|
||||
*
|
||||
* This file is part of QKSMS.
|
||||
*
|
||||
* QKSMS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* QKSMS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package filter
|
||||
|
||||
import model.Recipient
|
||||
import javax.inject.Inject
|
||||
|
||||
class RecipientFilter @Inject constructor(
|
||||
private val contactFilter: ContactFilter,
|
||||
private val phoneNumberFilter: PhoneNumberFilter)
|
||||
: Filter<Recipient>() {
|
||||
|
||||
override fun filter(item: Recipient, query: CharSequence) = when {
|
||||
item.contact?.let { contactFilter.filter(it, query) } == true -> true
|
||||
phoneNumberFilter.filter(item.address, query) -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,10 +32,11 @@ import android.telephony.PhoneNumberUtils
|
||||
import android.telephony.SmsManager
|
||||
import com.klinker.android.send_message.BroadcastUtils
|
||||
import com.klinker.android.send_message.StripAccents
|
||||
import io.reactivex.Flowable
|
||||
import filter.ConversationFilter
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.realm.Case
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmResults
|
||||
import io.realm.Sort
|
||||
@@ -46,6 +47,7 @@ import model.Contact
|
||||
import model.Conversation
|
||||
import model.Message
|
||||
import model.MmsPart
|
||||
import model.SearchResult
|
||||
import util.MessageUtils
|
||||
import util.Preferences
|
||||
import util.extensions.anyOf
|
||||
@@ -59,13 +61,13 @@ import javax.inject.Singleton
|
||||
class MessageRepositoryImpl @Inject constructor(
|
||||
private val context: Context,
|
||||
private val messageIds: KeyManager,
|
||||
private val conversationFilter: ConversationFilter,
|
||||
private val cursorToConversation: CursorToConversation,
|
||||
private val cursorToRecipient: CursorToRecipient,
|
||||
private val prefs: Preferences) : MessageRepository {
|
||||
|
||||
override fun getConversations(archived: Boolean): Flowable<List<Conversation>> {
|
||||
val realm = Realm.getDefaultInstance()
|
||||
return realm
|
||||
override fun getConversations(archived: Boolean): RealmResults<Conversation> {
|
||||
return Realm.getDefaultInstance()
|
||||
.where(Conversation::class.java)
|
||||
.notEqualTo("id", 0L)
|
||||
.greaterThan("count", 0)
|
||||
@@ -74,10 +76,6 @@ class MessageRepositoryImpl @Inject constructor(
|
||||
.isNotEmpty("recipients")
|
||||
.sort("date", Sort.DESCENDING)
|
||||
.findAllAsync()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
.filter { it.isValid }
|
||||
.map { conversations -> realm.copyFromRealm(conversations) }
|
||||
}
|
||||
|
||||
override fun getConversationsSnapshot(): List<Conversation> {
|
||||
@@ -92,6 +90,25 @@ class MessageRepositoryImpl @Inject constructor(
|
||||
.findAll())
|
||||
}
|
||||
|
||||
override fun searchConversations(query: String): List<SearchResult> {
|
||||
val conversations = getConversationsSnapshot()
|
||||
|
||||
val messagesByConversation = Realm.getDefaultInstance()
|
||||
.where(Message::class.java)
|
||||
.contains("body", query, Case.INSENSITIVE)
|
||||
.findAll()
|
||||
.groupBy { message -> message.threadId }
|
||||
.filter { (threadId, _) -> conversations.firstOrNull { it.id == threadId } != null }
|
||||
.map { (threadId, messages) -> Pair(conversations.first { it.id == threadId }, messages.size) }
|
||||
.map { (conversation, messages) -> SearchResult(query, conversation, messages) }
|
||||
.sortedByDescending { result -> result.messages }
|
||||
|
||||
return conversations
|
||||
.filter { conversation -> conversationFilter.filter(conversation, query) }
|
||||
.map { conversation -> SearchResult(query, conversation, 0) }
|
||||
.plus(messagesByConversation)
|
||||
}
|
||||
|
||||
override fun getBlockedConversations(): RealmResults<Conversation> {
|
||||
return Realm.getDefaultInstance()
|
||||
.where(Conversation::class.java)
|
||||
@@ -166,10 +183,11 @@ class MessageRepositoryImpl @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMessages(threadId: Long): RealmResults<Message> {
|
||||
override fun getMessages(threadId: Long, query: String): RealmResults<Message> {
|
||||
return Realm.getDefaultInstance()
|
||||
.where(Message::class.java)
|
||||
.equalTo("threadId", threadId)
|
||||
.let { if (query.isEmpty()) it else it.contains("body", query, Case.INSENSITIVE) }
|
||||
.sort("date")
|
||||
.findAllAsync()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user