Improved showing of suggestions on MainScreen
This commit is contained in:
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<List<AnnotatedString>>(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)
|
||||
) {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user