Skip to content

Commit

Permalink
Merge pull request #534 from rahul31124/Fixed-UI-StateLoss-In-BrainzP…
Browse files Browse the repository at this point in the history
…layerSearchScreen

Fixed UI State Loss In BrainzPlayerSearchScreen
  • Loading branch information
07jasjeet authored Jan 28, 2025
2 parents b02c7b0 + 3894327 commit feca7ce
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
Expand All @@ -26,6 +27,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.hilt.navigation.compose.hiltViewModel
import org.listenbrainz.android.R
import org.listenbrainz.android.model.PlayableType
Expand All @@ -46,21 +48,15 @@ fun BrainzPlayerSearchScreen(
deactivate: () -> Unit,
) {
val context = LocalContext.current
var brainzplayerQueryState by remember {
mutableStateOf("")
}

val searchItems = remember {
mutableStateListOf<Song>()
}
val brainzplayerQueryState by viewModel.searchQuery.collectAsState()
val searchItems by viewModel.searchItems.collectAsState()

var error by remember {
mutableStateOf<ResponseError?>(null)
}

fun onDismiss() {
searchItems.clear()
brainzplayerQueryState = ""
viewModel.clearSearchResults()
error = null
deactivate()
}
Expand All @@ -71,20 +67,21 @@ fun BrainzPlayerSearchScreen(
exit = fadeOut()
) {
SearchScreen(
uiState = remember(searchItems, brainzplayerQueryState, error) {
uiState = remember(searchItems, brainzplayerQueryState.text, error) {
SearchUiState(
query = brainzplayerQueryState,
query = brainzplayerQueryState.text,
result = searchItems,
error = error
)
},
onDismiss = ::onDismiss,
onQueryChange = { newValue ->
brainzplayerQueryState = newValue
searchItems.clear()
searchItems.addAll(viewModel.searchSongs(brainzplayerQueryState) ?: emptyList())
onQueryChange = { newValue: String ->
val updatedQuery = TextFieldValue(newValue, selection = brainzplayerQueryState.selection)
viewModel.updateSearchQuery(updatedQuery)
},
onClear = {
viewModel.clearSearchResults()
},
onClear = searchItems::clear,
onErrorShown = { error = null },
placeholderText = "Search your music library"
) {
Expand All @@ -102,12 +99,17 @@ fun BrainzPlayerSearchScreen(
onDropdownSuccess = { context.showToast(it) },
onDropdownError = { error = it }
) {
viewModel.changePlayable(listOf(song), PlayableType.SONG, song.mediaID, 0)
viewModel.changePlayable(
listOf(song),
PlayableType.SONG,
song.mediaID,
0
)
viewModel.playOrToggleSong(song, true)
onDismiss()
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.palette.graphics.Palette
Expand All @@ -23,8 +24,12 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.listenbrainz.android.model.Playable
import org.listenbrainz.android.model.PlayableType
Expand Down Expand Up @@ -67,11 +72,16 @@ class BrainzPlayerViewModel @Inject constructor(
val isPlaying = brainzPlayerServiceConnection.isPlaying
val playButton = brainzPlayerServiceConnection.playButtonState
val repeatMode = brainzPlayerServiceConnection.repeatModeState
var isSearching by mutableStateOf(false)

var playerBackGroundColor by mutableStateOf(Color.Transparent)
private set

private val _searchQuery = MutableStateFlow(TextFieldValue(""))
val searchQuery: StateFlow<TextFieldValue> = _searchQuery

private val _searchItems = MutableStateFlow<List<Song>>(emptyList())
val searchItems: StateFlow<List<Song>> = _searchItems

init {
updatePlayerPosition()
_mediaItems.value = Resource.loading()
Expand All @@ -96,6 +106,16 @@ class BrainzPlayerViewModel @Inject constructor(
currentlyPlaying.items.plus(it)
}
}

viewModelScope.launch {
_searchQuery
.map { it.text }
.debounce(200) // 0.2 Seconds
.distinctUntilChanged()
.collect { query ->
SearchSong(query)
}
}
}

fun updateBackgroundColorForPlayer(
Expand Down Expand Up @@ -191,19 +211,28 @@ class BrainzPlayerViewModel @Inject constructor(
}
}

fun searchSongs(query: String): List<Song>? {
val listToSearch = _mediaItems.value.data
fun updateSearchQuery(newQuery: TextFieldValue) {
_searchQuery.value = newQuery
}

private fun SearchSong(query: String) {
val listToSearch = _mediaItems.value.data
if (query.isEmpty()) {
isSearching = false
_searchItems.value = emptyList()
return
}
val result: List<Song>? = listToSearch?.filter {
it.title.contains(query.trim(), ignoreCase = true)
}
isSearching = true
return result
_searchItems.value = result ?: emptyList()
}

fun clearSearchResults() {
_searchItems.value = emptyList()
_searchQuery.value = TextFieldValue("")
}


fun playOrToggleSong(mediaItem: Song, toggle: Boolean = false) {
val isPrepared = playbackState.value.isPrepared
if (isPrepared && mediaItem.mediaID == currentlyPlayingSong.value.toSong.mediaID) {
Expand Down

0 comments on commit feca7ce

Please sign in to comment.