Redesign contact results
This commit is contained in:
@@ -14,7 +14,10 @@ import de.mm20.launcher2.icons.TextLayer
|
||||
import de.mm20.launcher2.ktx.asBitmap
|
||||
import de.mm20.launcher2.ktx.tryStartActivity
|
||||
import de.mm20.launcher2.search.Contact
|
||||
import de.mm20.launcher2.search.ContactInfo
|
||||
import de.mm20.launcher2.search.ContactApp
|
||||
import de.mm20.launcher2.search.EmailAddress
|
||||
import de.mm20.launcher2.search.PhoneNumber
|
||||
import de.mm20.launcher2.search.PostalAddress
|
||||
import de.mm20.launcher2.search.SearchableSerializer
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -24,7 +27,10 @@ internal data class AndroidContact(
|
||||
override val firstName: String,
|
||||
override val lastName: String,
|
||||
override val displayName: String,
|
||||
override val contactInfos: Iterable<ContactInfo>,
|
||||
override val phoneNumbers: List<PhoneNumber>,
|
||||
override val emailAddresses: List<EmailAddress>,
|
||||
override val postalAddresses: List<PostalAddress>,
|
||||
override val contactApps: List<ContactApp>,
|
||||
internal val lookupKey: String,
|
||||
override val labelOverride: String? = null,
|
||||
) : Contact {
|
||||
@@ -38,7 +44,7 @@ internal data class AndroidContact(
|
||||
|
||||
override val summary: String
|
||||
get() {
|
||||
return contactInfos.distinctBy { it.label }.take(5).joinToString(separator = ", ") { it.label }
|
||||
return (phoneNumbers.map { it.number } + emailAddresses.map { it.address }).joinToString(", ")
|
||||
}
|
||||
|
||||
override fun overrideLabel(label: String): Contact {
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
package de.mm20.launcher2.contacts
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.ContactsContract
|
||||
import de.mm20.launcher2.search.ContactInfo
|
||||
import de.mm20.launcher2.search.ContactInfoType
|
||||
import java.net.URLEncoder
|
||||
|
||||
|
||||
internal data class PhoneContactInfo(
|
||||
val number: String,
|
||||
) : ContactInfo {
|
||||
override val label: String
|
||||
get() = number
|
||||
|
||||
override val type: ContactInfoType = ContactInfoType.Phone
|
||||
|
||||
override val intent: Intent
|
||||
get() = Intent(Intent.ACTION_VIEW)
|
||||
.setData(Uri.parse("tel:$number"))
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
internal data class MailContactInfo(
|
||||
val address: String,
|
||||
) : ContactInfo {
|
||||
override val label: String
|
||||
get() = address
|
||||
|
||||
override val type: ContactInfoType = ContactInfoType.Email
|
||||
|
||||
override val intent: Intent
|
||||
get() = Intent(Intent.ACTION_VIEW)
|
||||
.setData(Uri.parse("mailto:$address"))
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
internal data class PostalContactInfo(
|
||||
val address: String,
|
||||
) : ContactInfo {
|
||||
override val label: String
|
||||
get() = address.replace("\n", ", ")
|
||||
|
||||
override val type: ContactInfoType = ContactInfoType.Postal
|
||||
|
||||
override val intent: Intent
|
||||
get() = Intent(Intent.ACTION_VIEW)
|
||||
.setData(Uri.parse("geo:0,0?q=${URLEncoder.encode(address, "utf8")}"))
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
|
||||
internal data class TelegramContactInfo(
|
||||
override val label: String,
|
||||
val userId: String,
|
||||
) : ContactInfo {
|
||||
|
||||
override val type: ContactInfoType = ContactInfoType.Telegram
|
||||
|
||||
override val intent: Intent
|
||||
get() = Intent(Intent.ACTION_VIEW)
|
||||
.setData(Uri.parse("tg:openmessage?user_id=$userId"))
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
internal companion object {
|
||||
const val ItemType = "vnd.android.cursor.item/vnd.org.telegram.messenger.android.profile"
|
||||
}
|
||||
}
|
||||
|
||||
internal data class SignalContactInfo(
|
||||
override val label: String,
|
||||
val dataId: Long,
|
||||
) : ContactInfo {
|
||||
|
||||
override val type: ContactInfoType = ContactInfoType.Signal
|
||||
|
||||
override val intent: Intent
|
||||
get() = Intent(Intent.ACTION_VIEW)
|
||||
.setData(
|
||||
Uri.withAppendedPath(
|
||||
ContactsContract.Data.CONTENT_URI,
|
||||
dataId.toString()
|
||||
)
|
||||
)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
internal companion object {
|
||||
const val ItemType = "vnd.android.cursor.item/vnd.org.thoughtcrime.securesms.contact"
|
||||
}
|
||||
}
|
||||
|
||||
internal data class WhatsAppContactInfo(
|
||||
override val label: String,
|
||||
val dataId: Long,
|
||||
) : ContactInfo {
|
||||
|
||||
override val type: ContactInfoType = ContactInfoType.Whatsapp
|
||||
|
||||
override val intent: Intent
|
||||
get() = Intent(Intent.ACTION_VIEW)
|
||||
.setData(
|
||||
Uri.withAppendedPath(
|
||||
ContactsContract.Data.CONTENT_URI,
|
||||
dataId.toString()
|
||||
)
|
||||
)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
|
||||
internal companion object {
|
||||
const val ItemType = "vnd.android.cursor.item/vnd.com.whatsapp.profile"
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,19 @@
|
||||
package de.mm20.launcher2.contacts
|
||||
|
||||
import android.content.ContentUris
|
||||
import android.content.Context
|
||||
import android.provider.ContactsContract
|
||||
import androidx.core.database.getLongOrNull
|
||||
import androidx.core.database.getStringOrNull
|
||||
import de.mm20.launcher2.permissions.PermissionGroup
|
||||
import de.mm20.launcher2.permissions.PermissionsManager
|
||||
import de.mm20.launcher2.preferences.search.ContactSearchSettings
|
||||
import de.mm20.launcher2.search.Contact
|
||||
import de.mm20.launcher2.search.ContactInfo
|
||||
import de.mm20.launcher2.search.ContactApp
|
||||
import de.mm20.launcher2.search.ContactInfoType
|
||||
import de.mm20.launcher2.search.EmailAddress
|
||||
import de.mm20.launcher2.search.PhoneNumber
|
||||
import de.mm20.launcher2.search.PostalAddress
|
||||
import de.mm20.launcher2.search.SearchableRepository
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
@@ -51,25 +57,22 @@ internal class ContactRepository(
|
||||
|
||||
private suspend fun getWithRawIds(id: Long, rawIds: Set<Long>): Contact? =
|
||||
withContext(Dispatchers.IO) {
|
||||
val s = "(" + rawIds.joinToString(separator = " OR ",
|
||||
transform = { "${ContactsContract.Data.RAW_CONTACT_ID} = $it" }) + ")" +
|
||||
" AND (${ContactsContract.Data.MIMETYPE} = \"${ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE}\"" +
|
||||
" OR ${ContactsContract.Data.MIMETYPE} = \"${ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE}\"" +
|
||||
" OR ${ContactsContract.Data.MIMETYPE} = \"${ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE}\"" +
|
||||
" OR ${ContactsContract.Data.MIMETYPE} = \"${ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE}\"" +
|
||||
" OR ${ContactsContract.Data.MIMETYPE} = \"${TelegramContactInfo.ItemType}\"" +
|
||||
" OR ${ContactsContract.Data.MIMETYPE} = \"${WhatsAppContactInfo.ItemType}\"" +
|
||||
" OR ${ContactsContract.Data.MIMETYPE} = \"${SignalContactInfo.ItemType}\"" +
|
||||
")"
|
||||
val s = "${ContactsContract.Data.RAW_CONTACT_ID} IN (${rawIds.joinToString(", ")})"
|
||||
val dataCursor = context.contentResolver.query(
|
||||
ContactsContract.Data.CONTENT_URI,
|
||||
null, s, null, null
|
||||
) ?: return@withContext null
|
||||
val contactInfos = mutableSetOf<ContactInfo>()
|
||||
var firstName = ""
|
||||
var lastName = ""
|
||||
var displayName = ""
|
||||
val phoneNumbers = mutableListOf<PhoneNumber>()
|
||||
val emailAddresses = mutableListOf<EmailAddress>()
|
||||
val postalAddresses = mutableListOf<PostalAddress>()
|
||||
val contactApps = mutableListOf<ContactApp>()
|
||||
|
||||
val mimeTypeColumn = dataCursor.getColumnIndex(ContactsContract.Data.MIMETYPE)
|
||||
val typeColumn =
|
||||
dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.Contactables.TYPE)
|
||||
val emailAddressColumn =
|
||||
dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS)
|
||||
val numberColumn =
|
||||
@@ -82,25 +85,49 @@ internal class ContactRepository(
|
||||
dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME)
|
||||
val familyNameColumn =
|
||||
dataCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME)
|
||||
val data1Column = dataCursor.getColumnIndex(ContactsContract.Data.DATA1)
|
||||
val accountTypeColumn = dataCursor.getColumnIndex(ContactsContract.Data.ACCOUNT_TYPE_AND_DATA_SET)
|
||||
|
||||
val data3Column = dataCursor.getColumnIndex(ContactsContract.Data.DATA3)
|
||||
val idColumn = dataCursor.getColumnIndex(ContactsContract.Data._ID)
|
||||
loop@ while (dataCursor.moveToNext()) {
|
||||
when (dataCursor.getStringOrNull(mimeTypeColumn)) {
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE ->
|
||||
dataCursor.getStringOrNull(emailAddressColumn)?.let {
|
||||
contactInfos.add(MailContactInfo(it))
|
||||
emailAddresses += EmailAddress(
|
||||
it,
|
||||
when (dataCursor.getInt(typeColumn)) {
|
||||
ContactsContract.CommonDataKinds.Email.TYPE_HOME -> ContactInfoType.Home
|
||||
ContactsContract.CommonDataKinds.Email.TYPE_WORK -> ContactInfoType.Work
|
||||
ContactsContract.CommonDataKinds.Email.TYPE_MOBILE -> ContactInfoType.Mobile
|
||||
else -> ContactInfoType.Other
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ->
|
||||
dataCursor.getStringOrNull(numberColumn)?.let {
|
||||
val phone = it.replace(Regex("[^+0-9]"), "")
|
||||
contactInfos.add(PhoneContactInfo(phone))
|
||||
phoneNumbers += PhoneNumber(
|
||||
phone,
|
||||
when (dataCursor.getInt(typeColumn)) {
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_HOME -> ContactInfoType.Home
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_WORK -> ContactInfoType.Work
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE -> ContactInfoType.Mobile
|
||||
else -> ContactInfoType.Other
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE ->
|
||||
dataCursor.getStringOrNull(addressColumn)?.let {
|
||||
contactInfos.add(PostalContactInfo(it))
|
||||
postalAddresses += PostalAddress(
|
||||
it,
|
||||
when (dataCursor.getInt(typeColumn)) {
|
||||
ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME -> ContactInfoType.Home
|
||||
ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK -> ContactInfoType.Work
|
||||
else -> ContactInfoType.Other
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE -> {
|
||||
@@ -109,34 +136,18 @@ internal class ContactRepository(
|
||||
displayName = dataCursor.getStringOrNull(displayNameColumn) ?: ""
|
||||
}
|
||||
|
||||
TelegramContactInfo.ItemType -> {
|
||||
val data1 = dataCursor.getStringOrNull(data1Column)
|
||||
?: continue@loop
|
||||
val data3 = dataCursor.getStringOrNull(data3Column)
|
||||
?: continue@loop
|
||||
contactInfos.add(
|
||||
TelegramContactInfo(data3.substringAfterLast(" "), data1)
|
||||
else -> {
|
||||
val mimeType = dataCursor.getStringOrNull(mimeTypeColumn) ?: continue
|
||||
contactApps += ContactApp(
|
||||
label = dataCursor.getStringOrNull(data3Column) ?: continue,
|
||||
packageName = dataCursor.getStringOrNull(accountTypeColumn) ?: continue,
|
||||
mimeType = mimeType,
|
||||
uri = ContentUris.withAppendedId(
|
||||
ContactsContract.Data.CONTENT_URI,
|
||||
dataCursor.getLongOrNull(idColumn) ?: continue
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
WhatsAppContactInfo.ItemType -> {
|
||||
val data1 = dataCursor.getStringOrNull(data1Column)
|
||||
?: continue@loop
|
||||
val dataId = dataCursor.getLong(idColumn)
|
||||
contactInfos.add(
|
||||
WhatsAppContactInfo(
|
||||
"+${data1.substringBefore('@')}",
|
||||
dataId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
SignalContactInfo.ItemType -> {
|
||||
val data1 = dataCursor.getStringOrNull(data1Column)
|
||||
?: continue@loop
|
||||
val dataId = dataCursor.getLong(idColumn)
|
||||
contactInfos.add(SignalContactInfo(data1, dataId))
|
||||
}
|
||||
}
|
||||
}
|
||||
dataCursor.close()
|
||||
@@ -159,7 +170,10 @@ internal class ContactRepository(
|
||||
firstName = firstName,
|
||||
lastName = lastName,
|
||||
displayName = displayName,
|
||||
contactInfos = contactInfos,
|
||||
phoneNumbers = phoneNumbers.distinct(),
|
||||
emailAddresses = emailAddresses.distinct(),
|
||||
postalAddresses = postalAddresses.distinct(),
|
||||
contactApps = contactApps.distinct(),
|
||||
lookupKey = lookUpKey
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user