From d038a33b36cf53cc484ba04fdd23d777a88807db Mon Sep 17 00:00:00 2001 From: austinried <4966622+austinried@users.noreply.github.com> Date: Mon, 19 Oct 2026 14:21:51 +0000 Subject: [PATCH] ui: close the list search on back --- .../com/subtracks/ui/library/LibraryScreen.kt | 11 ++++-- .../com/subtracks/ui/LibraryScreenTest.kt | 39 +++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt b/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt index c7292728..1429ad13 100644 --- a/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/library/LibraryScreen.kt @@ -1,5 +1,6 @@ package com.subtracks.ui.library +import androidx.activity.compose.BackHandler import androidx.annotation.StringRes import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.Canvas @@ -429,9 +430,14 @@ fun LibraryScreen( var searchActive by rememberSaveable { mutableStateOf(false) } var topRequest by remember { mutableIntStateOf(0) } val searchFocus = remember { FocusRequester() } + val closeSearch = { + searchActive = false + onSearchChange("") + } // Search mode is left open so the typed query survives; MainNavigation dismisses the keyboard. DismissOnRequest(dismissals) { showOptions = false } + BackHandler(enabled = searchActive, onBack = closeSearch) LaunchedEffect(pagerState) { snapshotFlow { pagerState.settledPage }.collect { page -> @@ -594,10 +600,7 @@ fun LibraryScreen( SearchField( value = search, onValueChange = onSearchChange, - onClose = { - searchActive = false - onSearchChange("") - }, + onClose = closeSearch, focusRequester = searchFocus, modifier = Modifier diff --git a/app/src/test/kotlin/com/subtracks/ui/LibraryScreenTest.kt b/app/src/test/kotlin/com/subtracks/ui/LibraryScreenTest.kt index 9d29b19f..3cd0a327 100644 --- a/app/src/test/kotlin/com/subtracks/ui/LibraryScreenTest.kt +++ b/app/src/test/kotlin/com/subtracks/ui/LibraryScreenTest.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.pager.PagerState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule +import androidx.compose.ui.test.onAllNodesWithContentDescription import androidx.compose.ui.test.onAllNodesWithTag import androidx.compose.ui.test.onAllNodesWithText import androidx.compose.ui.test.onNodeWithContentDescription @@ -20,6 +21,7 @@ import androidx.paging.LoadStates import androidx.paging.PagingData import androidx.test.ext.junit.runners.AndroidJUnit4 import com.github.takahirom.roborazzi.RobolectricDeviceQualifiers +import com.subtracks.R import com.subtracks.data.model.Album import com.subtracks.data.model.Artist import com.subtracks.data.model.Playlist @@ -32,6 +34,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOf import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test @@ -272,6 +275,42 @@ class LibraryScreenTest { composeRule.waitForIdle() } + @Test + fun backClosesTheListSearchInsteadOfLeavingTheApp() { + val search = mutableStateOf("xyz") + composeRule.setContent { + SubtracksTheme { + LibraryScreen( + selectedTab = LibraryTab.Albums, + onTabSelected = {}, + albums = remember { flowOf(PagingData.from(albums())) }, + artists = remember { flowOf(PagingData.empty()) }, + playlists = remember { flowOf(PagingData.empty()) }, + coverArt = { _, _ -> null }, + onAlbumClick = {}, + onArtistClick = {}, + onPlaylistClick = {}, + onSync = {}, + onOpenSettings = {}, + search = search.value, + onSearchChange = { search.value = it }, + ) + } + } + + val closeLabel = composeRule.activity.getString(R.string.close_search) + composeRule.waitUntil(timeoutMillis = 5_000) { + composeRule.onAllNodesWithContentDescription(closeLabel).fetchSemanticsNodes().isNotEmpty() + } + + composeRule.runOnIdle { composeRule.activity.onBackPressedDispatcher.onBackPressed() } + composeRule.waitForIdle() + + assertEquals("back should clear the list search", "", search.value) + composeRule.onNodeWithContentDescription(closeLabel).assertDoesNotExist() + assertFalse("back should not leave the app", composeRule.activity.isFinishing) + } + @Test fun theTabRowReflowsInOneDirectionDuringASwitch() { val pagerState = PagerState(currentPage = 1, pageCount = { LibraryTab.entries.size })