feat(app): improve search function by removing search suggestions

This commit is contained in:
Anthony 2024-06-30 22:06:37 +02:00
parent 1b94c0a694
commit 64c2e13a6f
3 changed files with 54 additions and 64 deletions

View File

@ -1,15 +1,10 @@
package component package component
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
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.filled.Clear import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Search
@ -27,13 +22,11 @@ import androidx.compose.ui.semantics.traversalIndex
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
import data.ENumber
import tab.Licenses import tab.Licenses
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun Search(eNumbers: List<ENumber>) { fun Search(text: MutableState<String>) {
var text by rememberSaveable { mutableStateOf("") }
var expanded by rememberSaveable { mutableStateOf(false) } var expanded by rememberSaveable { mutableStateOf(false) }
val menuExpanded = remember { mutableStateOf(false) } val menuExpanded = remember { mutableStateOf(false) }
@ -47,32 +40,24 @@ fun Search(eNumbers: List<ENumber>) {
modifier = Modifier modifier = Modifier
.align(Alignment.CenterHorizontally) .align(Alignment.CenterHorizontally)
.semantics { traversalIndex = 0f }, .semantics { traversalIndex = 0f },
query = text, query = text.value,
onQueryChange = { text = it }, onQueryChange = { text.value = it },
onSearch = { expanded = false }, onSearch = { expanded = false },
onActiveChange = { expanded = it }, onActiveChange = { /* Do nothing */ },
active = expanded, active = expanded,
placeholder = { Text("Search E Numbers") }, placeholder = { Text("Search E Numbers") },
leadingIcon = { leadingIcon = {
IconButton( IconButton(
enabled = expanded, enabled = false,
onClick = { if (expanded) expanded = false } onClick = { /* Do nothing */ }
) { ) {
AnimatedContent(
targetState = expanded,
) { targetExpanded ->
if (targetExpanded) {
Icon(Icons.AutoMirrored.Filled.ArrowBack, "Exit Search")
} else {
Icon(Icons.Filled.Search, "Navigation Menu") Icon(Icons.Filled.Search, "Navigation Menu")
} }
}
}
}, },
trailingIcon = { trailingIcon = {
Row { Row {
if (text.isNotEmpty()) { if (text.value.isNotEmpty()) {
IconButton(onClick = { text = "" }) { IconButton(onClick = { text.value = "" }) {
Icon(imageVector = Icons.Filled.Clear, contentDescription = "Clear Search") Icon(imageVector = Icons.Filled.Clear, contentDescription = "Clear Search")
} }
} }
@ -84,22 +69,7 @@ fun Search(eNumbers: List<ENumber>) {
} }
} }
} }
) { ) { /* No search content - done externally */ }
Column(Modifier.verticalScroll(rememberScrollState())) {
searchSuggestion(query = text, eNumbers = eNumbers).forEach {
ListItem(
headlineContent = { Text(text = it.number) },
modifier = Modifier
.clickable {
text = it.number
expanded = false
}
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 4.dp)
)
}
}
}
} }
} }
@ -128,15 +98,3 @@ private fun OptionsMenu(expanded: MutableState<Boolean>) {
) )
} }
} }
private fun searchSuggestion(query: String, eNumbers: List<ENumber>): List<ENumber> {
if (query.isEmpty()) {
return eNumbers
}
val filtered = eNumbers.filter { eNumber ->
eNumber.number.contains(query, ignoreCase = true)
}
return filtered
}

View File

@ -2,6 +2,7 @@ package tab.list
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@ -17,22 +18,42 @@ import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.screen.Screen import cafe.adriel.voyager.core.screen.Screen
import data.EGroup import data.EGroup
import data.ENumber import data.ENumber
class ENumberList(private val eNumbers: List<EGroup>) : Screen { class ENumberList(private val eNumbers: List<EGroup>, private val searchText: MutableState<String>) : Screen {
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
override fun Content() { override fun Content() {
val displayItems = searchFilter(query = searchText.value, eGroups = eNumbers)
println(displayItems)
if (displayItems.isEmpty()) {
Column (
modifier = Modifier
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(text = "Sorry, we couldn't find any results :(")
}
return
}
LazyColumn(contentPadding = PaddingValues(6.dp)) { LazyColumn(contentPadding = PaddingValues(6.dp)) {
eNumbers.forEach { eGroup -> displayItems.forEach { eGroup ->
if (displayItems.isNotEmpty()) {
stickyHeader { stickyHeader {
Header(group = eGroup.group) Header(group = eGroup.group)
} }
}
items(eGroup.numbers) { eNumber -> items(eGroup.numbers) { eNumber ->
ItemList(eNumber = eNumber) ItemList(eNumber = eNumber)
@ -88,4 +109,18 @@ class ENumberList(private val eNumbers: List<EGroup>) : Screen {
contentDescription = status contentDescription = status
) )
} }
private fun searchFilter(query: String, eGroups: List<EGroup>): List<EGroup> {
if (query.isEmpty()) {
return eGroups
}
val filtered = eGroups.map { eGroup ->
eGroup.copy(numbers = eGroup.numbers.filter { eNumber ->
eNumber.number.contains(query, ignoreCase = true)
})
}.filter { it.numbers.isNotEmpty() }
return filtered
}
} }

View File

@ -7,6 +7,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import cafe.adriel.voyager.core.model.rememberNavigatorScreenModel import cafe.adriel.voyager.core.model.rememberNavigatorScreenModel
@ -38,18 +39,14 @@ object ListMain : Tab {
val screenModel = navigator.rememberNavigatorScreenModel { ListScreenModel() } val screenModel = navigator.rememberNavigatorScreenModel { ListScreenModel() }
val state by screenModel.state.collectAsState() val state by screenModel.state.collectAsState()
val searchText = rememberSaveable { mutableStateOf("") }
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
Scaffold( Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
when (val s = state) { Search(text = searchText)
is ListScreenModel.State.Result -> {
val ungroupedENumbers = s.eNumbers.flatMap { it.numbers }
Search(ungroupedENumbers)
}
else -> Unit
}
} }
) { innerPadding -> ) { innerPadding ->
Column( Column(
@ -57,7 +54,7 @@ object ListMain : Tab {
) { ) {
when (val s = state) { when (val s = state) {
is ListScreenModel.State.Loading -> LoadingScreen("E Numbers").Content() is ListScreenModel.State.Loading -> LoadingScreen("E Numbers").Content()
is ListScreenModel.State.Result -> ENumberList(s.eNumbers).Content() is ListScreenModel.State.Result -> ENumberList(s.eNumbers, searchText = searchText).Content()
} }
} }
} }