Migrate search settings

This commit is contained in:
MM20
2022-01-10 21:48:29 +01:00
parent d91fc525f8
commit 5834e7e8c4
22 changed files with 964 additions and 371 deletions
@@ -1,14 +1,17 @@
package de.mm20.launcher2.contacts
import android.content.Context
import android.provider.ContactsContract
import de.mm20.launcher2.hiddenitems.HiddenItemsRepository
import de.mm20.launcher2.permissions.PermissionGroup
import de.mm20.launcher2.permissions.PermissionsManager
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.search.data.Contact
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
interface ContactRepository {
fun search(query: String): Flow<List<Contact>>
@@ -17,19 +20,61 @@ interface ContactRepository {
class ContactRepositoryImpl(
private val context: Context,
hiddenItemsRepository: HiddenItemsRepository
) : ContactRepository {
) : ContactRepository, KoinComponent {
private val permissionsManager: PermissionsManager by inject()
private val dataStore: LauncherDataStore by inject()
private val hiddenItems = hiddenItemsRepository.hiddenItemsKeys
override fun search(query: String): Flow<List<Contact>> = channelFlow {
val contacts = withContext(Dispatchers.IO) {
Contact.search(context, query)
val searchContacts = dataStore.data.map { it.contactsSearch.enabled }
val hasPermission = permissionsManager.hasPermission(PermissionGroup.Contacts)
if (query.length < 3) {
send(emptyList())
return@channelFlow
}
hiddenItems.collectLatest { hiddenItems ->
val contactResults = withContext(Dispatchers.IO) {
contacts.filter { !hiddenItems.contains(it.key) }
combine(searchContacts, hasPermission) { search, permission ->
search && permission
}.map {
if (it) {
queryContacts(query)
} else {
emptyList()
}
send(contactResults)
}.flatMapLatest { contacts ->
hiddenItems.map { hidden ->
contacts.filter { !hidden.contains(it.key) }
}
}.collectLatest {
send(it)
}
}
private suspend fun queryContacts(query: String): List<Contact> {
val results = withContext(Dispatchers.IO) {
val proj = arrayOf(
ContactsContract.RawContacts.CONTACT_ID,
ContactsContract.RawContacts._ID
)
val sel = "${ContactsContract.RawContacts.DISPLAY_NAME_PRIMARY} LIKE ?"
val selArgs = arrayOf("%$query%")
val cursor = context.contentResolver.query(
ContactsContract.RawContacts.CONTENT_URI, proj, sel, selArgs, null
) ?: return@withContext mutableListOf()
//Maps raw contact ids to contact ids
val contactMap = mutableMapOf<Long, MutableSet<Long>>()
while (cursor.moveToNext()) {
contactMap.getOrPut(cursor.getLong(0)) { mutableSetOf() }.add(cursor.getLong(1))
}
cursor.close()
val results = mutableListOf<Contact>()
for ((id, rawIds) in contactMap) {
Contact.contactById(context, id, rawIds)?.let { results.add(it) }
}
results.sortedBy { it }
}
return results
}
}
@@ -74,38 +74,7 @@ class Contact(
return null
}
companion object: KoinComponent {
fun search(context: Context, query: String): List<Contact> {
if (query.length < 3) return mutableListOf()
if (!LauncherPreferences.instance.searchContacts) {
return mutableListOf()
}
val permissionsManager: PermissionsManager = get()
if (!permissionsManager.checkPermissionOnce(PermissionGroup.Contacts)) {
return mutableListOf()
}
val proj = arrayOf(
ContactsContract.RawContacts.CONTACT_ID,
ContactsContract.RawContacts._ID
)
val sel = "${ContactsContract.RawContacts.DISPLAY_NAME_PRIMARY} LIKE ?"
val selArgs = arrayOf("%$query%")
val cursor = context.contentResolver.query(
ContactsContract.RawContacts.CONTENT_URI, proj, sel, selArgs, null
) ?: return mutableListOf()
//Maps raw contact ids to contact ids
val contactMap = mutableMapOf<Long, MutableSet<Long>>()
while (cursor.moveToNext()) {
contactMap.getOrPut(cursor.getLong(0)) { mutableSetOf() }.add(cursor.getLong(1))
}
cursor.close()
val results = mutableListOf<Contact>()
for ((id, rawIds) in contactMap) {
contactById(context, id, rawIds)?.let { results.add(it) }
}
return results.sortedBy { it }
}
companion object {
internal fun contactById(context: Context, id: Long, rawIds: Set<Long>): Contact? {
val s = "(" + rawIds.joinToString(separator = " OR ",
transform = { "${ContactsContract.Data.RAW_CONTACT_ID} = $it" }) + ")" +