From f1caf335e11be6bdcc2b5fc63d5cfb8bb7a291a9 Mon Sep 17 00:00:00 2001 From: Syer10 Date: Fri, 7 May 2021 22:30:15 -0400 Subject: [PATCH] Implement searchbar + initial extension search --- .../ca/gosyer/ui/base/components/Toolbar.kt | 96 ++++++++++++------- .../ca/gosyer/ui/extensions/ExtensionsMenu.kt | 14 ++- .../ui/extensions/ExtensionsMenuViewModel.kt | 19 +++- 3 files changed, 89 insertions(+), 40 deletions(-) diff --git a/src/main/kotlin/ca/gosyer/ui/base/components/Toolbar.kt b/src/main/kotlin/ca/gosyer/ui/base/components/Toolbar.kt index 933f38da..b8a131d8 100644 --- a/src/main/kotlin/ca/gosyer/ui/base/components/Toolbar.kt +++ b/src/main/kotlin/ca/gosyer/ui/base/components/Toolbar.kt @@ -6,23 +6,40 @@ package ca.gosyer.ui.base.components +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField import androidx.compose.material.AppBarDefaults +import androidx.compose.material.Card import androidx.compose.material.Icon import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface import androidx.compose.material.Text -import androidx.compose.material.TopAppBar +import androidx.compose.material.contentColorFor import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.RectangleShape +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import ca.gosyer.ui.main.Route import com.github.zsoltk.compose.router.BackStack import compose.icons.FontAwesomeIcons @@ -36,19 +53,50 @@ fun Toolbar( closable: Boolean, modifier: Modifier = Modifier, actions: @Composable RowScope.() -> Unit = {}, - backgroundColor: Color = MaterialTheme.colors.primary, // CustomColors.current.bars, - contentColor: Color = MaterialTheme.colors.onPrimary, // CustomColors.current.onBars, + backgroundColor: Color = MaterialTheme.colors.surface, // CustomColors.current.bars, + contentColor: Color = contentColorFor(backgroundColor), // CustomColors.current.onBars, elevation: Dp = AppBarDefaults.TopAppBarElevation, search: ((String) -> Unit)? = null ) { val searchText = remember { mutableStateOf("") } - Surface(Modifier.fillMaxWidth().height(32.dp), elevation = 2.dp) { - TopAppBar( - { - Text(name) - }, - modifier, - actions = @Composable { + Surface( + modifier = modifier, + elevation = elevation, + shape = RectangleShape, + color = backgroundColor, + contentColor = contentColor + ) { + Row( + Modifier.fillMaxWidth().padding(AppBarDefaults.ContentPadding).height(56.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text(name, fontSize = 24.sp) + if (search != null) { + Card( + Modifier.fillMaxHeight() + .width(300.dp) + .padding(8.dp), + shape = RoundedCornerShape(4.dp), + elevation = 2.dp, + border = BorderStroke(1.dp, MaterialTheme.colors.primary) + ) { + Box(Modifier.fillMaxSize().padding(8.dp), Alignment.CenterStart) { + BasicTextField( + searchText.value, + onValueChange = { + searchText.value = it + search(it) + }, + singleLine = true, + modifier = Modifier.fillMaxWidth(), + textStyle = TextStyle(contentColor, 18.sp), + cursorBrush = SolidColor(contentColor.copy(alpha = 0.50F)) + ) + } + } + } + Row { actions() if (closable) { IconButton( @@ -56,34 +104,10 @@ fun Toolbar( router?.pop() } ) { - Icon(FontAwesomeIcons.Regular.WindowClose, "close") + Icon(FontAwesomeIcons.Regular.WindowClose, "close", Modifier.size(52.dp)) } } - }, - backgroundColor = backgroundColor, - contentColor = contentColor, - elevation = elevation - ) - /*Row(Modifier.fillMaxSize(), horizontalArrangement = Arrangement.SpaceBetween) { - Text(name, fontSize = 24.sp) - if (search != null) { - BasicTextField( - searchText.value, - onValueChange = { - searchText.value = it - search(it) - } - ) } - if (closable) { - IconButton( - onClick = { - router?.pop() - } - ) { - Icon(FontAwesomeIcons.Regular.WindowClose, "close", Modifier.size(32.dp)) - } - } - }*/ + } } } diff --git a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt index d7612607..66f3e422 100644 --- a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt +++ b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenu.kt @@ -43,6 +43,7 @@ import androidx.compose.ui.unit.sp import ca.gosyer.data.models.Extension import ca.gosyer.ui.base.components.KtorImage import ca.gosyer.ui.base.components.LoadingScreen +import ca.gosyer.ui.base.components.Toolbar import ca.gosyer.ui.base.vm.viewModel import ca.gosyer.util.compose.ThemedWindow @@ -61,7 +62,7 @@ fun ExtensionsMenu() { val serverUrl by vm.serverUrl.collectAsState() Box(Modifier.fillMaxSize().background(MaterialTheme.colors.background)) { - if (extensions.isEmpty()) { + if (isLoading) { LoadingScreen(isLoading) } else { val state = rememberLazyListState() @@ -69,6 +70,15 @@ fun ExtensionsMenu() { Box(Modifier.fillMaxSize()) { LazyColumn(Modifier.fillMaxSize().padding(end = 12.dp), state) { + item { + Toolbar( + "Extensions", + closable = false, + search = { + vm.search(it) + } + ) + } items(extensions) { extension -> ExtensionItem( extension, @@ -87,7 +97,7 @@ fun ExtensionsMenu() { modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight(), adapter = rememberScrollbarAdapter( scrollState = state, - itemCount = itemCount, + itemCount = itemCount + 1, // Plus toolbar, averageItemSize = 37.dp // TextBox height + Spacer height ) ) diff --git a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt index 6d7dff5c..259c7e12 100644 --- a/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt +++ b/src/main/kotlin/ca/gosyer/ui/extensions/ExtensionsMenuViewModel.kt @@ -27,6 +27,8 @@ class ExtensionsMenuViewModel @Inject constructor( val serverUrl = serverPreferences.server().stateIn(scope) + private lateinit var extensionList: List + private val _extensions = MutableStateFlow(emptyList()) val extensions = _extensions.asStateFlow() @@ -43,8 +45,8 @@ class ExtensionsMenuViewModel @Inject constructor( try { _isLoading.value = true val enabledLangs = extensionPreferences.languages().get() - val extensions = extensionHandler.getExtensionList() - _extensions.value = extensions.filter { it.lang in enabledLangs }.sortedWith(compareBy({ it.lang }, { it.pkgName })) + extensionList = extensionHandler.getExtensionList() + _extensions.value = extensionList.filter { it.lang in enabledLangs }.sortedWith(compareBy({ it.lang }, { it.pkgName })) } catch (e: Exception) { if (e is CancellationException) throw e } finally { @@ -75,4 +77,17 @@ class ExtensionsMenuViewModel @Inject constructor( getExtensions() } } + + fun search(searchQuery: String) { + if (searchQuery.isBlank()) { + _extensions.value = extensionList + } else { + val queries = searchQuery.split(" ") + val extensions = extensionList.toMutableList() + queries.forEach { query -> + extensions.removeIf { !it.name.contains(query, true) } + } + _extensions.value = extensions.toList() + } + } }