search: add a type filter bar and share the search field

Add a filter chip bar above the keyboard to toggle songs, albums, artists
and playlists independently, all on by default and scrolling when it
overflows. Extract one compact 48dp search field and use it in both the
cross-library screen and the library tabs.
This commit is contained in:
austinried
2026-10-04 00:30:07 +00:00
parent 12ad62813e
commit 3bef469acc
4 changed files with 210 additions and 80 deletions
@@ -49,10 +49,10 @@ class SearchScreenTest {
}
}
composeRule.onNodeWithText("Songs").assertIsDisplayed()
composeRule.onNodeWithText("Albums").assertIsDisplayed()
composeRule.onNodeWithText("Artists").assertIsDisplayed()
composeRule.onNodeWithText("Playlists").assertIsDisplayed()
composeRule.onNodeWithText("Road Song").assertIsDisplayed()
composeRule.onNodeWithText("Road Album").assertIsDisplayed()
composeRule.onNodeWithText("Road Artist").assertIsDisplayed()
composeRule.onNodeWithText("Road Trip").assertIsDisplayed()
composeRule.onNodeWithText("Road Song").performClick()
composeRule.onNodeWithText("Road Album").performClick()
@@ -107,6 +107,46 @@ class SearchScreenTest {
composeRule.onNodeWithText("Road Trip").assertIsDisplayed()
}
@Test
fun disablingATypeHidesItsSection() {
composeRule.setContent {
SubtracksTheme {
SearchScreen(
query = "road",
onQueryChange = {},
results =
SearchResults(
albums = listOf(album("al-1", "Road Album")),
songs = listOf(AlbumSongItem(song("s1", "Road Song"), coverArt = null)),
),
filters = setOf(SearchFilter.Albums),
)
}
}
composeRule.onNodeWithText("Road Album").assertIsDisplayed()
composeRule.onNodeWithText("Road Song").assertDoesNotExist()
}
@Test
fun tappingAFilterChipTogglesIt() {
var toggled: SearchFilter? = null
composeRule.setContent {
SubtracksTheme {
SearchScreen(
query = "ro",
onQueryChange = {},
results = SearchResults(),
onToggleFilter = { toggled = it },
)
}
}
composeRule.onNodeWithText("Playlists").performClick()
assertEquals(SearchFilter.Playlists, toggled)
}
private fun album(
id: String,
name: String,