On contacts screen seach, show also contacts where search string matches contacts TEL URIs
Improved contact labeling
This commit is contained in:
@ -211,8 +211,10 @@ sealed class Contact {
|
||||
ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1,
|
||||
ContactsContract.Data.DATA2, ContactsContract.Data.PHOTO_THUMBNAIL_URI,
|
||||
ContactsContract.Contacts.STARRED)
|
||||
@Suppress("DEPRECATION")
|
||||
val sipMime = ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
||||
val selection =
|
||||
ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' OR " +
|
||||
ContactsContract.Data.MIMETYPE + "='" + sipMime + "' OR " +
|
||||
ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE + "' OR " +
|
||||
ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE + "'"
|
||||
val cur: Cursor? = ctx.contentResolver.query(ContactsContract.Data.CONTENT_URI, projection,
|
||||
@ -242,7 +244,7 @@ sealed class Contact {
|
||||
if (contact.uris.none { it.uri == uri })
|
||||
contact.uris.add(ContactUri(uri, label))
|
||||
}
|
||||
ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE -> {
|
||||
sipMime -> {
|
||||
val uri = "sip:$data"
|
||||
if (contact.uris.none { it.uri == uri })
|
||||
contact.uris.add(ContactUri(uri, ""))
|
||||
|
||||
@ -626,7 +626,14 @@ private fun UrisSection(
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textStyle = androidx.compose.ui.text.TextStyle(fontSize = 18.sp),
|
||||
label = { Text("${stringResource(R.string.sip_or_tel_uri)} ${index + 1}") },
|
||||
label = {
|
||||
val labelText = when {
|
||||
contactUri.uri.startsWith("sip:") -> stringResource(R.string.sip_uri)
|
||||
contactUri.uri.startsWith("tel:") -> stringResource(R.string.tel_uri)
|
||||
else -> stringResource(R.string.sip_or_tel_uri)
|
||||
}
|
||||
Text(labelText)
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
|
||||
)
|
||||
OutlinedTextField(
|
||||
@ -683,15 +690,10 @@ private fun UrisSection(
|
||||
}
|
||||
else
|
||||
Column(modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
uris.forEachIndexed { index, contactUri ->
|
||||
uris.forEach { contactUri ->
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
val uri = contactUri.uri
|
||||
val label = contactUri.label.ifEmpty {
|
||||
if (uri.startsWith("tel:"))
|
||||
"${stringResource(R.string.tel_uri)} ${index + 1}"
|
||||
else
|
||||
"${stringResource(R.string.sip_uri)} ${index + 1}"
|
||||
}
|
||||
val label = contactUri.label
|
||||
|
||||
OutlinedTextField(
|
||||
value = uri.substringAfter(":"),
|
||||
@ -699,7 +701,15 @@ private fun UrisSection(
|
||||
readOnly = true,
|
||||
modifier = Modifier.weight(1f),
|
||||
textStyle = androidx.compose.ui.text.TextStyle(fontSize = 18.sp),
|
||||
label = { Text(text = label, fontWeight = FontWeight.Bold) },
|
||||
label = {
|
||||
val labelText = label.ifEmpty {
|
||||
if (uri.startsWith("tel:"))
|
||||
stringResource(R.string.tel_uri)
|
||||
else
|
||||
stringResource(R.string.sip_uri)
|
||||
}
|
||||
Text(text = labelText, fontWeight = FontWeight.Bold)
|
||||
},
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
focusedBorderColor = MaterialTheme.colorScheme.outline,
|
||||
unfocusedBorderColor = MaterialTheme.colorScheme.outline,
|
||||
@ -1044,6 +1054,7 @@ private fun addAndroidContact(ctx: Context, contact: Contact.BaresipContact): Bo
|
||||
for (contactUri in contact.uris) {
|
||||
val uri = contactUri.uri
|
||||
val label = contactUri.label
|
||||
@Suppress("DEPRECATION")
|
||||
val mimeType = if (uri.startsWith("sip:"))
|
||||
CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
||||
else
|
||||
@ -1092,6 +1103,7 @@ private fun updateAndroidContact(ctx: Context, rawContactId: Long, contact: Cont
|
||||
private fun addAndroidUri(ctx: Context, rawContactId: Long, contactUri: Contact.ContactUri) {
|
||||
val uri = contactUri.uri
|
||||
val label = contactUri.label
|
||||
@Suppress("DEPRECATION")
|
||||
val mimeType = if (uri.startsWith("sip:"))
|
||||
CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
||||
else
|
||||
@ -1118,6 +1130,7 @@ private fun addAndroidUri(ctx: Context, rawContactId: Long, contactUri: Contact.
|
||||
private fun updateAndroidUri(ctx: Context, rawContactId: Long, contactUri: Contact.ContactUri): Int {
|
||||
val uri = contactUri.uri
|
||||
val label = contactUri.label
|
||||
@Suppress("DEPRECATION")
|
||||
val mimeType = if (uri.startsWith("sip:"))
|
||||
CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
||||
else
|
||||
|
||||
@ -66,6 +66,7 @@ import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
@ -561,9 +562,8 @@ private fun BottomBar(
|
||||
value = searchContactName,
|
||||
onValueChange = {
|
||||
onSearchContactNameChange(it)
|
||||
if (it.isBlank()) {
|
||||
if (it.isBlank())
|
||||
keyboardController?.hide()
|
||||
}
|
||||
},
|
||||
modifier = Modifier.weight(1f),
|
||||
singleLine = true,
|
||||
@ -633,16 +633,28 @@ private fun ContactsContent(
|
||||
val filteredContacts = remember(BaresipService.contacts, searchQuery) {
|
||||
if (searchQuery.isBlank())
|
||||
BaresipService.contacts.map { contact ->
|
||||
Pair(contact, buildAnnotatedString { append(contact.name()) })
|
||||
Triple(contact, buildAnnotatedString { append(contact.name()) }, null)
|
||||
}
|
||||
else {
|
||||
val normalizedQuery = Utils.unaccent(searchQuery)
|
||||
BaresipService.contacts
|
||||
.filter { contact ->
|
||||
Utils.unaccent(contact.name()).contains(normalizedQuery, ignoreCase = true)
|
||||
val numericQuery = searchQuery.filter { it.isDigit() || it == '+' }
|
||||
BaresipService.contacts.mapNotNull { contact ->
|
||||
val nameMatch = Utils.unaccent(contact.name()).contains(normalizedQuery, ignoreCase = true)
|
||||
var matchingUri: Contact.ContactUri? = null
|
||||
if (numericQuery.isNotEmpty()) {
|
||||
matchingUri = contact.uris().find {
|
||||
it.uri.startsWith("tel:") && it.uri.substring(4).contains(numericQuery)
|
||||
}
|
||||
}
|
||||
if (nameMatch || matchingUri != null) {
|
||||
val annotatedName = if (nameMatch)
|
||||
Utils.buildAnnotatedStringWithHighlight(contact.name(), searchQuery)
|
||||
else
|
||||
AnnotatedString(contact.name())
|
||||
Triple(contact, annotatedName, matchingUri)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
.map { contact ->
|
||||
Pair(contact, Utils.buildAnnotatedStringWithHighlight(contact.name(), searchQuery))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -667,8 +679,8 @@ private fun ContactsContent(
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||
) {
|
||||
itemsIndexed(
|
||||
filteredContacts, key = { index, (contact, _) -> "${contact.id()}_$index" }
|
||||
) { _, (contact, annotatedName) ->
|
||||
filteredContacts, key = { index, (contact, _, _) -> "${contact.id()}_$index" }
|
||||
) { _, (contact, annotatedName, matchingUri) ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Start
|
||||
@ -681,9 +693,7 @@ private fun ContactsContent(
|
||||
bitmap = avatarImage.asImageBitmap(),
|
||||
contentDescription = "Avatar",
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.clip(CircleShape)
|
||||
modifier = Modifier.size(36.dp).clip(CircleShape)
|
||||
)
|
||||
else
|
||||
TextAvatar(contact.name(), contact.color)
|
||||
@ -695,21 +705,13 @@ private fun ContactsContent(
|
||||
model = thumbNailUri,
|
||||
contentDescription = "Avatar",
|
||||
contentScale = ContentScale.Crop,
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.clip(CircleShape),
|
||||
modifier = Modifier.size(36.dp).clip(CircleShape),
|
||||
)
|
||||
else
|
||||
TextAvatar(contact.name(), contact.color)
|
||||
}
|
||||
}
|
||||
when (contact) {
|
||||
is Contact.BaresipContact -> {
|
||||
Text(
|
||||
text = annotatedName,
|
||||
fontSize = 20.sp,
|
||||
fontStyle = if (contact.favorite()) FontStyle.Italic else FontStyle.Normal,
|
||||
modifier = Modifier
|
||||
val textModifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 10.dp)
|
||||
.combinedClickable(
|
||||
@ -721,6 +723,8 @@ private fun ContactsContent(
|
||||
onFirstClicked.value = { }
|
||||
lastButtonText.value = deleteText
|
||||
onLastClicked.value = {
|
||||
when (contact) {
|
||||
is Contact.BaresipContact -> {
|
||||
val id = contact.id
|
||||
val avatarFile = File(BaresipService.filesPath, "$id.png")
|
||||
if (avatarFile.exists())
|
||||
@ -731,36 +735,43 @@ private fun ContactsContent(
|
||||
}
|
||||
Contact.removeBaresipContact(contact)
|
||||
}
|
||||
showDialog.value = true
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
is Contact.AndroidContact -> {
|
||||
Text(text = annotatedName,
|
||||
fontSize = 20.sp,
|
||||
fontStyle = if (contact.favorite()) FontStyle.Italic else FontStyle.Normal,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 10.dp, top = 4.dp, bottom = 4.dp)
|
||||
.combinedClickable(
|
||||
onClick = { navController.navigate("contact/${contact.name()}/old") },
|
||||
onLongClick = {
|
||||
title.value = confirmationText
|
||||
message.value = String.format(contactDeleteQuestion, contact.name())
|
||||
firstButtonText.value = cancelText
|
||||
onFirstClicked.value = { }
|
||||
lastButtonText.value = deleteText
|
||||
onLastClicked.value = {
|
||||
ctx.contentResolver.delete(
|
||||
ContactsContract.RawContacts.CONTENT_URI,
|
||||
ContactsContract.Contacts.DISPLAY_NAME + "='" + contact.name() + "'",
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
showDialog.value = true
|
||||
}
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = if (contact is Contact.AndroidContact)
|
||||
textModifier.padding(top = 4.dp, bottom = 4.dp)
|
||||
else
|
||||
textModifier
|
||||
) {
|
||||
Text(
|
||||
text = annotatedName,
|
||||
fontSize = 20.sp,
|
||||
fontStyle = if (contact.favorite()) FontStyle.Italic else FontStyle.Normal
|
||||
)
|
||||
if (matchingUri != null) {
|
||||
val tel = matchingUri.uri.substring(4)
|
||||
val annotatedTel = Utils.buildAnnotatedStringWithHighlight(
|
||||
tel,
|
||||
searchQuery.filter { it.isDigit() || it == '+' })
|
||||
Text(
|
||||
text = buildAnnotatedString {
|
||||
if (matchingUri.label.isNotEmpty())
|
||||
append("${matchingUri.label} ")
|
||||
append(annotatedTel)
|
||||
},
|
||||
fontSize = 16.sp,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user