mirror of
https://github.com/NuvioMedia/NuvioMobile.git
synced 2026-07-26 17:12:16 +00:00
Merge pull request #1610 from Laskco/feat/cloud-library-search
feat(library): Search the cloud library
This commit is contained in:
commit
2fda777249
2 changed files with 64 additions and 1 deletions
|
|
@ -1658,6 +1658,7 @@
|
|||
<string name="cloud_library_playable_file_count">%1$d playable files</string>
|
||||
<string name="cloud_library_provider_all">All</string>
|
||||
<string name="cloud_library_refresh">Refresh cloud library</string>
|
||||
<string name="cloud_library_search_label">Search cloud library</string>
|
||||
<string name="cloud_library_select_provider">Select provider</string>
|
||||
<string name="cloud_library_select_type">Select type</string>
|
||||
<string name="cloud_library_status_ready">Ready to play</string>
|
||||
|
|
|
|||
|
|
@ -31,15 +31,18 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.InsertDriveFile
|
||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.rounded.Close
|
||||
import androidx.compose.material.icons.rounded.GridView
|
||||
import androidx.compose.material.icons.rounded.PlayArrow
|
||||
import androidx.compose.material.icons.rounded.Refresh
|
||||
import androidx.compose.material.icons.rounded.Search
|
||||
import androidx.compose.material.icons.rounded.ViewAgenda
|
||||
import com.nuvio.app.core.ui.NuvioLoadingIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -132,6 +135,7 @@ fun LibraryScreen(
|
|||
}
|
||||
var selectedProviderId by rememberSaveable { mutableStateOf<String?>(null) }
|
||||
var selectedTypeName by rememberSaveable { mutableStateOf<String?>(null) }
|
||||
var cloudSearchQuery by rememberSaveable { mutableStateOf("") }
|
||||
val selectedType = remember(selectedTypeName) {
|
||||
selectedTypeName?.let { runCatching { CloudLibraryItemType.valueOf(it) }.getOrNull() }
|
||||
}
|
||||
|
|
@ -305,6 +309,11 @@ fun LibraryScreen(
|
|||
selectedProviderId = selectedProviderId,
|
||||
selectedType = selectedType,
|
||||
selectedCloudItemKey = selectedCloudItemKey,
|
||||
searchQuery = cloudSearchQuery,
|
||||
onSearchQueryChange = {
|
||||
cloudSearchQuery = it
|
||||
selectedCloudItemKey = null
|
||||
},
|
||||
onProviderSelected = {
|
||||
selectedProviderId = it
|
||||
selectedTypeName = null
|
||||
|
|
@ -443,6 +452,8 @@ private fun LazyListScope.cloudLibraryContent(
|
|||
selectedProviderId: String?,
|
||||
selectedType: CloudLibraryItemType?,
|
||||
selectedCloudItemKey: String?,
|
||||
searchQuery: String,
|
||||
onSearchQueryChange: (String) -> Unit,
|
||||
onProviderSelected: (String?) -> Unit,
|
||||
onTypeSelected: (CloudLibraryItemType?) -> Unit,
|
||||
onItemSelected: (CloudLibraryItem) -> Unit,
|
||||
|
|
@ -488,8 +499,19 @@ private fun LazyListScope.cloudLibraryContent(
|
|||
.distinct()
|
||||
.sortedBy { type -> type.ordinal }
|
||||
val effectiveSelectedType = selectedType?.takeIf { type -> type in availableTypes }
|
||||
val filteredItems = providerItems
|
||||
val typeFilteredItems = providerItems
|
||||
.filter { item -> effectiveSelectedType == null || item.type == effectiveSelectedType }
|
||||
// Local filter over the already-loaded library. Matches the item name or any of its
|
||||
// file names, since the useful identifier is often in the filename, not the title.
|
||||
val trimmedQuery = searchQuery.trim()
|
||||
val filteredItems = if (trimmedQuery.isEmpty()) {
|
||||
typeFilteredItems
|
||||
} else {
|
||||
typeFilteredItems.filter { item ->
|
||||
item.name.contains(trimmedQuery, ignoreCase = true) ||
|
||||
item.files.any { file -> file.name.contains(trimmedQuery, ignoreCase = true) }
|
||||
}
|
||||
}
|
||||
val selectedItem = filteredItems.firstOrNull { it.stableKey == selectedCloudItemKey }
|
||||
|
||||
if (selectedItem != null) {
|
||||
|
|
@ -514,6 +536,14 @@ private fun LazyListScope.cloudLibraryContent(
|
|||
)
|
||||
}
|
||||
|
||||
item(key = "cloud-library-search") {
|
||||
CloudLibrarySearchField(
|
||||
query = searchQuery,
|
||||
onQueryChange = onSearchQueryChange,
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
)
|
||||
}
|
||||
|
||||
uiState.providers
|
||||
.filter { providerState -> selectedProviderId == null || providerState.providerId == selectedProviderId }
|
||||
.filter { providerState -> !providerState.errorMessage.isNullOrBlank() && providerState.items.isEmpty() }
|
||||
|
|
@ -557,6 +587,38 @@ private fun LazyListScope.cloudLibraryContent(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CloudLibrarySearchField(
|
||||
query: String,
|
||||
onQueryChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
OutlinedTextField(
|
||||
value = query,
|
||||
onValueChange = onQueryChange,
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
singleLine = true,
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
placeholder = { Text(stringResource(Res.string.cloud_library_search_label)) },
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Search,
|
||||
contentDescription = null,
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
if (query.isNotEmpty()) {
|
||||
IconButton(onClick = { onQueryChange("") }) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Close,
|
||||
contentDescription = stringResource(Res.string.compose_search_clear),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private fun LazyListScope.cloudLibrarySkeletonItems() {
|
||||
item(key = "cloud-library-skeleton-toolbar") {
|
||||
CloudLibrarySkeletonToolbar(
|
||||
|
|
|
|||
Loading…
Reference in a new issue