search: add playlist results
Add playlist results to the search view.
This commit is contained in:
parent
06885ba264
commit
b2e899a211
4 changed files with 43 additions and 19 deletions
|
@ -43,6 +43,7 @@ class SearchAdapter(private val listener: SelectableListListener<Music>) :
|
||||||
is Album -> AlbumViewHolder.VIEW_TYPE
|
is Album -> AlbumViewHolder.VIEW_TYPE
|
||||||
is Artist -> ArtistViewHolder.VIEW_TYPE
|
is Artist -> ArtistViewHolder.VIEW_TYPE
|
||||||
is Genre -> GenreViewHolder.VIEW_TYPE
|
is Genre -> GenreViewHolder.VIEW_TYPE
|
||||||
|
is Playlist -> PlaylistViewHolder.VIEW_TYPE
|
||||||
is BasicHeader -> BasicHeaderViewHolder.VIEW_TYPE
|
is BasicHeader -> BasicHeaderViewHolder.VIEW_TYPE
|
||||||
else -> super.getItemViewType(position)
|
else -> super.getItemViewType(position)
|
||||||
}
|
}
|
||||||
|
@ -53,6 +54,7 @@ class SearchAdapter(private val listener: SelectableListListener<Music>) :
|
||||||
AlbumViewHolder.VIEW_TYPE -> AlbumViewHolder.from(parent)
|
AlbumViewHolder.VIEW_TYPE -> AlbumViewHolder.from(parent)
|
||||||
ArtistViewHolder.VIEW_TYPE -> ArtistViewHolder.from(parent)
|
ArtistViewHolder.VIEW_TYPE -> ArtistViewHolder.from(parent)
|
||||||
GenreViewHolder.VIEW_TYPE -> GenreViewHolder.from(parent)
|
GenreViewHolder.VIEW_TYPE -> GenreViewHolder.from(parent)
|
||||||
|
PlaylistViewHolder.VIEW_TYPE -> PlaylistViewHolder.from(parent)
|
||||||
BasicHeaderViewHolder.VIEW_TYPE -> BasicHeaderViewHolder.from(parent)
|
BasicHeaderViewHolder.VIEW_TYPE -> BasicHeaderViewHolder.from(parent)
|
||||||
else -> error("Invalid item type $viewType")
|
else -> error("Invalid item type $viewType")
|
||||||
}
|
}
|
||||||
|
@ -64,6 +66,7 @@ class SearchAdapter(private val listener: SelectableListListener<Music>) :
|
||||||
is Album -> (holder as AlbumViewHolder).bind(item, listener)
|
is Album -> (holder as AlbumViewHolder).bind(item, listener)
|
||||||
is Artist -> (holder as ArtistViewHolder).bind(item, listener)
|
is Artist -> (holder as ArtistViewHolder).bind(item, listener)
|
||||||
is Genre -> (holder as GenreViewHolder).bind(item, listener)
|
is Genre -> (holder as GenreViewHolder).bind(item, listener)
|
||||||
|
is Playlist -> (holder as PlaylistViewHolder).bind(item, listener)
|
||||||
is BasicHeader -> (holder as BasicHeaderViewHolder).bind(item)
|
is BasicHeader -> (holder as BasicHeaderViewHolder).bind(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.oxycblt.auxio.music.Album
|
||||||
import org.oxycblt.auxio.music.Artist
|
import org.oxycblt.auxio.music.Artist
|
||||||
import org.oxycblt.auxio.music.Genre
|
import org.oxycblt.auxio.music.Genre
|
||||||
import org.oxycblt.auxio.music.Music
|
import org.oxycblt.auxio.music.Music
|
||||||
|
import org.oxycblt.auxio.music.Playlist
|
||||||
import org.oxycblt.auxio.music.Song
|
import org.oxycblt.auxio.music.Song
|
||||||
import org.oxycblt.auxio.music.info.Name
|
import org.oxycblt.auxio.music.info.Name
|
||||||
|
|
||||||
|
@ -33,8 +34,6 @@ import org.oxycblt.auxio.music.info.Name
|
||||||
* Implements the fuzzy-ish searching algorithm used in the search view.
|
* Implements the fuzzy-ish searching algorithm used in the search view.
|
||||||
*
|
*
|
||||||
* @author Alexander Capehart
|
* @author Alexander Capehart
|
||||||
*
|
|
||||||
* TODO: Add playlists
|
|
||||||
*/
|
*/
|
||||||
interface SearchEngine {
|
interface SearchEngine {
|
||||||
/**
|
/**
|
||||||
|
@ -53,12 +52,14 @@ interface SearchEngine {
|
||||||
* @param albums A list of [Album]s, null if empty.
|
* @param albums A list of [Album]s, null if empty.
|
||||||
* @param artists A list of [Artist]s, null if empty.
|
* @param artists A list of [Artist]s, null if empty.
|
||||||
* @param genres A list of [Genre]s, null if empty.
|
* @param genres A list of [Genre]s, null if empty.
|
||||||
|
* @param playlists A list of [Playlist], null if empty.
|
||||||
*/
|
*/
|
||||||
data class Items(
|
data class Items(
|
||||||
val songs: List<Song>?,
|
val songs: List<Song>?,
|
||||||
val albums: List<Album>?,
|
val albums: List<Album>?,
|
||||||
val artists: List<Artist>?,
|
val artists: List<Artist>?,
|
||||||
val genres: List<Genre>?
|
val genres: List<Genre>?,
|
||||||
|
val playlists: List<Playlist>?
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +73,8 @@ class SearchEngineImpl @Inject constructor(@ApplicationContext private val conte
|
||||||
},
|
},
|
||||||
albums = items.albums?.searchListImpl(query),
|
albums = items.albums?.searchListImpl(query),
|
||||||
artists = items.artists?.searchListImpl(query),
|
artists = items.artists?.searchListImpl(query),
|
||||||
genres = items.genres?.searchListImpl(query))
|
genres = items.genres?.searchListImpl(query),
|
||||||
|
playlists = items.playlists?.searchListImpl(query))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search a given [Music] list.
|
* Search a given [Music] list.
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.oxycblt.auxio.list.Item
|
||||||
import org.oxycblt.auxio.list.Sort
|
import org.oxycblt.auxio.list.Sort
|
||||||
import org.oxycblt.auxio.music.*
|
import org.oxycblt.auxio.music.*
|
||||||
import org.oxycblt.auxio.music.device.DeviceLibrary
|
import org.oxycblt.auxio.music.device.DeviceLibrary
|
||||||
|
import org.oxycblt.auxio.music.user.UserLibrary
|
||||||
import org.oxycblt.auxio.playback.PlaybackSettings
|
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||||
import org.oxycblt.auxio.util.logD
|
import org.oxycblt.auxio.util.logD
|
||||||
|
|
||||||
|
@ -73,7 +74,7 @@ constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMusicChanges(changes: MusicRepository.Changes) {
|
override fun onMusicChanges(changes: MusicRepository.Changes) {
|
||||||
if (changes.deviceLibrary && musicRepository.deviceLibrary != null) {
|
if (changes.deviceLibrary || changes.userLibrary) {
|
||||||
search(lastQuery)
|
search(lastQuery)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +91,8 @@ constructor(
|
||||||
lastQuery = query
|
lastQuery = query
|
||||||
|
|
||||||
val deviceLibrary = musicRepository.deviceLibrary
|
val deviceLibrary = musicRepository.deviceLibrary
|
||||||
if (query.isNullOrEmpty() || deviceLibrary == null) {
|
val userLibrary = musicRepository.userLibrary
|
||||||
|
if (query.isNullOrEmpty() || deviceLibrary == null || userLibrary == null) {
|
||||||
logD("Search query is not applicable.")
|
logD("Search query is not applicable.")
|
||||||
_searchResults.value = listOf()
|
_searchResults.value = listOf()
|
||||||
return
|
return
|
||||||
|
@ -101,11 +103,16 @@ constructor(
|
||||||
// Searching is time-consuming, so do it in the background.
|
// Searching is time-consuming, so do it in the background.
|
||||||
currentSearchJob =
|
currentSearchJob =
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_searchResults.value = searchImpl(deviceLibrary, query).also { yield() }
|
_searchResults.value =
|
||||||
|
searchImpl(deviceLibrary, userLibrary, query).also { yield() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun searchImpl(deviceLibrary: DeviceLibrary, query: String): List<Item> {
|
private suspend fun searchImpl(
|
||||||
|
deviceLibrary: DeviceLibrary,
|
||||||
|
userLibrary: UserLibrary,
|
||||||
|
query: String
|
||||||
|
): List<Item> {
|
||||||
val filterMode = searchSettings.searchFilterMode
|
val filterMode = searchSettings.searchFilterMode
|
||||||
|
|
||||||
val items =
|
val items =
|
||||||
|
@ -115,33 +122,40 @@ constructor(
|
||||||
deviceLibrary.songs,
|
deviceLibrary.songs,
|
||||||
deviceLibrary.albums,
|
deviceLibrary.albums,
|
||||||
deviceLibrary.artists,
|
deviceLibrary.artists,
|
||||||
deviceLibrary.genres)
|
deviceLibrary.genres,
|
||||||
|
userLibrary.playlists)
|
||||||
} else {
|
} else {
|
||||||
SearchEngine.Items(
|
SearchEngine.Items(
|
||||||
songs = if (filterMode == MusicMode.SONGS) deviceLibrary.songs else null,
|
songs = if (filterMode == MusicMode.SONGS) deviceLibrary.songs else null,
|
||||||
albums = if (filterMode == MusicMode.ALBUMS) deviceLibrary.albums else null,
|
albums = if (filterMode == MusicMode.ALBUMS) deviceLibrary.albums else null,
|
||||||
artists = if (filterMode == MusicMode.ARTISTS) deviceLibrary.artists else null,
|
artists = if (filterMode == MusicMode.ARTISTS) deviceLibrary.artists else null,
|
||||||
genres = if (filterMode == MusicMode.GENRES) deviceLibrary.genres else null)
|
genres = if (filterMode == MusicMode.GENRES) deviceLibrary.genres else null,
|
||||||
|
playlists =
|
||||||
|
if (filterMode == MusicMode.PLAYLISTS) userLibrary.playlists else null)
|
||||||
}
|
}
|
||||||
|
|
||||||
val results = searchEngine.search(items, query)
|
val results = searchEngine.search(items, query)
|
||||||
|
|
||||||
return buildList {
|
return buildList {
|
||||||
results.artists?.let { artists ->
|
results.artists?.let {
|
||||||
add(BasicHeader(R.string.lbl_artists))
|
add(BasicHeader(R.string.lbl_artists))
|
||||||
addAll(SORT.artists(artists))
|
addAll(SORT.artists(it))
|
||||||
}
|
}
|
||||||
results.albums?.let { albums ->
|
results.albums?.let {
|
||||||
add(BasicHeader(R.string.lbl_albums))
|
add(BasicHeader(R.string.lbl_albums))
|
||||||
addAll(SORT.albums(albums))
|
addAll(SORT.albums(it))
|
||||||
}
|
}
|
||||||
results.genres?.let { genres ->
|
results.playlists?.let {
|
||||||
|
add(BasicHeader(R.string.lbl_playlists))
|
||||||
|
addAll(SORT.playlists(it))
|
||||||
|
}
|
||||||
|
results.genres?.let {
|
||||||
add(BasicHeader(R.string.lbl_genres))
|
add(BasicHeader(R.string.lbl_genres))
|
||||||
addAll(SORT.genres(genres))
|
addAll(SORT.genres(it))
|
||||||
}
|
}
|
||||||
results.songs?.let { songs ->
|
results.songs?.let {
|
||||||
add(BasicHeader(R.string.lbl_songs))
|
add(BasicHeader(R.string.lbl_songs))
|
||||||
addAll(SORT.songs(songs))
|
addAll(SORT.songs(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,7 +172,7 @@ constructor(
|
||||||
MusicMode.ALBUMS -> R.id.option_filter_albums
|
MusicMode.ALBUMS -> R.id.option_filter_albums
|
||||||
MusicMode.ARTISTS -> R.id.option_filter_artists
|
MusicMode.ARTISTS -> R.id.option_filter_artists
|
||||||
MusicMode.GENRES -> R.id.option_filter_genres
|
MusicMode.GENRES -> R.id.option_filter_genres
|
||||||
MusicMode.PLAYLISTS -> R.id.option_filter_all // TODO: Handle
|
MusicMode.PLAYLISTS -> R.id.option_filter_playlists
|
||||||
// Null maps to filtering nothing.
|
// Null maps to filtering nothing.
|
||||||
null -> R.id.option_filter_all
|
null -> R.id.option_filter_all
|
||||||
}
|
}
|
||||||
|
@ -175,6 +189,7 @@ constructor(
|
||||||
R.id.option_filter_albums -> MusicMode.ALBUMS
|
R.id.option_filter_albums -> MusicMode.ALBUMS
|
||||||
R.id.option_filter_artists -> MusicMode.ARTISTS
|
R.id.option_filter_artists -> MusicMode.ARTISTS
|
||||||
R.id.option_filter_genres -> MusicMode.GENRES
|
R.id.option_filter_genres -> MusicMode.GENRES
|
||||||
|
R.id.option_filter_playlists -> MusicMode.PLAYLISTS
|
||||||
// Null maps to filtering nothing.
|
// Null maps to filtering nothing.
|
||||||
R.id.option_filter_all -> null
|
R.id.option_filter_all -> null
|
||||||
else -> error("Invalid option ID provided")
|
else -> error("Invalid option ID provided")
|
||||||
|
|
|
@ -28,6 +28,10 @@
|
||||||
android:id="@+id/option_filter_genres"
|
android:id="@+id/option_filter_genres"
|
||||||
android:title="@string/lbl_genres"
|
android:title="@string/lbl_genres"
|
||||||
app:showAsAction="never" />
|
app:showAsAction="never" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/option_filter_playlists"
|
||||||
|
android:title="@string/lbl_playlists"
|
||||||
|
app:showAsAction="never" />
|
||||||
</group>
|
</group>
|
||||||
</menu>
|
</menu>
|
||||||
</item>
|
</item>
|
||||||
|
|
Loading…
Reference in a new issue