Added possibility to add labels to contacts
This commit is contained in:
@ -13,14 +13,16 @@ import java.util.ArrayList
|
||||
|
||||
sealed class Contact {
|
||||
|
||||
data class ContactUri(var uri: String, var label: String = "")
|
||||
|
||||
abstract fun name(): String
|
||||
abstract fun id(): Long
|
||||
abstract fun favorite(): Boolean
|
||||
abstract fun colorInt(): Int
|
||||
abstract fun uris(): List<String>
|
||||
abstract fun uris(): List<ContactUri>
|
||||
abstract fun email(): String
|
||||
|
||||
class BaresipContact(var name: String, val uris: ArrayList<String>, var email: String, var color: Int,
|
||||
class BaresipContact(var name: String, val uris: ArrayList<ContactUri>, var email: String, var color: Int,
|
||||
var id: Long, var favorite: Boolean): Contact() {
|
||||
var avatarImage: Bitmap? = null
|
||||
override fun name() = name
|
||||
@ -31,7 +33,7 @@ sealed class Contact {
|
||||
override fun email() = email
|
||||
}
|
||||
|
||||
class AndroidContact(var name: String, val uris: ArrayList<String>, var email: String, var color: Int,
|
||||
class AndroidContact(var name: String, val uris: ArrayList<ContactUri>, var email: String, var color: Int,
|
||||
var thumbnailUri: Uri?, var id: Long, var favorite: Boolean): Contact() {
|
||||
override fun name() = name
|
||||
override fun id() = id
|
||||
@ -101,9 +103,9 @@ sealed class Contact {
|
||||
is BaresipContact -> {
|
||||
if (c.name.equals(name, ignoreCase = true)) {
|
||||
for (u in c.uris) {
|
||||
if (tel && !u.startsWith("tel:"))
|
||||
if (tel && !u.uri.startsWith("tel:"))
|
||||
continue
|
||||
uris.add(u)
|
||||
uris.add(u.uri)
|
||||
}
|
||||
return uris
|
||||
}
|
||||
@ -111,9 +113,9 @@ sealed class Contact {
|
||||
is AndroidContact -> {
|
||||
if (c.name == name) {
|
||||
for (u in c.uris) {
|
||||
if (tel && !u.startsWith("tel:"))
|
||||
if (tel && !u.uri.startsWith("tel:"))
|
||||
continue
|
||||
uris.add(u)
|
||||
uris.add(u.uri)
|
||||
}
|
||||
return uris
|
||||
}
|
||||
@ -129,14 +131,14 @@ sealed class Contact {
|
||||
when (c) {
|
||||
is BaresipContact -> {
|
||||
for (u in c.uris)
|
||||
if (Utils.uriMatch(u, uri))
|
||||
if (Utils.uriMatch(u.uri, uri))
|
||||
return c
|
||||
}
|
||||
is AndroidContact -> {
|
||||
val cleanUri = uri.filterNot { setOf('-', ' ', '(', ')').contains(it) }
|
||||
for (u in c.uris)
|
||||
if (Utils.uriMatch(
|
||||
u.filterNot { setOf('-', ' ', '(', ')').contains(it) },
|
||||
u.uri.filterNot { setOf('-', ' ', '(', ')').contains(it) },
|
||||
cleanUri
|
||||
)
|
||||
)
|
||||
@ -161,7 +163,10 @@ sealed class Contact {
|
||||
BaresipService.baresipContacts.value.toList()
|
||||
}
|
||||
for (c in contacts) {
|
||||
contents += "\"${c.name}\" <${c.uris.joinToString(",")}>;email=${c.email};id=${c.id}" +
|
||||
val uris = c.uris.joinToString(",") {
|
||||
if (it.label.isNotEmpty()) "${it.uri}[${it.label}]" else it.uri
|
||||
}
|
||||
contents += "\"${c.name}\" <$uris>;email=${c.email};id=${c.id}" +
|
||||
";color=${c.color};favorite=${if (c.favorite) "yes" else "no"}\n"
|
||||
avatarFiles.remove(c.id.toString() + ".png")
|
||||
}
|
||||
@ -176,7 +181,7 @@ sealed class Contact {
|
||||
// cursor using getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE)
|
||||
val projection = arrayOf(ContactsContract.Data.CONTACT_ID, ContactsContract.Data.DISPLAY_NAME,
|
||||
ContactsContract.Data.MIMETYPE, ContactsContract.Data.DATA1,
|
||||
/* ContactsContract.Data.DATA2 ,*/ ContactsContract.Data.PHOTO_THUMBNAIL_URI,
|
||||
ContactsContract.Data.DATA2, ContactsContract.Data.PHOTO_THUMBNAIL_URI,
|
||||
ContactsContract.Contacts.STARRED)
|
||||
val selection =
|
||||
ContactsContract.Data.MIMETYPE + "='" + ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE + "' OR " +
|
||||
@ -191,12 +196,13 @@ sealed class Contact {
|
||||
val name = cur.getString(1) ?: ""
|
||||
val mime = cur.getString(2)
|
||||
val data = cur.getString(3) ?: continue
|
||||
val thumb = cur.getString(4)?.toUri()
|
||||
val starred = cur.getInt(5)
|
||||
val type = cur.getInt(4)
|
||||
val thumb = cur.getString(5)?.toUri()
|
||||
val starred = cur.getInt(6)
|
||||
val contact = if (contacts.containsKey(id))
|
||||
contacts[id]!!
|
||||
else
|
||||
AndroidContact(name, ArrayList<String>(), "", Utils.randomColor(), thumb, id, starred == 1)
|
||||
AndroidContact(name, ArrayList<ContactUri>(), "", Utils.randomColor(), thumb, id, starred == 1)
|
||||
if (contact.name == "" && name != "")
|
||||
contact.name = name
|
||||
if (contact.thumbnailUri == null && thumb != null)
|
||||
@ -204,13 +210,14 @@ sealed class Contact {
|
||||
when (mime) {
|
||||
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> {
|
||||
val uri = "tel:${data.filterNot { setOf('-', ' ', '(', ')').contains(it) }}"
|
||||
if (uri !in contact.uris)
|
||||
contact.uris.add(uri)
|
||||
val label = typeToString(type)
|
||||
if (contact.uris.none { it.uri == uri })
|
||||
contact.uris.add(ContactUri(uri, label))
|
||||
}
|
||||
ContactsContract.CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE -> {
|
||||
val uri = "sip:$data"
|
||||
if (uri !in contact.uris)
|
||||
contact.uris.add(uri)
|
||||
if (contact.uris.none { it.uri == uri })
|
||||
contact.uris.add(ContactUri(uri, ""))
|
||||
}
|
||||
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE -> {
|
||||
if (contact.email == "")
|
||||
@ -228,13 +235,22 @@ sealed class Contact {
|
||||
BaresipService.androidContacts.value = newList.toList()
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
private fun typeToString(type: Int): String {
|
||||
return when(type) {
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_HOME -> "Home"
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE -> "Mobile"
|
||||
ContactsContract.CommonDataKinds.Phone.TYPE_WORK -> "Work"
|
||||
else -> "Unknown"
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
fun stringToType(label: String): Int {
|
||||
return when (label) {
|
||||
"Home" -> ContactsContract.CommonDataKinds.Phone.TYPE_HOME
|
||||
"Mobile" -> ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE
|
||||
"Work" -> ContactsContract.CommonDataKinds.Phone.TYPE_WORK
|
||||
"" -> ContactsContract.CommonDataKinds.Phone.TYPE_OTHER
|
||||
else -> ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,7 +268,17 @@ sealed class Contact {
|
||||
val name = parts[1]
|
||||
val uriParams = parts[2].trim()
|
||||
val urisPart = uriParams.substringAfter("<").substringBefore(">")
|
||||
val uris = ArrayList(urisPart.split(","))
|
||||
val uris = ArrayList<ContactUri>()
|
||||
for (uPart in urisPart.split(",")) {
|
||||
if (uPart.isEmpty()) continue
|
||||
if (uPart.contains("[") && uPart.contains("]")) {
|
||||
val uri = uPart.substringBefore("[")
|
||||
val label = uPart.substringAfter("[").substringBefore("]")
|
||||
uris.add(ContactUri(uri, label))
|
||||
} else {
|
||||
uris.add(ContactUri(uPart, ""))
|
||||
}
|
||||
}
|
||||
val params = uriParams.substringAfter(">;")
|
||||
val email = Utils.paramValue(params, "email")
|
||||
val colorValue = Utils.paramValue(params, "color" )
|
||||
|
||||
@ -54,6 +54,7 @@ import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LocalMinimumInteractiveComponentSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
@ -124,7 +125,7 @@ private data class ScreenState(
|
||||
val id: Long = 0,
|
||||
val newId: Long = 0,
|
||||
val name: String = "",
|
||||
val uris: List<String> = emptyList(),
|
||||
val uris: List<Contact.ContactUri> = emptyList(),
|
||||
val email: String = "",
|
||||
val color: Int = 0,
|
||||
val avatarImageUri: String? = null,
|
||||
@ -157,7 +158,7 @@ private fun ContactScreen(
|
||||
new = true,
|
||||
isEditing = true,
|
||||
name = "",
|
||||
uris = if (uriOrNameArg == "") emptyList() else listOf(uriOrNameArg),
|
||||
uris = if (uriOrNameArg == "") emptyList() else listOf(Contact.ContactUri(uriOrNameArg, "")),
|
||||
email = "",
|
||||
favorite = false,
|
||||
android = BaresipService.contactsMode == "android",
|
||||
@ -606,9 +607,9 @@ private fun UrisSection(
|
||||
ctx: Context,
|
||||
viewModel: ViewModel,
|
||||
navController: NavController,
|
||||
uris: List<String>,
|
||||
uris: List<Contact.ContactUri>,
|
||||
isEditing: Boolean,
|
||||
onUrisChange: (List<String>) -> Unit
|
||||
onUrisChange: (List<Contact.ContactUri>) -> Unit
|
||||
) {
|
||||
val selectedAor by viewModel.selectedAor.collectAsState()
|
||||
|
||||
@ -617,24 +618,39 @@ private fun UrisSection(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
uris.forEachIndexed { index, uri ->
|
||||
uris.forEachIndexed { index, contactUri ->
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = uri,
|
||||
placeholder = { Text(stringResource(R.string.user_domain_or_number)) },
|
||||
onValueChange = { newUri ->
|
||||
val newList = uris.toMutableList()
|
||||
newList[index] = newUri
|
||||
onUrisChange(newList.toList())
|
||||
},
|
||||
modifier = Modifier.weight(1f),
|
||||
textStyle = androidx.compose.ui.text.TextStyle(fontSize = 18.sp),
|
||||
label = { Text("${stringResource(R.string.sip_or_tel_uri)} ${index + 1}") },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
|
||||
)
|
||||
Column (modifier = Modifier.weight(1f)) {
|
||||
OutlinedTextField(
|
||||
value = contactUri.uri,
|
||||
placeholder = { Text(stringResource(R.string.user_domain_or_number)) },
|
||||
onValueChange = { newUri ->
|
||||
val newList = uris.toMutableList()
|
||||
newList[index] = contactUri.copy(uri = newUri)
|
||||
onUrisChange(newList.toList())
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textStyle = androidx.compose.ui.text.TextStyle(fontSize = 18.sp),
|
||||
label = { Text("${stringResource(R.string.sip_or_tel_uri)} ${index + 1}") },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = contactUri.label,
|
||||
placeholder = { Text(stringResource(R.string.label)) },
|
||||
onValueChange = { newLabel ->
|
||||
val newList = uris.toMutableList()
|
||||
newList[index] = contactUri.copy(label = newLabel)
|
||||
onUrisChange(newList.toList())
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textStyle = androidx.compose.ui.text.TextStyle(fontSize = 18.sp),
|
||||
label = { Text(stringResource(R.string.label)) },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
|
||||
)
|
||||
}
|
||||
if (uris.size > 1) {
|
||||
CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) {
|
||||
IconButton(
|
||||
@ -659,7 +675,7 @@ private fun UrisSection(
|
||||
IconButton(
|
||||
onClick = {
|
||||
val newList = uris.toMutableList()
|
||||
newList.add("")
|
||||
newList.add(Contact.ContactUri("", ""))
|
||||
onUrisChange(newList.toList())
|
||||
},
|
||||
modifier = Modifier.align(Alignment.Start)
|
||||
@ -674,15 +690,32 @@ private fun UrisSection(
|
||||
} else {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
for (uri in uris) {
|
||||
uris.forEachIndexed { index, contactUri ->
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = stringResource(R.string.bullet_item, uri.substringAfter(":")),
|
||||
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}"
|
||||
}
|
||||
|
||||
OutlinedTextField(
|
||||
value = uri.substringAfter(":"),
|
||||
onValueChange = {},
|
||||
enabled = false,
|
||||
modifier = Modifier.weight(1f),
|
||||
fontSize = 18.sp,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
textStyle = androidx.compose.ui.text.TextStyle(fontSize = 18.sp),
|
||||
label = { Text(text = label, fontWeight = FontWeight.Bold) },
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
disabledTextColor = MaterialTheme.colorScheme.onSurface,
|
||||
disabledBorderColor = MaterialTheme.colorScheme.outline,
|
||||
disabledLeadingIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
disabledTrailingIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
)
|
||||
|
||||
val ua = UserAgent.ofAor(selectedAor)
|
||||
@ -772,15 +805,24 @@ private fun EmailSection(ctx: Context, email: String, isEditing: Boolean, onEmai
|
||||
)
|
||||
} else if (email.isNotEmpty()) {
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(bottom = 12.dp),
|
||||
Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Start
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.bullet_item, email),
|
||||
OutlinedTextField(
|
||||
value = email,
|
||||
onValueChange = {},
|
||||
enabled = false,
|
||||
modifier = Modifier.weight(1f),
|
||||
fontSize = 18.sp,
|
||||
color = MaterialTheme.colorScheme.onBackground,
|
||||
textStyle = androidx.compose.ui.text.TextStyle(fontSize = 18.sp),
|
||||
label = { Text(text = stringResource(R.string.email), fontWeight = FontWeight.Bold) },
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
disabledTextColor = MaterialTheme.colorScheme.onSurface,
|
||||
disabledBorderColor = MaterialTheme.colorScheme.outline,
|
||||
disabledLeadingIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
disabledTrailingIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
disabledLabelColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
)
|
||||
IconButton(
|
||||
onClick = {
|
||||
@ -855,9 +897,9 @@ private fun checkOnClick(
|
||||
currentState: ScreenState,
|
||||
uriOrNameArg: String
|
||||
): Boolean {
|
||||
val newUris = ArrayList<String>()
|
||||
for (uri in currentState.uris) {
|
||||
var u = uri.filterNot { setOf('-', ' ', '(', ')').contains(it) }
|
||||
val newUris = ArrayList<Contact.ContactUri>()
|
||||
for (contactUri in currentState.uris) {
|
||||
var u = contactUri.uri.filterNot { setOf('-', ' ', '(', ')').contains(it) }
|
||||
if (u == "") continue
|
||||
if (!u.startsWith("sip:") && !u.startsWith("tel:"))
|
||||
u = if (Utils.isTelNumber(u)) "tel:$u" else "sip:$u"
|
||||
@ -868,7 +910,7 @@ private fun checkOnClick(
|
||||
showAlert.value = true
|
||||
return false
|
||||
}
|
||||
newUris.add(u)
|
||||
newUris.add(Contact.ContactUri(u, contactUri.label))
|
||||
}
|
||||
|
||||
if (newUris.isEmpty() && currentState.email.trim().isEmpty()) {
|
||||
@ -879,7 +921,7 @@ private fun checkOnClick(
|
||||
}
|
||||
|
||||
var newName = currentState.name.trim()
|
||||
if (newName == "") newName = if (newUris.isNotEmpty()) newUris[0].substringAfter(":") else currentState.email
|
||||
if (newName == "") newName = if (newUris.isNotEmpty()) newUris[0].uri.substringAfter(":") else currentState.email
|
||||
if (!Utils.checkName(newName)) {
|
||||
alertTitle.value = ctx.getString(R.string.notice)
|
||||
alertMessage.value = String.format(ctx.getString(R.string.invalid_contact), newName)
|
||||
@ -1015,12 +1057,21 @@ private fun addAndroidContact(ctx: Context, contact: Contact.BaresipContact): Bo
|
||||
.withValue(CommonDataKinds.Email.ADDRESS, contact.email)
|
||||
.withValue(CommonDataKinds.Email.TYPE, CommonDataKinds.Email.TYPE_HOME).build())
|
||||
}
|
||||
for (uri in contact.uris) {
|
||||
for (contactUri in contact.uris) {
|
||||
val uri = contactUri.uri
|
||||
val label = contactUri.label
|
||||
val mimeType = if (uri.startsWith("sip:")) CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE else CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
||||
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
||||
val builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
||||
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
|
||||
.withValue(Data.MIMETYPE, mimeType)
|
||||
.withValue(Data.DATA1, uri.substringAfter(":")).build())
|
||||
.withValue(Data.DATA1, uri.substringAfter(":"))
|
||||
if (mimeType == CommonDataKinds.Phone.CONTENT_ITEM_TYPE) {
|
||||
val type = Contact.stringToType(label)
|
||||
builder.withValue(CommonDataKinds.Phone.TYPE, type)
|
||||
if (type == CommonDataKinds.Phone.TYPE_CUSTOM)
|
||||
builder.withValue(CommonDataKinds.Phone.LABEL, label)
|
||||
}
|
||||
ops.add(builder.build())
|
||||
}
|
||||
if (contact.avatarImage != null) {
|
||||
val photoData = bitmapToPNGByteArray(contact.avatarImage!!)
|
||||
@ -1044,17 +1095,26 @@ private fun updateAndroidContact(ctx: Context, rawContactId: Long, contact: Cont
|
||||
if (contact.email.isNotEmpty()) {
|
||||
if (updateAndroidEmail(ctx, rawContactId, contact.email) == 0) addAndroidEmail(ctx, rawContactId, contact.email)
|
||||
}
|
||||
for (uri in contact.uris) if (updateAndroidUri(ctx, rawContactId, uri) == 0) addAndroidUri(ctx, rawContactId, uri)
|
||||
for (contactUri in contact.uris) if (updateAndroidUri(ctx, rawContactId, contactUri) == 0) addAndroidUri(ctx, rawContactId, contactUri)
|
||||
if (updateAndroidPhoto(ctx, rawContactId, contact.avatarImage) == 0) if (contact.avatarImage != null) addAndroidPhoto(ctx, rawContactId, contact.avatarImage!!)
|
||||
}
|
||||
|
||||
private fun addAndroidUri(ctx: Context, rawContactId: Long, uri: String) {
|
||||
private fun addAndroidUri(ctx: Context, rawContactId: Long, contactUri: Contact.ContactUri) {
|
||||
val uri = contactUri.uri
|
||||
val label = contactUri.label
|
||||
val mimeType = if (uri.startsWith("sip:")) CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE else CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
||||
val ops = ArrayList<ContentProviderOperation>()
|
||||
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
||||
val builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
|
||||
.withValue(Data.RAW_CONTACT_ID, rawContactId)
|
||||
.withValue(Data.MIMETYPE, mimeType)
|
||||
.withValue(Data.DATA1, uri.substringAfter(":")).build())
|
||||
.withValue(Data.DATA1, uri.substringAfter(":"))
|
||||
if (mimeType == CommonDataKinds.Phone.CONTENT_ITEM_TYPE) {
|
||||
val type = Contact.stringToType(label)
|
||||
builder.withValue(CommonDataKinds.Phone.TYPE, type)
|
||||
if (type == CommonDataKinds.Phone.TYPE_CUSTOM)
|
||||
builder.withValue(CommonDataKinds.Phone.LABEL, label)
|
||||
}
|
||||
val ops = ArrayList<ContentProviderOperation>()
|
||||
ops.add(builder.build())
|
||||
try {
|
||||
ctx.contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
|
||||
} catch (e: Exception) {
|
||||
@ -1062,10 +1122,18 @@ private fun addAndroidUri(ctx: Context, rawContactId: Long, uri: String) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateAndroidUri(ctx: Context, rawContactId: Long, uri: String): Int {
|
||||
private fun updateAndroidUri(ctx: Context, rawContactId: Long, contactUri: Contact.ContactUri): Int {
|
||||
val uri = contactUri.uri
|
||||
val label = contactUri.label
|
||||
val mimeType = if (uri.startsWith("sip:")) CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE else CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
||||
val contentValues = ContentValues()
|
||||
contentValues.put(ContactsContract.Data.DATA1, uri)
|
||||
contentValues.put(ContactsContract.Data.DATA1, uri.substringAfter(":"))
|
||||
if (mimeType == CommonDataKinds.Phone.CONTENT_ITEM_TYPE) {
|
||||
val type = Contact.stringToType(label)
|
||||
contentValues.put(CommonDataKinds.Phone.TYPE, type)
|
||||
if (type == CommonDataKinds.Phone.TYPE_CUSTOM)
|
||||
contentValues.put(CommonDataKinds.Phone.LABEL, label)
|
||||
}
|
||||
val where = "${ContactsContract.Data.RAW_CONTACT_ID}=$rawContactId and ${ContactsContract.Data.MIMETYPE}='$mimeType'"
|
||||
return try {
|
||||
ctx.contentResolver.update(ContactsContract.Data.CONTENT_URI, contentValues, where, null)
|
||||
|
||||
@ -151,10 +151,17 @@ private fun ContactsScreen(navController: NavController) {
|
||||
writer.write("PHOTO;ENCODING=BASE64;JPEG:$base64Image\n")
|
||||
}
|
||||
for (u in contact.uris) {
|
||||
if (u.startsWith("tel:"))
|
||||
writer.write("TEL:${u.substring(4)}\n")
|
||||
else if (u.startsWith("sip:"))
|
||||
writer.write("X-SIP:${u.substring(4)}\n")
|
||||
if (u.uri.startsWith("tel:")) {
|
||||
if (u.label.isNotEmpty())
|
||||
writer.write("TEL;X-${u.label}:${u.uri.substring(4)}\n")
|
||||
else
|
||||
writer.write("TEL:${u.uri.substring(4)}\n")
|
||||
} else if (u.uri.startsWith("sip:")) {
|
||||
if (u.label.isNotEmpty())
|
||||
writer.write("X-SIP;X-${u.label}:${u.uri.substring(4)}\n")
|
||||
else
|
||||
writer.write("X-SIP:${u.uri.substring(4)}\n")
|
||||
}
|
||||
}
|
||||
writer.write("END:VCARD\n")
|
||||
}
|
||||
@ -188,7 +195,7 @@ private fun ContactsScreen(navController: NavController) {
|
||||
|
||||
var name = ""
|
||||
var email = ""
|
||||
val uris = mutableListOf<String>()
|
||||
val uris = mutableListOf<Contact.ContactUri>()
|
||||
var photoBase64 = ""
|
||||
var contactNo = 0
|
||||
val newBaresipContacts = BaresipService.baresipContacts.value.toMutableList()
|
||||
@ -212,18 +219,20 @@ private fun ContactsScreen(navController: NavController) {
|
||||
email = line.substringAfter(":").trim()
|
||||
}
|
||||
line.startsWith("TEL", ignoreCase = true) -> {
|
||||
val label = if (line.contains("X-")) line.substringAfter("X-").substringBefore(":") else ""
|
||||
val value = line.substringAfter(":").trim()
|
||||
val cleanValue = value.filterNot { setOf('-', ' ', '(', ')').contains(it) }
|
||||
if (cleanValue.isNotEmpty()) {
|
||||
val telUri = if (cleanValue.startsWith("tel:")) cleanValue else "tel:$cleanValue"
|
||||
if (telUri !in uris) uris.add(telUri)
|
||||
if (uris.none { it.uri == telUri }) uris.add(Contact.ContactUri(telUri, label))
|
||||
}
|
||||
}
|
||||
line.startsWith("X-SIP:", ignoreCase = true) -> {
|
||||
val sipUri = line.substring(6).trim()
|
||||
line.startsWith("X-SIP", ignoreCase = true) -> {
|
||||
val label = if (line.contains("X-")) line.substringAfter("X-").substringBefore(":") else ""
|
||||
val sipUri = line.substringAfter(":").trim()
|
||||
if (sipUri.isNotEmpty()) {
|
||||
val fullSipUri = if (sipUri.startsWith("sip:")) sipUri else "sip:$sipUri"
|
||||
if (fullSipUri !in uris) uris.add(fullSipUri)
|
||||
if (uris.none { it.uri == fullSipUri }) uris.add(Contact.ContactUri(fullSipUri, label))
|
||||
}
|
||||
}
|
||||
line.startsWith("PHOTO", ignoreCase = true) && line.contains("BASE64", ignoreCase = true) -> {
|
||||
@ -249,7 +258,7 @@ private fun ContactsScreen(navController: NavController) {
|
||||
}
|
||||
if (existingContact != null) {
|
||||
for (u in uris) {
|
||||
if (u !in existingContact.uris) {
|
||||
if (existingContact.uris.none { it.uri == u.uri }) {
|
||||
existingContact.uris.add(u)
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,6 +485,7 @@
|
||||
<!-- Contact Activity -->
|
||||
<string name="new_contact">Uusi yhteystieto</string>
|
||||
<string name="contact_name">Nimi</string>
|
||||
<string name="label">Kuvaus</string>
|
||||
<string name="email">Sähköposti</string>
|
||||
<string name="sip_or_tel_uri">SIP tai TEL URI</string>
|
||||
<string name="user_domain_or_number">käyttäjä@domain tai puhelinnumero</string>
|
||||
|
||||
@ -460,6 +460,7 @@
|
||||
<!-- Contact Activity -->
|
||||
<string name="new_contact">New Contact</string>
|
||||
<string name="contact_name">Name</string>
|
||||
<string name="label">Label</string>
|
||||
<string name="email">Email</string>
|
||||
<string name="sip_or_tel_uri">SIP or tel URI</string>
|
||||
<string name="user_domain_or_number">user@domain or telephone number</string>
|
||||
|
||||
Reference in New Issue
Block a user