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