Added support for multiple uris in baresip contact
Improved selectable alert dialog colors
This commit is contained in:
@ -37,7 +37,9 @@ import androidx.compose.foundation.shape.CircleShape
|
|||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
|
import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@ -108,7 +110,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 uri: String = "",
|
val uris: List<String> = emptyList(),
|
||||||
val color: Int = 0,
|
val color: Int = 0,
|
||||||
val avatarImageUri: String? = null,
|
val avatarImageUri: String? = null,
|
||||||
val tmpAvatarFile: File? = null,
|
val tmpAvatarFile: File? = null,
|
||||||
@ -138,7 +140,7 @@ private fun ContactScreen(
|
|||||||
screenState = ScreenState(
|
screenState = ScreenState(
|
||||||
new = true,
|
new = true,
|
||||||
name = "",
|
name = "",
|
||||||
uri = uriOrNameArg,
|
uris = if (uriOrNameArg == "") emptyList() else listOf(uriOrNameArg),
|
||||||
favorite = false,
|
favorite = false,
|
||||||
android = BaresipService.contactsMode == "android",
|
android = BaresipService.contactsMode == "android",
|
||||||
color = Utils.randomColor(),
|
color = Utils.randomColor(),
|
||||||
@ -153,7 +155,7 @@ private fun ContactScreen(
|
|||||||
screenState = ScreenState(
|
screenState = ScreenState(
|
||||||
new = false,
|
new = false,
|
||||||
name = uriOrNameArg,
|
name = uriOrNameArg,
|
||||||
uri = contact.uri,
|
uris = contact.uris,
|
||||||
favorite = contact.favorite,
|
favorite = contact.favorite,
|
||||||
android = false,
|
android = false,
|
||||||
color = contact.color,
|
color = contact.color,
|
||||||
@ -320,9 +322,9 @@ private fun ContactContent(
|
|||||||
new = screenState.new,
|
new = screenState.new,
|
||||||
onNameChange = { newName -> onStateChange(screenState.copy(name = newName)) }
|
onNameChange = { newName -> onStateChange(screenState.copy(name = newName)) }
|
||||||
)
|
)
|
||||||
ContactUri(
|
ContactUris(
|
||||||
uri = screenState.uri,
|
uris = screenState.uris,
|
||||||
onUriChange = { newUri -> onStateChange(screenState.copy(uri = newUri)) }
|
onUrisChange = { newUris -> onStateChange(screenState.copy(uris = newUris)) }
|
||||||
)
|
)
|
||||||
Favorite(
|
Favorite(
|
||||||
ctx = ctx,
|
ctx = ctx,
|
||||||
@ -456,16 +458,62 @@ private fun ContactName(name: String, new: Boolean, onNameChange: (String) -> Un
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ContactUri(uri: String, onUriChange: (String) -> Unit) {
|
private fun ContactUris(uris: List<String>, onUrisChange: (List<String>) -> Unit) {
|
||||||
OutlinedTextField(
|
Column(
|
||||||
value = uri,
|
|
||||||
placeholder = { Text(stringResource(R.string.user_domain_or_number)) },
|
|
||||||
onValueChange = onUriChange,
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
textStyle = androidx.compose.ui.text.TextStyle(fontSize = 18.sp),
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
label = { Text(stringResource(R.string.sip_or_tel_uri)) },
|
) {
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text)
|
uris.forEachIndexed { index, uri ->
|
||||||
)
|
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)
|
||||||
|
)
|
||||||
|
if (uris.size > 1) {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
val newList = uris.toMutableList()
|
||||||
|
newList.removeAt(index)
|
||||||
|
onUrisChange(newList.toList())
|
||||||
|
},
|
||||||
|
modifier = Modifier.padding(start = 4.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Delete,
|
||||||
|
contentDescription = "Delete",
|
||||||
|
tint = MaterialTheme.colorScheme.error
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
val newList = uris.toMutableList()
|
||||||
|
newList.add("")
|
||||||
|
onUrisChange(newList.toList())
|
||||||
|
},
|
||||||
|
modifier = Modifier.align(Alignment.Start)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Add,
|
||||||
|
contentDescription = "Add",
|
||||||
|
tint = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -520,22 +568,34 @@ private fun checkOnClick(
|
|||||||
uriOrNameArg: String
|
uriOrNameArg: String
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
|
||||||
var newUri = currentState.uri.filterNot{setOf('-', ' ', '(', ')').contains(it)}
|
val newUris = ArrayList<String>()
|
||||||
if (!newUri.startsWith("sip:") && !newUri.startsWith("tel:"))
|
for (uri in currentState.uris) {
|
||||||
newUri = if (Utils.isTelNumber(newUri))
|
var u = uri.filterNot{setOf('-', ' ', '(', ')').contains(it)}
|
||||||
"tel:$newUri"
|
if (u == "") continue
|
||||||
else
|
if (!u.startsWith("sip:") && !u.startsWith("tel:"))
|
||||||
"sip:$newUri"
|
u = if (Utils.isTelNumber(u))
|
||||||
|
"tel:$u"
|
||||||
|
else
|
||||||
|
"sip:$u"
|
||||||
|
|
||||||
if (!Utils.checkUri(newUri)) {
|
if (!Utils.checkUri(u)) {
|
||||||
|
alertTitle.value = ctx.getString(R.string.notice)
|
||||||
|
alertMessage.value = String.format(ctx.getString(R.string.invalid_sip_or_tel_uri), u)
|
||||||
|
showAlert.value = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
newUris.add(u)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newUris.isEmpty()) {
|
||||||
alertTitle.value = ctx.getString(R.string.notice)
|
alertTitle.value = ctx.getString(R.string.notice)
|
||||||
alertMessage.value = String.format(ctx.getString(R.string.invalid_sip_or_tel_uri), newUri)
|
alertMessage.value = ctx.getString(R.string.sip_or_tel_uri)
|
||||||
showAlert.value = true
|
showAlert.value = true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var newName = currentState.name.trim()
|
var newName = currentState.name.trim()
|
||||||
if (newName == "") newName = newUri.substringAfter(":")
|
if (newName == "") newName = newUris[0].substringAfter(":")
|
||||||
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)
|
||||||
@ -572,7 +632,7 @@ private fun checkOnClick(
|
|||||||
val contact: Contact.BaresipContact =
|
val contact: Contact.BaresipContact =
|
||||||
Contact.BaresipContact(
|
Contact.BaresipContact(
|
||||||
newName,
|
newName,
|
||||||
newUri,
|
newUris,
|
||||||
currentState.color,
|
currentState.color,
|
||||||
idToUse,
|
idToUse,
|
||||||
currentState.favorite
|
currentState.favorite
|
||||||
@ -683,17 +743,19 @@ private fun addAndroidContact(ctx: Context, contact: Contact.BaresipContact): Bo
|
|||||||
.withValue(Data.MIMETYPE, CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
|
.withValue(Data.MIMETYPE, CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
|
||||||
.withValue(CommonDataKinds.StructuredName.DISPLAY_NAME, contact.name)
|
.withValue(CommonDataKinds.StructuredName.DISPLAY_NAME, contact.name)
|
||||||
.build())
|
.build())
|
||||||
val mimeType = if (contact.uri.startsWith("sip:"))
|
for (uri in contact.uris) {
|
||||||
CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
val mimeType = if (uri.startsWith("sip:"))
|
||||||
else
|
CommonDataKinds.SipAddress.CONTENT_ITEM_TYPE
|
||||||
CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
else
|
||||||
ops.add(
|
CommonDataKinds.Phone.CONTENT_ITEM_TYPE
|
||||||
ContentProviderOperation
|
ops.add(
|
||||||
.newInsert(ContactsContract.Data.CONTENT_URI)
|
ContentProviderOperation
|
||||||
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
|
.newInsert(ContactsContract.Data.CONTENT_URI)
|
||||||
.withValue(Data.MIMETYPE, mimeType)
|
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
|
||||||
.withValue(Data.DATA1, contact.uri.substringAfter(":"))
|
.withValue(Data.MIMETYPE, mimeType)
|
||||||
.build())
|
.withValue(Data.DATA1, uri.substringAfter(":"))
|
||||||
|
.build())
|
||||||
|
}
|
||||||
|
|
||||||
if (contact.avatarImage != null) {
|
if (contact.avatarImage != null) {
|
||||||
val photoData: ByteArray? = bitmapToPNGByteArray(contact.avatarImage!!)
|
val photoData: ByteArray? = bitmapToPNGByteArray(contact.avatarImage!!)
|
||||||
@ -717,8 +779,9 @@ private fun addAndroidContact(ctx: Context, contact: Contact.BaresipContact): Bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateAndroidContact(ctx: Context, rawContactId: Long, contact: Contact.BaresipContact) {
|
private fun updateAndroidContact(ctx: Context, rawContactId: Long, contact: Contact.BaresipContact) {
|
||||||
if (updateAndroidUri(ctx, rawContactId, contact.uri) == 0)
|
for (uri in contact.uris)
|
||||||
addAndroidUri(ctx, rawContactId, contact.uri)
|
if (updateAndroidUri(ctx, rawContactId, uri) == 0)
|
||||||
|
addAndroidUri(ctx, rawContactId, uri)
|
||||||
if (updateAndroidPhoto(ctx, rawContactId, contact.avatarImage) == 0)
|
if (updateAndroidPhoto(ctx, rawContactId, contact.avatarImage) == 0)
|
||||||
if (contact.avatarImage != null)
|
if (contact.avatarImage != null)
|
||||||
addAndroidPhoto(ctx, rawContactId, contact.avatarImage!!)
|
addAndroidPhoto(ctx, rawContactId, contact.avatarImage!!)
|
||||||
|
|||||||
@ -72,6 +72,7 @@ import androidx.navigation.compose.composable
|
|||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import com.tutpro.baresip.CustomElements.AlertDialog
|
import com.tutpro.baresip.CustomElements.AlertDialog
|
||||||
|
import com.tutpro.baresip.CustomElements.SelectableAlertDialog
|
||||||
import com.tutpro.baresip.CustomElements.verticalScrollbar
|
import com.tutpro.baresip.CustomElements.verticalScrollbar
|
||||||
|
|
||||||
fun NavGraphBuilder.callsScreenRoute(navController: NavController, viewModel: ViewModel) {
|
fun NavGraphBuilder.callsScreenRoute(navController: NavController, viewModel: ViewModel) {
|
||||||
@ -303,6 +304,15 @@ private fun Calls(
|
|||||||
lastButtonText = stringResource(R.string.ok),
|
lastButtonText = stringResource(R.string.ok),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SelectableAlertDialog(
|
||||||
|
openDialog = CustomElements.showSelectItemDialog,
|
||||||
|
title = stringResource(R.string.choose_destination_uri),
|
||||||
|
items = CustomElements.selectItems.value,
|
||||||
|
onItemClicked = CustomElements.selectItemAction.value,
|
||||||
|
neutralButtonText = stringResource(R.string.cancel),
|
||||||
|
onNeutralClicked = {}
|
||||||
|
)
|
||||||
|
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@ -339,32 +349,88 @@ private fun Calls(
|
|||||||
secondButtonText.value = ctx.getString(R.string.call)
|
secondButtonText.value = ctx.getString(R.string.call)
|
||||||
secondAction.value = {
|
secondAction.value = {
|
||||||
if (ua != null) {
|
if (ua != null) {
|
||||||
handleIntent(ctx, viewModel, intent, "call")
|
val contact = Contact.findContact(peerUri)
|
||||||
navController.navigate("main") {
|
val uris = if (contact is Contact.BaresipContact) {
|
||||||
popUpTo("main")
|
if (ua.account.isMobile)
|
||||||
launchSingleTop = true
|
contact.uris.filter { it.startsWith("tel:") }
|
||||||
|
else
|
||||||
|
contact.uris
|
||||||
|
} else {
|
||||||
|
listOf(peerUri)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uris.size > 1) {
|
||||||
|
CustomElements.selectItems.value = uris
|
||||||
|
CustomElements.selectItemAction.value = { index ->
|
||||||
|
intent.putExtra("peer", uris[index])
|
||||||
|
handleIntent(ctx, viewModel, intent, "call")
|
||||||
|
navController.navigate("main") {
|
||||||
|
popUpTo("main")
|
||||||
|
launchSingleTop = true
|
||||||
|
}
|
||||||
|
CustomElements.showSelectItemDialog.value = false
|
||||||
|
}
|
||||||
|
CustomElements.showSelectItemDialog.value = true
|
||||||
|
} else if (uris.size == 1) {
|
||||||
|
intent.putExtra("peer", uris[0])
|
||||||
|
handleIntent(ctx, viewModel, intent, "call")
|
||||||
|
navController.navigate("main") {
|
||||||
|
popUpTo("main")
|
||||||
|
launchSingleTop = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastButtonText.value = ctx.getString(R.string.send_message)
|
lastButtonText.value = ctx.getString(R.string.send_message)
|
||||||
lastAction.value = {
|
lastAction.value = {
|
||||||
if (account.isMobile) {
|
if (ua != null) {
|
||||||
if (!Utils.isDefaultSmsApp(ctx)) {
|
val contact = Contact.findContact(peerUri)
|
||||||
alertTitle.value = ctx.getString(R.string.notice)
|
val uris = if (contact is Contact.BaresipContact) {
|
||||||
alertMessage.value = ctx.getString(R.string.enable_default_messaging)
|
if (ua.account.isMobile)
|
||||||
showAlert.value = true
|
contact.uris.filter { it.startsWith("tel:") }
|
||||||
|
else
|
||||||
|
contact.uris
|
||||||
} else {
|
} else {
|
||||||
if (ua != null) {
|
listOf(peerUri)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uris.size > 1) {
|
||||||
|
CustomElements.selectItems.value = uris
|
||||||
|
CustomElements.selectItemAction.value = { index ->
|
||||||
|
intent.putExtra("peer", uris[index])
|
||||||
|
if (ua.account.isMobile) {
|
||||||
|
if (!Utils.isDefaultSmsApp(ctx)) {
|
||||||
|
alertTitle.value = ctx.getString(R.string.notice)
|
||||||
|
alertMessage.value = ctx.getString(R.string.enable_default_messaging)
|
||||||
|
showAlert.value = true
|
||||||
|
} else {
|
||||||
|
handleIntent(ctx, viewModel, intent, "message")
|
||||||
|
navController.navigateUp()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleIntent(ctx, viewModel, intent, "message")
|
||||||
|
navController.navigateUp()
|
||||||
|
}
|
||||||
|
CustomElements.showSelectItemDialog.value = false
|
||||||
|
}
|
||||||
|
CustomElements.showSelectItemDialog.value = true
|
||||||
|
} else if (uris.size == 1) {
|
||||||
|
intent.putExtra("peer", uris[0])
|
||||||
|
if (ua.account.isMobile) {
|
||||||
|
if (!Utils.isDefaultSmsApp(ctx)) {
|
||||||
|
alertTitle.value = ctx.getString(R.string.notice)
|
||||||
|
alertMessage.value = ctx.getString(R.string.enable_default_messaging)
|
||||||
|
showAlert.value = true
|
||||||
|
} else {
|
||||||
|
handleIntent(ctx, viewModel, intent, "message")
|
||||||
|
navController.navigateUp()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
handleIntent(ctx, viewModel, intent, "message")
|
handleIntent(ctx, viewModel, intent, "message")
|
||||||
navController.navigateUp()
|
navController.navigateUp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
if (ua != null) {
|
|
||||||
handleIntent(ctx, viewModel, intent, "message")
|
|
||||||
navController.navigateUp()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
},
|
},
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import java.util.ArrayList
|
|||||||
|
|
||||||
sealed class Contact {
|
sealed class Contact {
|
||||||
|
|
||||||
class BaresipContact(var name: String, var uri: String, var color: Int, var id: Long,
|
class BaresipContact(var name: String, val uris: ArrayList<String>, var color: Int, var id: Long,
|
||||||
var favorite: Boolean): Contact() {
|
var favorite: Boolean): Contact() {
|
||||||
var avatarImage: Bitmap? = null
|
var avatarImage: Bitmap? = null
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ sealed class Contact {
|
|||||||
fun copy(): Contact {
|
fun copy(): Contact {
|
||||||
val copy = when (this) {
|
val copy = when (this) {
|
||||||
is BaresipContact ->
|
is BaresipContact ->
|
||||||
BaresipContact(name, uri, color, id, favorite)
|
BaresipContact(name, ArrayList(uris), color, id, favorite)
|
||||||
is AndroidContact ->
|
is AndroidContact ->
|
||||||
AndroidContact(name, color, thumbnailUri, id, favorite)
|
AndroidContact(name, color, thumbnailUri, id, favorite)
|
||||||
}
|
}
|
||||||
@ -107,9 +107,10 @@ sealed class Contact {
|
|||||||
when (c) {
|
when (c) {
|
||||||
is BaresipContact -> {
|
is BaresipContact -> {
|
||||||
if (c.name.equals(name, ignoreCase = true)) {
|
if (c.name.equals(name, ignoreCase = true)) {
|
||||||
uris.add(c.uri.removePrefix("<")
|
for (u in c.uris)
|
||||||
.replaceAfter(">", "")
|
uris.add(u.removePrefix("<")
|
||||||
.replace(">", ""))
|
.replaceAfter(">", "")
|
||||||
|
.replace(">", ""))
|
||||||
return uris
|
return uris
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,8 +129,9 @@ sealed class Contact {
|
|||||||
for (c in BaresipService.contacts)
|
for (c in BaresipService.contacts)
|
||||||
when (c) {
|
when (c) {
|
||||||
is BaresipContact -> {
|
is BaresipContact -> {
|
||||||
if (Utils.uriMatch(c.uri, uri))
|
for (u in c.uris)
|
||||||
return c
|
if (Utils.uriMatch(u, uri))
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
is AndroidContact -> {
|
is AndroidContact -> {
|
||||||
val cleanUri = uri.filterNot{setOf('-', ' ', '(', ')').contains(it)}
|
val cleanUri = uri.filterNot{setOf('-', ' ', '(', ')').contains(it)}
|
||||||
@ -153,7 +155,7 @@ sealed class Contact {
|
|||||||
val avatarFiles = avatarFileNames()
|
val avatarFiles = avatarFileNames()
|
||||||
var contents = ""
|
var contents = ""
|
||||||
for (c in BaresipService.baresipContacts.value) {
|
for (c in BaresipService.baresipContacts.value) {
|
||||||
contents += "\"${c.name}\" <${c.uri}>;id=${c.id};color=${c.color}" +
|
contents += "\"${c.name}\" <${c.uris.joinToString(",")}>;id=${c.id};color=${c.color}" +
|
||||||
";favorite=${if (c.favorite) "yes" else "no"}\n"
|
";favorite=${if (c.favorite) "yes" else "no"}\n"
|
||||||
avatarFiles.remove(c.id.toString() + ".png")
|
avatarFiles.remove(c.id.toString() + ".png")
|
||||||
}
|
}
|
||||||
@ -236,7 +238,8 @@ sealed class Contact {
|
|||||||
contactNo++
|
contactNo++
|
||||||
val name = parts[1]
|
val name = parts[1]
|
||||||
val uriParams = parts[2].trim()
|
val uriParams = parts[2].trim()
|
||||||
val uri = uriParams.substringAfter("<").substringBefore(">")
|
val urisPart = uriParams.substringAfter("<").substringBefore(">")
|
||||||
|
val uris = ArrayList(urisPart.split(","))
|
||||||
val params = uriParams.substringAfter(">;")
|
val params = uriParams.substringAfter(">;")
|
||||||
val colorValue = Utils.paramValue(params, "color" )
|
val colorValue = Utils.paramValue(params, "color" )
|
||||||
val color: Int = if (colorValue != "")
|
val color: Int = if (colorValue != "")
|
||||||
@ -249,8 +252,8 @@ sealed class Contact {
|
|||||||
else
|
else
|
||||||
baseId + contactNo
|
baseId + contactNo
|
||||||
val favorite = Utils.paramValue(params, "favorite" ) == "yes"
|
val favorite = Utils.paramValue(params, "favorite" ) == "yes"
|
||||||
Log.d(TAG, "Restoring contact $name, $uri, $color, $id")
|
Log.d(TAG, "Restoring contact $name, $urisPart, $color, $id")
|
||||||
val contact = BaresipContact(name, uri, color, id, favorite)
|
val contact = BaresipContact(name, uris, color, id, favorite)
|
||||||
val avatarFilePath = BaresipService.filesPath + "/$id.png"
|
val avatarFilePath = BaresipService.filesPath + "/$id.png"
|
||||||
if (File(avatarFilePath).exists()) {
|
if (File(avatarFilePath).exists()) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -77,6 +77,7 @@ import androidx.navigation.NavGraphBuilder
|
|||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import com.tutpro.baresip.CustomElements.AlertDialog
|
import com.tutpro.baresip.CustomElements.AlertDialog
|
||||||
|
import com.tutpro.baresip.CustomElements.SelectableAlertDialog
|
||||||
import com.tutpro.baresip.CustomElements.TextAvatar
|
import com.tutpro.baresip.CustomElements.TextAvatar
|
||||||
import com.tutpro.baresip.CustomElements.verticalScrollbar
|
import com.tutpro.baresip.CustomElements.verticalScrollbar
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -209,6 +210,15 @@ private fun ContactsScreen(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SelectableAlertDialog(
|
||||||
|
openDialog = CustomElements.showSelectItemDialog,
|
||||||
|
title = stringResource(R.string.choose_destination_uri),
|
||||||
|
items = CustomElements.selectItems.value,
|
||||||
|
onItemClicked = CustomElements.selectItemAction.value,
|
||||||
|
neutralButtonText = stringResource(R.string.cancel),
|
||||||
|
onNeutralClicked = {}
|
||||||
|
)
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier.fillMaxSize().imePadding(),
|
modifier = Modifier.fillMaxSize().imePadding(),
|
||||||
containerColor = MaterialTheme.colorScheme.background,
|
containerColor = MaterialTheme.colorScheme.background,
|
||||||
@ -508,7 +518,6 @@ private fun ContactsContent(
|
|||||||
val intent = Intent(ctx, MainActivity::class.java)
|
val intent = Intent(ctx, MainActivity::class.java)
|
||||||
if (ua != null) {
|
if (ua != null) {
|
||||||
intent.putExtra("uap", ua.uap)
|
intent.putExtra("uap", ua.uap)
|
||||||
intent.putExtra("peer", contact.uri)
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Log.w(TAG, "onClickListener did not find UA for $aor")
|
Log.w(TAG, "onClickListener did not find UA for $aor")
|
||||||
@ -519,30 +528,79 @@ private fun ContactsContent(
|
|||||||
secondText.value = ctx.getString(R.string.call)
|
secondText.value = ctx.getString(R.string.call)
|
||||||
secondAction.value = {
|
secondAction.value = {
|
||||||
if (ua != null) {
|
if (ua != null) {
|
||||||
handleIntent(ctx, viewModel, intent, "call")
|
val uris = if (ua.account.isMobile)
|
||||||
navController.navigate("main") {
|
contact.uris.filter { it.startsWith("tel:") }
|
||||||
popUpTo("main")
|
else
|
||||||
launchSingleTop = true
|
contact.uris
|
||||||
|
|
||||||
|
if (uris.size > 1) {
|
||||||
|
CustomElements.selectItems.value = uris
|
||||||
|
CustomElements.selectItemAction.value = { index: Int ->
|
||||||
|
intent.putExtra("peer", uris[index])
|
||||||
|
handleIntent(ctx, viewModel, intent, "call")
|
||||||
|
navController.navigate("main") {
|
||||||
|
popUpTo("main")
|
||||||
|
launchSingleTop = true
|
||||||
|
}
|
||||||
|
CustomElements.showSelectItemDialog.value = false
|
||||||
|
}
|
||||||
|
CustomElements.showSelectItemDialog.value = true
|
||||||
|
} else if (uris.size == 1) {
|
||||||
|
intent.putExtra("peer", uris[0])
|
||||||
|
handleIntent(ctx, viewModel, intent, "call")
|
||||||
|
navController.navigate("main") {
|
||||||
|
popUpTo("main")
|
||||||
|
launchSingleTop = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastText.value = ctx.getString(R.string.send_message)
|
lastText.value = ctx.getString(R.string.send_message)
|
||||||
lastAction.value = {
|
lastAction.value = {
|
||||||
if (ua != null) {
|
if (ua != null) {
|
||||||
if (ua.account.isMobile) {
|
val uris = if (ua.account.isMobile)
|
||||||
if (!Utils.isDefaultSmsApp(ctx)) {
|
contact.uris.filter { it.startsWith("tel:") }
|
||||||
alertTitle.value = ctx.getString(R.string.notice)
|
else
|
||||||
alertMessage.value = ctx.getString(R.string.enable_default_messaging)
|
contact.uris
|
||||||
showAlert.value = true
|
|
||||||
} else {
|
if (uris.size > 1) {
|
||||||
|
CustomElements.selectItems.value = uris
|
||||||
|
CustomElements.selectItemAction.value = { index: Int ->
|
||||||
|
intent.putExtra("peer", uris[index])
|
||||||
|
if (ua.account.isMobile) {
|
||||||
|
if (!Utils.isDefaultSmsApp(ctx)) {
|
||||||
|
alertTitle.value = ctx.getString(R.string.notice)
|
||||||
|
alertMessage.value = ctx.getString(R.string.enable_default_messaging)
|
||||||
|
showAlert.value = true
|
||||||
|
} else {
|
||||||
|
handleIntent(ctx, viewModel, intent, "message")
|
||||||
|
navController.navigateUp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
handleIntent(ctx, viewModel, intent, "message")
|
||||||
|
navController.navigateUp()
|
||||||
|
}
|
||||||
|
CustomElements.showSelectItemDialog.value = false
|
||||||
|
}
|
||||||
|
CustomElements.showSelectItemDialog.value = true
|
||||||
|
} else if (uris.size == 1) {
|
||||||
|
intent.putExtra("peer", uris[0])
|
||||||
|
if (ua.account.isMobile) {
|
||||||
|
if (!Utils.isDefaultSmsApp(ctx)) {
|
||||||
|
alertTitle.value = ctx.getString(R.string.notice)
|
||||||
|
alertMessage.value = ctx.getString(R.string.enable_default_messaging)
|
||||||
|
showAlert.value = true
|
||||||
|
} else {
|
||||||
|
handleIntent(ctx, viewModel, intent, "message")
|
||||||
|
navController.navigateUp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
handleIntent(ctx, viewModel, intent, "message")
|
handleIntent(ctx, viewModel, intent, "message")
|
||||||
navController.navigateUp()
|
navController.navigateUp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
handleIntent(ctx, viewModel, intent, "message")
|
|
||||||
navController.navigateUp()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
|
|||||||
@ -82,6 +82,10 @@ import androidx.compose.ui.window.DialogProperties
|
|||||||
|
|
||||||
object CustomElements {
|
object CustomElements {
|
||||||
|
|
||||||
|
val selectItems = mutableStateOf(listOf<String>())
|
||||||
|
val selectItemAction = mutableStateOf<(Int) -> Unit>({ _ -> run {} })
|
||||||
|
val showSelectItemDialog = mutableStateOf(false)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Button(
|
fun Button(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
@ -424,7 +428,7 @@ object CustomElements {
|
|||||||
.padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 0.dp),
|
.padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 0.dp),
|
||||||
shape = RoundedCornerShape(16.dp),
|
shape = RoundedCornerShape(16.dp),
|
||||||
colors = CardDefaults.cardColors(
|
colors = CardDefaults.cardColors(
|
||||||
containerColor = MaterialTheme.colorScheme.surfaceContainer
|
containerColor = MaterialTheme.colorScheme.surfaceVariant
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.padding(16.dp)) {
|
Column(modifier = Modifier.padding(16.dp)) {
|
||||||
@ -449,8 +453,8 @@ object CustomElements {
|
|||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = item,
|
text = stringResource(R.string.bullet_item, item),
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
textAlign = TextAlign.Start
|
textAlign = TextAlign.Start
|
||||||
)
|
)
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.app.Activity.RESULT_OK
|
import android.app.Activity.RESULT_OK
|
||||||
import android.app.KeyguardManager
|
import android.app.KeyguardManager
|
||||||
import android.app.role.RoleManager
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
@ -180,9 +179,9 @@ private val showPasswordsDialog = mutableStateOf(false)
|
|||||||
private var passwordAccounts = mutableListOf<String>()
|
private var passwordAccounts = mutableListOf<String>()
|
||||||
private var password = mutableStateOf("")
|
private var password = mutableStateOf("")
|
||||||
|
|
||||||
private val selectItems = mutableStateOf(listOf<String>())
|
private val selectItems = CustomElements.selectItems
|
||||||
private val selectItemAction = mutableStateOf<(Int) -> Unit>({ _ -> run {} })
|
private val selectItemAction = CustomElements.selectItemAction
|
||||||
private val showSelectItemDialog = mutableStateOf(false)
|
private val showSelectItemDialog = CustomElements.showSelectItemDialog
|
||||||
|
|
||||||
fun NavGraphBuilder.mainScreenRoute(
|
fun NavGraphBuilder.mainScreenRoute(
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
|
|||||||
Reference in New Issue
Block a user