Skip to content

Commit

Permalink
Merge pull request #2 from hyuwah/feature/recent-search-query
Browse files Browse the repository at this point in the history
Feature: recent search query
  • Loading branch information
hyuwah authored Sep 19, 2023
2 parents c893a20 + 92b1ef9 commit d1da00a
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import dev.hyuwah.imusic.features.search.domain.model.SearchModel
import dev.hyuwah.imusic.features.search.domain.model.SearchResultModel
import dev.hyuwah.imusic.features.search.domain.model.TrackPlaybackState
import dev.hyuwah.imusic.features.search.presentation.component.MiniPlaybackControl
import dev.hyuwah.imusic.features.search.presentation.component.RecentSearchQueries
import dev.hyuwah.imusic.features.search.presentation.component.SearchResultItem
import dev.hyuwah.imusic.ui.theme.IMusicTheme

Expand Down Expand Up @@ -72,12 +73,12 @@ fun SearchScreen(
searchQuery = it
},
onSearch = {
active = false
if (searchQuery.isNotBlank()) {
onEvent(SearchScreenEvent.Search(it))
onEvent(SearchScreenEvent.Search(it.trim()))
} else {
searchQuery = ""
}
active = false
},
active = active,
onActiveChange = {
Expand Down Expand Up @@ -111,7 +112,26 @@ fun SearchScreen(
.fillMaxWidth()
.padding(12.dp)
) {

RecentSearchQueries(
searchHistories = screenState.searchHistories,
onItemClick = { query ->
if (query != searchQuery) {
searchQuery = query
if (searchQuery.isNotBlank()) {
onEvent(SearchScreenEvent.Search(query))
} else {
searchQuery = ""
}
}
active = false
},
onClearAll = {
onEvent(SearchScreenEvent.ClearRecentSearch)
},
onRemoveItem = { query ->
onEvent(SearchScreenEvent.RemoveRecentSearch(query))
},
)
}
Box(
modifier = Modifier.weight(1f),
Expand Down Expand Up @@ -154,22 +174,6 @@ fun SearchScreen(
}
}
}

with(trackPlaybackState) {
if (playerState != null && playerState != PlayerState.STOPPED) {
MiniPlaybackControl(
modifier = Modifier.align(Alignment.BottomCenter).padding(horizontal = 12.dp, vertical = 16.dp),
track = currentTrack,
playerState = playerState,
seekbarPos = currentPosition,
seekbarDuration = totalDuration,
onSeekbarChanged = { onEvent(SearchScreenEvent.SeekTrackPosition(it)) },
onResumeClicked = { onEvent(SearchScreenEvent.ResumeTrack) },
onPauseClicked = { onEvent(SearchScreenEvent.PauseTrack) }) {
// [enhancement] Open Playback Control Detail
}
}
}
} else {
Text(
text = "No result found for \"$searchQuery\"",
Expand All @@ -196,6 +200,24 @@ fun SearchScreen(
}
}
}

with(trackPlaybackState) {
if (playerState != null && playerState != PlayerState.STOPPED) {
MiniPlaybackControl(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(horizontal = 12.dp, vertical = 16.dp),
track = currentTrack,
playerState = playerState,
seekbarPos = currentPosition,
seekbarDuration = totalDuration,
onSeekbarChanged = { onEvent(SearchScreenEvent.SeekTrackPosition(it)) },
onResumeClicked = { onEvent(SearchScreenEvent.ResumeTrack) },
onPauseClicked = { onEvent(SearchScreenEvent.PauseTrack) }) {
// [enhancement] Open Playback Control Detail
}
}
}
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ sealed interface SearchScreenEvent {
data class SeekTrackPosition(val pos: Long): SearchScreenEvent
data class OnTrackSelected(val selectedTrack: SearchModel) : SearchScreenEvent
data class Search(val query: String) : SearchScreenEvent
data class RemoveRecentSearch(val query: String) : SearchScreenEvent
data object ClearRecentSearch : SearchScreenEvent
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import dev.hyuwah.imusic.features.search.domain.model.SearchResultModel
data class SearchScreenState(
val isLoading: Boolean? = null,
val searchResult: SearchResultModel? = null,
val searchHistories: List<String> = listOf(),
val selectedTrack: SearchModel? = null,
val searchError: ErrorType? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ class SearchViewModel @Inject constructor(
when (event) {
is SearchScreenEvent.Search -> {
search(event.query)
addQueryToRecentSearch(event.query)
}
is SearchScreenEvent.RemoveRecentSearch -> {
val recentQuery = screenState.searchHistories.toMutableList()
recentQuery.remove(event.query)
screenState = screenState.copy(
searchHistories = recentQuery
)
}
SearchScreenEvent.ClearRecentSearch -> {
screenState = screenState.copy(
searchHistories = emptyList()
)
}
is SearchScreenEvent.OnTrackSelected -> {
screenState = screenState.copy(selectedTrack = event.selectedTrack)
Expand Down Expand Up @@ -81,6 +94,20 @@ class SearchViewModel @Inject constructor(
}
}

private fun addQueryToRecentSearch(query: String) {
viewModelScope.launch {
delay(200)
val newHistories = screenState.searchHistories.toMutableList()
if (screenState.searchHistories.contains(query)) {
newHistories.remove(query)
}
newHistories.add(0, query)
screenState = screenState.copy(
searchHistories = newHistories
)
}
}

private fun setMediaControllerCallback() {
playbackControllerUseCase.setMediaControllerCallback { playerState, currentTrack, currentPosition, totalDuration ->
trackPlaybackState = trackPlaybackState.copy(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package dev.hyuwah.imusic.features.search.presentation.component

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.DeleteSweep
import androidx.compose.material.icons.filled.History
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

@Composable
fun RecentSearchQueries(
modifier: Modifier = Modifier,
searchHistories: List<String>,
onItemClick: (query: String) -> Unit,
onRemoveItem: (query: String) -> Unit,
onClearAll: () -> Unit
) {
if (searchHistories.isNotEmpty()) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(start = 20.dp, end = 20.dp, top = 12.dp, bottom = 8.dp)
) {
Text(
text = "Recent Search",
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.onSurface
)
IconButton(onClick = { onClearAll() }) {
Icon(
imageVector = Icons.Default.DeleteSweep,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
LazyColumn {
items(searchHistories) { query ->
ListItem(
headlineContent = {
Text(text = query)
},
leadingContent = {
Icon(imageVector = Icons.Default.History, contentDescription = null)
},
trailingContent = {
IconButton(onClick = { onRemoveItem(query) }) {
Icon(imageVector = Icons.Default.Delete, contentDescription = null)
}
},
modifier = Modifier.clickable {
onItemClick(query)
})
}
}
}
}

0 comments on commit d1da00a

Please sign in to comment.