From c5bd9bdd808277cc0d15f68989743019aa9efbd7 Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Sun, 18 Jan 2026 22:44:45 +0200 Subject: [PATCH] Improved showing of suggestions on MainScreen --- .../com/tutpro/baresip/ContactsScreen.kt | 19 +---- .../kotlin/com/tutpro/baresip/MainScreen.kt | 83 ++++++++++++------- .../main/kotlin/com/tutpro/baresip/Utils.kt | 22 +++++ 3 files changed, 77 insertions(+), 47 deletions(-) diff --git a/app/src/main/kotlin/com/tutpro/baresip/ContactsScreen.kt b/app/src/main/kotlin/com/tutpro/baresip/ContactsScreen.kt index ccdbcb1d..48e9b709 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/ContactsScreen.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/ContactsScreen.kt @@ -255,7 +255,7 @@ private fun ContactsContent( Utils.unaccent(contact.name()).contains(normalizedQuery, ignoreCase = true) } .map { contact -> - Pair(contact, buildAnnotatedStringWithHighlight(contact.name(), searchQuery)) + Pair(contact, Utils.buildAnnotatedStringWithHighlight(contact.name(), searchQuery)) } } } @@ -432,20 +432,3 @@ private fun ContactsContent( } } } - -private fun buildAnnotatedStringWithHighlight(name: String, query: String): AnnotatedString { - val normalizedName = Utils.unaccent(name) - val normalizedQuery = Utils.unaccent(query) - val startIndex = normalizedName.indexOf(normalizedQuery, ignoreCase = true) - return if (startIndex == -1) { - buildAnnotatedString { append(name) } - } else { - buildAnnotatedString { - append(name.take(startIndex)) - withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { - append(name.drop(startIndex).take(normalizedQuery.length)) - } - append(name.drop(startIndex + normalizedQuery.length)) - } - } -} diff --git a/app/src/main/kotlin/com/tutpro/baresip/MainScreen.kt b/app/src/main/kotlin/com/tutpro/baresip/MainScreen.kt index 2f4d1ceb..c5cf9feb 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/MainScreen.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/MainScreen.kt @@ -128,6 +128,7 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.vectorResource +import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType @@ -483,7 +484,9 @@ private fun MainScreen( } Scaffold( - modifier = Modifier.fillMaxSize().imePadding(), + modifier = Modifier + .fillMaxSize() + .imePadding(), containerColor = MaterialTheme.colorScheme.background, topBar = { Column( @@ -652,8 +655,7 @@ private fun TopAppBar( onClick = { if (Build.VERSION.SDK_INT >= 31) Log.d(TAG, "Toggling speakerphone when dev/mode is " + - "${am.communicationDevice!!.type}/${am.mode}" - ) + "${am.communicationDevice!!.type}/${am.mode}") isSpeakerOn.value = !Utils.isSpeakerPhoneOn(am) Utils.toggleSpeakerPhone(ContextCompat.getMainExecutor(ctx), am) }, @@ -826,7 +828,9 @@ private fun BottomBar(ctx: Context, viewModel: ViewModel, navController: NavCont IconButton( onClick = { viewModel.toggleDialpadVisibility() }, - modifier = Modifier.weight(1f).size(buttonSize), + modifier = Modifier + .weight(1f) + .size(buttonSize), enabled = dialpadButtonEnabled.value ) { Icon( @@ -1060,8 +1064,7 @@ private fun AccountSpinner(ctx: Context, viewModel: ViewModel, navController: Na if (Api.account_regint(acc.accp) > 0) { Api.account_set_regint(acc.accp, 0) Api.ua_unregister(ua.uap) - } - else { + } else { Api.account_set_regint( acc.accp, acc.configuredRegInt @@ -1112,8 +1115,7 @@ private fun AccountSpinner(ctx: Context, viewModel: ViewModel, navController: Na if (Api.account_regint(acc.accp) > 0) { Api.account_set_regint(acc.accp, 0) Api.ua_unregister(ua.uap) - } - else { + } else { Api.account_set_regint( acc.accp, acc.configuredRegInt @@ -1179,15 +1181,17 @@ private fun CallUriRow( val isDialer = dialerState != null val suggestions by remember { contactNames } - var filteredSuggestions by remember { mutableStateOf(suggestions) } + var filteredSuggestions by remember { mutableStateOf>(emptyList()) } val focusRequester = remember { FocusRequester() } val lazyListState = rememberLazyListState() val isDialpadVisible by viewModel.isDialpadVisible.collectAsState() - Row(modifier = Modifier - .fillMaxWidth() - .padding(top = 4.dp, bottom = 8.dp), - verticalAlignment = Alignment.CenterVertically) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 4.dp, bottom = 8.dp), + verticalAlignment = Alignment.CenterVertically + ) { Column( modifier = Modifier.weight(1f), horizontalAlignment = Alignment.CenterHorizontally @@ -1200,10 +1204,21 @@ private fun CallUriRow( if (isDialer) { if (it != dialerState.callUri.value) { dialerState.callUri.value = it - filteredSuggestions = suggestions.filter { suggestion -> - it.length > 2 && suggestion.startsWith(it, ignoreCase = true) + if (it == "") { + dialerState.showCallButton.value = true + dialerState.showCallConferenceButton.value = true } - dialerState.showSuggestions.value = it.length > 2 + val normalizedInput = Utils.unaccent(it) + filteredSuggestions = suggestions + .filter { suggestion -> + it.length > 1 && + Utils.unaccent(suggestion) + .contains(normalizedInput, ignoreCase = true) + } + .map { suggestion -> + Utils.buildAnnotatedStringWithHighlight(suggestion, it) + } + dialerState.showSuggestions.value = it.length > 1 } } }, @@ -1214,8 +1229,9 @@ private fun CallUriRow( modifier = Modifier.clickable { if (dialerState.showSuggestions.value) dialerState.showSuggestions.value = false - else - dialerState.callUri.value = "" + dialerState.callUri.value = "" + dialerState.showCallButton.value = true + dialerState.showCallConferenceButton.value = true }, tint = MaterialTheme.colorScheme.onSurfaceVariant ) @@ -1233,10 +1249,11 @@ private fun CallUriRow( } }, label = { - Text(text = if (isDialer) - dialerState.callUriLabel.value - else - call!!.callUriLabel.value, + Text( + text = if (isDialer) + dialerState.callUriLabel.value + else + call!!.callUriLabel.value, fontSize = 18.sp ) }, @@ -1258,9 +1275,11 @@ private fun CallUriRow( .animateContentSize() ) { if (isDialer && dialerState.showSuggestions.value && filteredSuggestions.isNotEmpty()) { - Box(modifier = Modifier - .fillMaxWidth() - .heightIn(max = 150.dp)) { + Box( + modifier = Modifier + .fillMaxWidth() + .heightIn(max = 150.dp) + ) { LazyColumn( modifier = Modifier .fillMaxWidth() @@ -1273,13 +1292,13 @@ private fun CallUriRow( ) { items( items = filteredSuggestions, - key = { suggestion -> suggestion } + key = { suggestion -> suggestion.toString() } ) { suggestion -> Box( modifier = Modifier .fillMaxWidth() .clickable { - dialerState.callUri.value = suggestion + dialerState.callUri.value = suggestion.toString() dialerState.showSuggestions.value = false } .padding(12.dp) @@ -1619,7 +1638,12 @@ private fun CallRow( }, modifier = Modifier .fillMaxWidth() - .padding(start = 4.dp, end = 4.dp, top = 12.dp, bottom = 2.dp) + .padding( + start = 4.dp, + end = 4.dp, + top = 12.dp, + bottom = 2.dp + ) .focusRequester(focusRequester), label = { Text(stringResource(R.string.transfer_destination)) }, textStyle = TextStyle(fontSize = 18.sp), @@ -1662,7 +1686,8 @@ private fun CallRow( .fillMaxWidth() .clickable { transferUri = suggestion - call.showSuggestions.value = false + call.showSuggestions.value = + false } .padding(12.dp) ) { diff --git a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt index 23671162..f9ceca1f 100644 --- a/app/src/main/kotlin/com/tutpro/baresip/Utils.kt +++ b/app/src/main/kotlin/com/tutpro/baresip/Utils.kt @@ -29,6 +29,11 @@ import android.text.format.DateUtils import androidx.activity.result.ActivityResultLauncher import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatDelegate +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.withStyle import androidx.core.content.ContextCompat import androidx.core.graphics.toColorInt import androidx.core.net.toUri @@ -424,6 +429,23 @@ object Utils { return "\\p{InCombiningDiacriticalMarks}+".toRegex().replace(normalized, "") } + fun buildAnnotatedStringWithHighlight(name: String, query: String): AnnotatedString { + val normalizedName = Utils.unaccent(name) + val normalizedQuery = Utils.unaccent(query) + val startIndex = normalizedName.indexOf(normalizedQuery, ignoreCase = true) + return if (startIndex == -1) { + buildAnnotatedString { append(name) } + } else { + buildAnnotatedString { + append(name.take(startIndex)) + withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { + append(name.drop(startIndex).take(normalizedQuery.length)) + } + append(name.drop(startIndex + normalizedQuery.length)) + } + } + } + fun isVisible(): Boolean { return ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED) }