Match search string to contacts' TEL URIs also on main and chats screens
This commit is contained in:
@ -14,9 +14,11 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.heightIn
|
import androidx.compose.foundation.layout.heightIn
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
import androidx.compose.foundation.layout.offset
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
@ -67,6 +69,7 @@ import androidx.compose.ui.platform.LocalFocusManager
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
@ -83,7 +86,6 @@ import androidx.navigation.NavType
|
|||||||
import androidx.navigation.compose.composable
|
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.BaresipService.Companion.contactNames
|
|
||||||
import com.tutpro.baresip.CustomElements.AlertDialog
|
import com.tutpro.baresip.CustomElements.AlertDialog
|
||||||
import com.tutpro.baresip.CustomElements.DropdownMenu
|
import com.tutpro.baresip.CustomElements.DropdownMenu
|
||||||
import com.tutpro.baresip.CustomElements.SelectableAlertDialog
|
import com.tutpro.baresip.CustomElements.SelectableAlertDialog
|
||||||
@ -137,6 +139,7 @@ private fun ChatsScreen(navController: NavController, aor: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
modifier = Modifier.fillMaxSize().imePadding(),
|
||||||
containerColor = MaterialTheme.colorScheme.background,
|
containerColor = MaterialTheme.colorScheme.background,
|
||||||
topBar = {
|
topBar = {
|
||||||
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
|
Column(modifier = Modifier.background(MaterialTheme.colorScheme.background)) {
|
||||||
@ -260,7 +263,6 @@ private fun Chats(
|
|||||||
account: Account,
|
account: Account,
|
||||||
uaMessages: MutableState<List<Message>>
|
uaMessages: MutableState<List<Message>>
|
||||||
) {
|
) {
|
||||||
val ctx = LocalContext.current
|
|
||||||
val aor = account.aor
|
val aor = account.aor
|
||||||
|
|
||||||
val showDialog = remember { mutableStateOf(false) }
|
val showDialog = remember { mutableStateOf(false) }
|
||||||
@ -272,6 +274,14 @@ private fun Chats(
|
|||||||
val lastButtonText = remember { mutableStateOf("") }
|
val lastButtonText = remember { mutableStateOf("") }
|
||||||
val lastAction = remember { mutableStateOf({}) }
|
val lastAction = remember { mutableStateOf({}) }
|
||||||
|
|
||||||
|
val shortChatQuestion = stringResource(R.string.short_chat_question)
|
||||||
|
val longChatQuestion = stringResource(R.string.long_chat_question)
|
||||||
|
val addContactText = stringResource(R.string.add_contact)
|
||||||
|
val blockText = stringResource(R.string.block)
|
||||||
|
val deleteText = stringResource(R.string.delete)
|
||||||
|
val anonymousText = stringResource(R.string.anonymous)
|
||||||
|
val unknownText = stringResource(R.string.unknown)
|
||||||
|
|
||||||
if (showDialog.value)
|
if (showDialog.value)
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
showDialog = showDialog,
|
showDialog = showDialog,
|
||||||
@ -341,17 +351,17 @@ private fun Chats(
|
|||||||
CustomElements.Button(
|
CustomElements.Button(
|
||||||
onClick = { navController.navigate("chat/${aor}/${message.peerUri}") },
|
onClick = { navController.navigate("chat/${aor}/${message.peerUri}") },
|
||||||
onLongClick = {
|
onLongClick = {
|
||||||
val peerName = Utils.friendlyUri(ctx, message.peerUri, account, includeLabel = false)
|
val peerName = Utils.friendlyUri(message.peerUri, account, includeLabel = false, anonymous = anonymousText, unknown = unknownText)
|
||||||
val peerNameWithLabel = Utils.friendlyUri(ctx, message.peerUri, account)
|
val peerNameWithLabel = Utils.friendlyUri(message.peerUri, account, anonymous = anonymousText, unknown = unknownText)
|
||||||
val contactExists =
|
val contactExists =
|
||||||
Contact.nameExists(peerName, BaresipService.contacts, false)
|
Contact.nameExists(peerName, BaresipService.contacts, false)
|
||||||
if (contactExists) {
|
if (contactExists) {
|
||||||
dialogMessage.value = String.format(
|
dialogMessage.value = String.format(
|
||||||
ctx.getString(R.string.short_chat_question),
|
shortChatQuestion,
|
||||||
peerNameWithLabel
|
peerNameWithLabel
|
||||||
)
|
)
|
||||||
secondButtonText.value = ""
|
secondButtonText.value = ""
|
||||||
lastButtonText.value = ctx.getString(R.string.delete)
|
lastButtonText.value = deleteText
|
||||||
lastAction.value = {
|
lastAction.value = {
|
||||||
deleteMessages(uaMessages, account, message.peerUri)
|
deleteMessages(uaMessages, account, message.peerUri)
|
||||||
}
|
}
|
||||||
@ -359,19 +369,19 @@ private fun Chats(
|
|||||||
else {
|
else {
|
||||||
dialogMessage.value =
|
dialogMessage.value =
|
||||||
String.format(
|
String.format(
|
||||||
ctx.getString(R.string.long_chat_question),
|
longChatQuestion,
|
||||||
peerName
|
peerName
|
||||||
)
|
)
|
||||||
secondButtonText.value = ctx.getString(R.string.add_contact)
|
secondButtonText.value = addContactText
|
||||||
secondAction.value = { navController.navigate("contact/${message.peerUri}/new") }
|
secondAction.value = { navController.navigate("contact/${message.peerUri}/new") }
|
||||||
thirdButtonText.value = ctx.getString(R.string.block)
|
thirdButtonText.value = blockText
|
||||||
thirdAction.value = {
|
thirdAction.value = {
|
||||||
if (!BlockRule.exists(message.peerUri)) {
|
if (!BlockRule.exists(message.peerUri)) {
|
||||||
BaresipService.blockRules.add(BlockRule(message.peerUri))
|
BaresipService.blockRules.add(BlockRule(message.peerUri))
|
||||||
BlockRule.save()
|
BlockRule.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastButtonText.value = ctx.getString(R.string.delete)
|
lastButtonText.value = deleteText
|
||||||
lastAction.value = { deleteMessages(uaMessages, account, message.peerUri) }
|
lastAction.value = { deleteMessages(uaMessages, account, message.peerUri) }
|
||||||
}
|
}
|
||||||
showDialog.value = true
|
showDialog.value = true
|
||||||
@ -384,7 +394,7 @@ private fun Chats(
|
|||||||
else
|
else
|
||||||
MaterialTheme.colorScheme.primaryContainer
|
MaterialTheme.colorScheme.primaryContainer
|
||||||
) {
|
) {
|
||||||
val peerName = Utils.friendlyUri(ctx, message.peerUri, account)
|
val peerName = Utils.friendlyUri(message.peerUri, account, anonymous = anonymousText, unknown = unknownText)
|
||||||
val cal = GregorianCalendar()
|
val cal = GregorianCalendar()
|
||||||
cal.timeInMillis = message.timeStamp
|
cal.timeInMillis = message.timeStamp
|
||||||
val fmt: DateFormat = if (isToday(message.timeStamp))
|
val fmt: DateFormat = if (isToday(message.timeStamp))
|
||||||
@ -424,12 +434,17 @@ private fun Chats(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun NewChatPeer(navController: NavController, account: Account) {
|
private fun NewChatPeer(navController: NavController, account: Account) {
|
||||||
val ctx = LocalContext.current
|
|
||||||
|
|
||||||
val alertTitle = remember { mutableStateOf("") }
|
val alertTitle = remember { mutableStateOf("") }
|
||||||
val alertMessage = remember { mutableStateOf("") }
|
val alertMessage = remember { mutableStateOf("") }
|
||||||
val showAlert = remember { mutableStateOf(false) }
|
val showAlert = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
val noticeText = stringResource(R.string.notice)
|
||||||
|
val noTelephonyProviderText = stringResource(R.string.no_telephony_provider)
|
||||||
|
val invalidSipOrTelUriText = stringResource(R.string.invalid_sip_or_tel_uri)
|
||||||
|
val contactNoTelUriText = stringResource(R.string.contact_no_tel_uri)
|
||||||
|
val contactNoSipOrTelUriText = stringResource(R.string.contact_no_sip_or_tel_uri)
|
||||||
|
|
||||||
fun makeChat(navController: NavController, account: Account, chatPeer: String) {
|
fun makeChat(navController: NavController, account: Account, chatPeer: String) {
|
||||||
val peerUri = if (Utils.isTelNumber(chatPeer))
|
val peerUri = if (Utils.isTelNumber(chatPeer))
|
||||||
"tel:$chatPeer"
|
"tel:$chatPeer"
|
||||||
@ -440,9 +455,9 @@ private fun NewChatPeer(navController: NavController, account: Account) {
|
|||||||
peerUri
|
peerUri
|
||||||
else
|
else
|
||||||
if (account.telProvider == "") {
|
if (account.telProvider == "") {
|
||||||
alertTitle.value = ctx.getString(R.string.notice)
|
alertTitle.value = noticeText
|
||||||
alertMessage.value =
|
alertMessage.value =
|
||||||
String.format(ctx.getString(R.string.no_telephony_provider), account.aor)
|
String.format(noTelephonyProviderText, account.aor)
|
||||||
showAlert.value = true
|
showAlert.value = true
|
||||||
""
|
""
|
||||||
} else
|
} else
|
||||||
@ -452,8 +467,8 @@ private fun NewChatPeer(navController: NavController, account: Account) {
|
|||||||
Utils.uriComplete(peerUri, account.aor)
|
Utils.uriComplete(peerUri, account.aor)
|
||||||
if (alertMessage.value.isEmpty()) {
|
if (alertMessage.value.isEmpty()) {
|
||||||
if (!Utils.checkUri(uri)) {
|
if (!Utils.checkUri(uri)) {
|
||||||
alertTitle.value = ctx.getString(R.string.notice)
|
alertTitle.value = noticeText
|
||||||
alertMessage.value = String.format(ctx.getString(R.string.invalid_sip_or_tel_uri), uri)
|
alertMessage.value = String.format(invalidSipOrTelUriText, uri)
|
||||||
showAlert.value = true
|
showAlert.value = true
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -483,8 +498,7 @@ private fun NewChatPeer(navController: NavController, account: Account) {
|
|||||||
onNeutralClicked = {}
|
onNeutralClicked = {}
|
||||||
)
|
)
|
||||||
|
|
||||||
val suggestions by remember { contactNames }
|
var filteredSuggestions by remember { mutableStateOf<List<Triple<Contact, AnnotatedString, Contact.ContactUri?>>>(emptyList()) }
|
||||||
var filteredSuggestions by remember { mutableStateOf<List<AnnotatedString>>(emptyList()) }
|
|
||||||
var showSuggestions by remember { mutableStateOf(false) }
|
var showSuggestions by remember { mutableStateOf(false) }
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
@ -518,23 +532,40 @@ private fun NewChatPeer(navController: NavController, account: Account) {
|
|||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = filteredSuggestions,
|
items = filteredSuggestions,
|
||||||
key = { suggestion -> suggestion.toString() }
|
key = { (contact, _, _) -> "${contact.id()}" }
|
||||||
) { suggestion ->
|
) { (contact, annotatedName, matchingUri) ->
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable {
|
.clickable {
|
||||||
newPeer = suggestion.toString()
|
val uri = matchingUri?.uri ?: contact.uris().firstOrNull()?.uri ?: contact.name()
|
||||||
|
newPeer = uri.substringAfter(":")
|
||||||
showSuggestions = false
|
showSuggestions = false
|
||||||
}
|
}
|
||||||
.padding(12.dp)
|
.padding(12.dp)
|
||||||
) {
|
) {
|
||||||
|
Column(modifier = Modifier.fillMaxWidth()) {
|
||||||
Text(
|
Text(
|
||||||
text = suggestion,
|
text = annotatedName,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
fontSize = 18.sp
|
fontSize = 18.sp
|
||||||
)
|
)
|
||||||
|
if (matchingUri != null) {
|
||||||
|
val tel = matchingUri.uri.substring(4)
|
||||||
|
val annotatedTel = Utils.buildAnnotatedStringWithHighlight(
|
||||||
|
tel,
|
||||||
|
newPeer.filter { c -> c.isDigit() || c == '+' })
|
||||||
|
Text(
|
||||||
|
text = buildAnnotatedString {
|
||||||
|
if (matchingUri.label.isNotEmpty())
|
||||||
|
append("${matchingUri.label} ")
|
||||||
|
append(annotatedTel)
|
||||||
|
},
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -552,13 +583,24 @@ private fun NewChatPeer(navController: NavController, account: Account) {
|
|||||||
emptyList()
|
emptyList()
|
||||||
else {
|
else {
|
||||||
val normalizedInput = Utils.unaccent(it)
|
val normalizedInput = Utils.unaccent(it)
|
||||||
suggestions
|
val numericInput = it.filter { c -> c.isDigit() || c == '+' }
|
||||||
.filter { suggestion ->
|
BaresipService.contacts.mapNotNull { contact ->
|
||||||
it.length > 1 &&
|
val nameMatch = Utils.unaccent(contact.name()).contains(normalizedInput, ignoreCase = true)
|
||||||
Utils.unaccent(suggestion).contains(normalizedInput, ignoreCase = true)
|
var matchingUri: Contact.ContactUri? = null
|
||||||
|
if (numericInput.isNotEmpty()) {
|
||||||
|
matchingUri = contact.uris().find { u ->
|
||||||
|
u.uri.startsWith("tel:") && u.uri.substring(4).contains(numericInput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nameMatch || matchingUri != null) {
|
||||||
|
val annotatedName = if (nameMatch)
|
||||||
|
Utils.buildAnnotatedStringWithHighlight(contact.name(), it)
|
||||||
|
else
|
||||||
|
AnnotatedString(contact.name())
|
||||||
|
Triple(contact, annotatedName, matchingUri)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
.map { suggestion ->
|
|
||||||
Utils.buildAnnotatedStringWithHighlight(suggestion, it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -595,11 +637,11 @@ private fun NewChatPeer(navController: NavController, account: Account) {
|
|||||||
val uris = Contact.contactContactUris(peerText, account.isMobile)
|
val uris = Contact.contactContactUris(peerText, account.isMobile)
|
||||||
if (uris.isEmpty()) {
|
if (uris.isEmpty()) {
|
||||||
if (Contact.nameExists(peerText, BaresipService.contacts, true)) {
|
if (Contact.nameExists(peerText, BaresipService.contacts, true)) {
|
||||||
alertTitle.value = ctx.getString(R.string.notice)
|
alertTitle.value = noticeText
|
||||||
alertMessage.value = if (account.isMobile)
|
alertMessage.value = if (account.isMobile)
|
||||||
String.format(ctx.getString(R.string.contact_no_tel_uri), peerText)
|
String.format(contactNoTelUriText, peerText)
|
||||||
else
|
else
|
||||||
String.format(ctx.getString(R.string.contact_no_sip_or_tel_uri), peerText)
|
String.format(contactNoSipOrTelUriText, peerText)
|
||||||
showAlert.value = true
|
showAlert.value = true
|
||||||
} else {
|
} else {
|
||||||
makeChat(navController, account, peerText)
|
makeChat(navController, account, peerText)
|
||||||
|
|||||||
@ -135,6 +135,7 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.res.vectorResource
|
import androidx.compose.ui.res.vectorResource
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||||
@ -153,7 +154,6 @@ import androidx.navigation.NavGraphBuilder
|
|||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import com.tutpro.baresip.BaresipService.Companion.circleGreen
|
import com.tutpro.baresip.BaresipService.Companion.circleGreen
|
||||||
import com.tutpro.baresip.BaresipService.Companion.colorblind
|
import com.tutpro.baresip.BaresipService.Companion.colorblind
|
||||||
import com.tutpro.baresip.BaresipService.Companion.contactNames
|
|
||||||
import com.tutpro.baresip.BaresipService.Companion.uas
|
import com.tutpro.baresip.BaresipService.Companion.uas
|
||||||
import com.tutpro.baresip.BaresipService.Companion.uasStatus
|
import com.tutpro.baresip.BaresipService.Companion.uasStatus
|
||||||
import com.tutpro.baresip.CustomElements.AlertDialog
|
import com.tutpro.baresip.CustomElements.AlertDialog
|
||||||
@ -1177,8 +1177,7 @@ private fun CallUriRow(
|
|||||||
|
|
||||||
val isDialer = dialerState != null
|
val isDialer = dialerState != null
|
||||||
|
|
||||||
val suggestions by remember { contactNames }
|
var filteredSuggestions by remember { mutableStateOf<List<Triple<Contact, AnnotatedString, Contact.ContactUri?>>>(emptyList()) }
|
||||||
var filteredSuggestions by remember { mutableStateOf<List<AnnotatedString>>(emptyList()) }
|
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
val isDialpadVisible by viewModel.isDialpadVisible.collectAsState()
|
val isDialpadVisible by viewModel.isDialpadVisible.collectAsState()
|
||||||
@ -1201,15 +1200,27 @@ private fun CallUriRow(
|
|||||||
dialerState.showCallButton.value = true
|
dialerState.showCallButton.value = true
|
||||||
dialerState.showCallConferenceButton.value = true
|
dialerState.showCallConferenceButton.value = true
|
||||||
}
|
}
|
||||||
|
if (it.length > 1) {
|
||||||
val normalizedInput = Utils.unaccent(it)
|
val normalizedInput = Utils.unaccent(it)
|
||||||
filteredSuggestions = suggestions
|
val numericInput = it.filter { c -> c.isDigit() || c == '+' }
|
||||||
.filter { suggestion ->
|
filteredSuggestions = BaresipService.contacts.mapNotNull { contact ->
|
||||||
it.length > 1 &&
|
val nameMatch = Utils.unaccent(contact.name()).contains(normalizedInput, ignoreCase = true)
|
||||||
Utils.unaccent(suggestion)
|
var matchingUri: Contact.ContactUri? = null
|
||||||
.contains(normalizedInput, ignoreCase = true)
|
if (numericInput.isNotEmpty()) {
|
||||||
|
matchingUri = contact.uris().find { u ->
|
||||||
|
u.uri.startsWith("tel:") && u.uri.substring(4).contains(numericInput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nameMatch || matchingUri != null) {
|
||||||
|
val annotatedName = if (nameMatch)
|
||||||
|
Utils.buildAnnotatedStringWithHighlight(contact.name(), it)
|
||||||
|
else
|
||||||
|
AnnotatedString(contact.name())
|
||||||
|
Triple(contact, annotatedName, matchingUri)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.map { suggestion ->
|
|
||||||
Utils.buildAnnotatedStringWithHighlight(suggestion, it)
|
|
||||||
}
|
}
|
||||||
dialerState.showSuggestions.value = it.length > 1
|
dialerState.showSuggestions.value = it.length > 1
|
||||||
}
|
}
|
||||||
@ -1305,23 +1316,40 @@ private fun CallUriRow(
|
|||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = filteredSuggestions,
|
items = filteredSuggestions,
|
||||||
key = { suggestion -> suggestion.toString() }
|
key = { (contact, _, _) -> "${contact.id()}" }
|
||||||
) { suggestion ->
|
) { (contact, annotatedName, matchingUri) ->
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable {
|
.clickable {
|
||||||
dialerState.callUri.value = suggestion.toString()
|
val uri = matchingUri?.uri ?: contact.uris().firstOrNull()?.uri ?: contact.name()
|
||||||
|
dialerState.callUri.value = uri.substringAfter(":")
|
||||||
dialerState.showSuggestions.value = false
|
dialerState.showSuggestions.value = false
|
||||||
}
|
}
|
||||||
.padding(12.dp)
|
.padding(12.dp)
|
||||||
) {
|
) {
|
||||||
|
Column(modifier = Modifier.fillMaxWidth()) {
|
||||||
Text(
|
Text(
|
||||||
text = suggestion,
|
text = annotatedName,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
fontSize = 18.sp
|
fontSize = 18.sp
|
||||||
)
|
)
|
||||||
|
if (matchingUri != null) {
|
||||||
|
val tel = matchingUri.uri.substring(4)
|
||||||
|
val annotatedTel = Utils.buildAnnotatedStringWithHighlight(
|
||||||
|
tel,
|
||||||
|
dialerState.callUri.value.filter { c -> c.isDigit() || c == '+' })
|
||||||
|
Text(
|
||||||
|
text = buildAnnotatedString {
|
||||||
|
if (matchingUri.label.isNotEmpty())
|
||||||
|
append("${matchingUri.label} ")
|
||||||
|
append(annotatedTel)
|
||||||
|
},
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1617,8 +1645,7 @@ private fun CallRow(
|
|||||||
color = MaterialTheme.colorScheme.onSurface,
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
)
|
)
|
||||||
var transferUri by remember { mutableStateOf("") }
|
var transferUri by remember { mutableStateOf("") }
|
||||||
val suggestions by remember { contactNames }
|
var filteredSuggestions by remember { mutableStateOf<List<Triple<Contact, AnnotatedString, Contact.ContactUri?>>>(emptyList()) }
|
||||||
var filteredSuggestions by remember { mutableStateOf<List<AnnotatedString>>(emptyList()) }
|
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
val lazyListState = rememberLazyListState()
|
val lazyListState = rememberLazyListState()
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
@ -1629,13 +1656,24 @@ private fun CallRow(
|
|||||||
transferUri = it
|
transferUri = it
|
||||||
if (it.length > 1) {
|
if (it.length > 1) {
|
||||||
val normalizedInput = Utils.unaccent(it)
|
val normalizedInput = Utils.unaccent(it)
|
||||||
filteredSuggestions = suggestions
|
val numericInput = it.filter { c -> c.isDigit() || c == '+' }
|
||||||
.filter { suggestion ->
|
filteredSuggestions = BaresipService.contacts.mapNotNull { contact ->
|
||||||
Utils.unaccent(suggestion)
|
val nameMatch = Utils.unaccent(contact.name()).contains(normalizedInput, ignoreCase = true)
|
||||||
.contains(normalizedInput, ignoreCase = true)
|
var matchingUri: Contact.ContactUri? = null
|
||||||
|
if (numericInput.isNotEmpty()) {
|
||||||
|
matchingUri = contact.uris().find { u ->
|
||||||
|
u.uri.startsWith("tel:") && u.uri.substring(4).contains(numericInput)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nameMatch || matchingUri != null) {
|
||||||
|
val annotatedName = if (nameMatch)
|
||||||
|
Utils.buildAnnotatedStringWithHighlight(contact.name(), it)
|
||||||
|
else
|
||||||
|
AnnotatedString(contact.name())
|
||||||
|
Triple(contact, annotatedName, matchingUri)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
.map { suggestion ->
|
|
||||||
Utils.buildAnnotatedStringWithHighlight(suggestion, it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
call.showSuggestions.value = transferUri.length > 1
|
call.showSuggestions.value = transferUri.length > 1
|
||||||
@ -1688,23 +1726,40 @@ private fun CallRow(
|
|||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
items = filteredSuggestions,
|
items = filteredSuggestions,
|
||||||
key = { suggestion -> suggestion.toString() }
|
key = { (contact, _, _) -> "${contact.id()}" }
|
||||||
) { suggestion ->
|
) { (contact, annotatedName, matchingUri) ->
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable {
|
.clickable {
|
||||||
transferUri = suggestion.toString()
|
val uri = matchingUri?.uri ?: contact.uris().firstOrNull()?.uri ?: contact.name()
|
||||||
|
transferUri = uri.substringAfter(":")
|
||||||
call.showSuggestions.value = false
|
call.showSuggestions.value = false
|
||||||
}
|
}
|
||||||
.padding(12.dp)
|
.padding(12.dp)
|
||||||
) {
|
) {
|
||||||
|
Column(modifier = Modifier.fillMaxWidth()) {
|
||||||
Text(
|
Text(
|
||||||
text = suggestion,
|
text = annotatedName,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
fontSize = 18.sp
|
fontSize = 18.sp
|
||||||
)
|
)
|
||||||
|
if (matchingUri != null) {
|
||||||
|
val tel = matchingUri.uri.substring(4)
|
||||||
|
val annotatedTel = Utils.buildAnnotatedStringWithHighlight(
|
||||||
|
tel,
|
||||||
|
transferUri.filter { c -> c.isDigit() || c == '+' })
|
||||||
|
Text(
|
||||||
|
text = buildAnnotatedString {
|
||||||
|
if (matchingUri.label.isNotEmpty())
|
||||||
|
append("${matchingUri.label} ")
|
||||||
|
append(annotatedTel)
|
||||||
|
},
|
||||||
|
fontSize = 14.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -158,6 +158,13 @@ object Utils {
|
|||||||
|
|
||||||
fun friendlyUri(ctx: Context, uri: String, account: Account, e164Check: Boolean = true,
|
fun friendlyUri(ctx: Context, uri: String, account: Account, e164Check: Boolean = true,
|
||||||
includeLabel: Boolean = true): String {
|
includeLabel: Boolean = true): String {
|
||||||
|
return friendlyUri(uri, account, e164Check, includeLabel,
|
||||||
|
ctx.getString(R.string.anonymous), ctx.getString(R.string.unknown))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun friendlyUri(uri: String, account: Account, e164Check: Boolean = true,
|
||||||
|
includeLabel: Boolean = true, anonymous: String = "Anonymous",
|
||||||
|
unknown: String = "Unknown"): String {
|
||||||
var u = Contact.contactName(uri, includeLabel)
|
var u = Contact.contactName(uri, includeLabel)
|
||||||
if (u != uri)
|
if (u != uri)
|
||||||
return u
|
return u
|
||||||
@ -175,9 +182,9 @@ object Utils {
|
|||||||
return if (host == aorDomain(account.aor) || params.contains("user=phone"))
|
return if (host == aorDomain(account.aor) || params.contains("user=phone"))
|
||||||
user
|
user
|
||||||
else if (host == "anonymous.invalid")
|
else if (host == "anonymous.invalid")
|
||||||
ctx.getString(R.string.anonymous)
|
anonymous
|
||||||
else if (host == "unknown.invalid")
|
else if (host == "unknown.invalid")
|
||||||
ctx.getString(R.string.unknown)
|
unknown
|
||||||
else if (params.isEmpty())
|
else if (params.isEmpty())
|
||||||
"$user@$host"
|
"$user@$host"
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in New Issue
Block a user