diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 08b32826e..000000000 --- a/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/debug/res/drawable-v24/ic_launcher_foreground.xml b/app/src/debug/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index de78f6455..000000000 --- a/app/src/debug/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - diff --git a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml deleted file mode 100644 index bbd3e0212..000000000 --- a/app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml new file mode 100644 index 000000000..bb857a700 --- /dev/null +++ b/app/src/debug/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Auxio Debug + \ No newline at end of file diff --git a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt index c830b2cf2..6962cbdee 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt @@ -41,6 +41,8 @@ import org.oxycblt.auxio.ui.toColor * search functionality. * FIXME: Heisenleak when navving from search * FIXME: Heisenleak on older versions + * TODO: Filtering & Search order upgrades + * TODO: Show result counts? */ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener { diff --git a/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt b/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt index 68b254806..e9b81c44f 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryViewModel.kt @@ -61,44 +61,80 @@ class LibraryViewModel : ViewModel(), SettingsManager.Callback { return } - // Search MusicStore for all the items [Artists, Albums, Songs] that contain - // the query, and update the LiveData with those items. This is done on a separate - // thread as it can be a very long operation for large music libraries. viewModelScope.launch { val combined = mutableListOf() - val children = mDisplayMode.getChildren() - // If the Library DisplayMode supports it, include artists / genres in the search. - if (children.contains(DisplayMode.SHOW_GENRES)) { - val genres = musicStore.genres.filter { it.name.contains(query, true) } - - if (genres.isNotEmpty()) { - combined.add(Header(name = context.getString(R.string.label_genres))) - combined.addAll(genres) + // Searching is done in a different order depending on which items are being shown + // E.G If albums are being shown, then they will be the first items on the list. + when (mDisplayMode) { + DisplayMode.SHOW_GENRES -> { + searchForGenres(combined, query, context) + searchForArtists(combined, query, context) + searchForAlbums(combined, query, context) } - } - if (children.contains(DisplayMode.SHOW_ARTISTS)) { - val artists = musicStore.artists.filter { it.name.contains(query, true) } - - if (artists.isNotEmpty()) { - combined.add(Header(name = context.getString(R.string.label_artists))) - combined.addAll(artists) + DisplayMode.SHOW_ARTISTS -> { + searchForArtists(combined, query, context) - + searchForAlbums(combined, query, context) + searchForGenres(combined, query, context) } - } - // Albums & Songs are always included. - val albums = musicStore.albums.filter { it.name.contains(query, true) } - - if (albums.isNotEmpty()) { - combined.add(Header(name = context.getString(R.string.label_albums))) - combined.addAll(albums) + DisplayMode.SHOW_ALBUMS -> { + searchForAlbums(combined, query, context) + searchForArtists(combined, query, context) + searchForGenres(combined, query, context) + } } mSearchResults.value = combined } } + private fun searchForGenres( + data: MutableList, + query: String, + context: Context + ): MutableList { + val genres = musicStore.genres.filter { it.name.contains(query, true) } + + if (genres.isNotEmpty()) { + data.add(Header(id = 0, name = context.getString(R.string.label_genres))) + data.addAll(genres) + } + + return data + } + + private fun searchForArtists( + data: MutableList, + query: String, + context: Context + ): MutableList { + val artists = musicStore.artists.filter { it.name.contains(query, true) } + + if (artists.isNotEmpty()) { + data.add(Header(id = 1, name = context.getString(R.string.label_artists))) + data.addAll(artists) + } + + return data + } + + private fun searchForAlbums( + data: MutableList, + query: String, + context: Context + ): MutableList { + val albums = musicStore.albums.filter { it.name.contains(query, true) } + + if (albums.isNotEmpty()) { + data.add(Header(id = 2, name = context.getString(R.string.label_albums))) + data.addAll(albums) + } + + return data + } + fun resetQuery() { mSearchResults.value = listOf() } diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt index 8352d50c8..5577cb1d0 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicUtils.kt @@ -10,6 +10,7 @@ import android.widget.TextView import androidx.databinding.BindingAdapter import org.oxycblt.auxio.R import org.oxycblt.auxio.recycler.SortMode +import org.oxycblt.auxio.ui.getPlural /** * List of ID3 genres + Winamp extensions, each index corresponds to their int value. @@ -120,12 +121,8 @@ fun TextView.bindArtistGenre(artist: Artist) { */ @BindingAdapter("artistCounts") fun TextView.bindArtistCounts(artist: Artist) { - val albums = context.resources.getQuantityString( - R.plurals.format_album_count, artist.albums.size, artist.albums.size - ) - val songs = context.resources.getQuantityString( - R.plurals.format_song_count, artist.songs.size, artist.songs.size - ) + val albums = context.getPlural(R.plurals.format_album_count, artist.albums.size) + val songs = context.getPlural(R.plurals.format_song_count, artist.songs.size) text = context.getString(R.string.format_double_counts, albums, songs) } @@ -138,10 +135,7 @@ fun TextView.bindAllAlbumDetails(album: Album) { text = context.getString( R.string.format_double_info, album.year.toYear(context), - context.resources.getQuantityString( - R.plurals.format_song_count, - album.songs.size, album.songs.size - ), + context.getPlural(R.plurals.format_song_count, album.songs.size), album.totalDuration ) } @@ -154,10 +148,7 @@ fun TextView.bindAlbumInfo(album: Album) { text = context.getString( R.string.format_info, album.artist.name, - context.resources.getQuantityString( - R.plurals.format_song_count, - album.songs.size, album.songs.size - ) + context.getPlural(R.plurals.format_song_count, album.songs.size), ) } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt index 16b8de562..ed9a1f04b 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt @@ -20,14 +20,17 @@ import org.oxycblt.auxio.settings.SettingsManager import kotlin.random.Random /** - * Master class for the playback state. This should ***not*** be used outside of the playback module. + * Master class (and possible god object) for the playback state. + * + * This should ***NOT*** be used outside of the playback module. * - If you want to use the playback state in the UI, use [org.oxycblt.auxio.playback.PlaybackViewModel]. * - If you want to use the playback state with the ExoPlayer instance or system-side things, * use [org.oxycblt.auxio.playback.PlaybackService]. * * All access should be done with [PlaybackStateManager.getInstance]. * @author OxygenCobalt - * // TODO: Sort queues + * + * TODO: Sort queues */ class PlaybackStateManager private constructor() { // Playback diff --git a/app/src/main/java/org/oxycblt/auxio/recycler/CenterSmoothScroller.kt b/app/src/main/java/org/oxycblt/auxio/recycler/CenterSmoothScroller.kt index 419bbc829..8dea77946 100644 --- a/app/src/main/java/org/oxycblt/auxio/recycler/CenterSmoothScroller.kt +++ b/app/src/main/java/org/oxycblt/auxio/recycler/CenterSmoothScroller.kt @@ -3,6 +3,11 @@ package org.oxycblt.auxio.recycler import android.content.Context import androidx.recyclerview.widget.LinearSmoothScroller +/** + * [LinearSmoothScroller] subclass that centers the item on the screen instead of snapping to the + * top or bottom. + * @author OxygenCobalt + */ class CenterSmoothScroller(context: Context, target: Int) : LinearSmoothScroller(context) { init { targetPosition = target diff --git a/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt b/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt index 493b1e4a7..bb3810639 100644 --- a/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt @@ -126,9 +126,8 @@ class SongsFragment : Fragment(), SearchView.OnQueryTextListener { if (isLandscape(resources)) { val spans = getLandscapeSpans(resources) - layoutManager = GridLayoutManager(requireContext(), GridLayoutManager.VERTICAL).also { - it.spanCount = spans - it.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { + layoutManager = GridLayoutManager(requireContext(), spans).apply { + spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { return if (binding.songRecycler.adapter == searchAdapter && position == 0) 2 else 1 diff --git a/app/src/main/java/org/oxycblt/auxio/songs/SongsViewModel.kt b/app/src/main/java/org/oxycblt/auxio/songs/SongsViewModel.kt index 7b7cb75b8..af1e81bd7 100644 --- a/app/src/main/java/org/oxycblt/auxio/songs/SongsViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/songs/SongsViewModel.kt @@ -34,17 +34,16 @@ class SongsViewModel : ViewModel() { } viewModelScope.launch { - val songs = mutableListOf().also { - it.addAll(musicStore.songs.filter { it.name.contains(query, true) }.toMutableList()) + val songs = mutableListOf().also { list -> + list.addAll( + musicStore.songs.filter { + it.name.contains(query, true) + }.toMutableList() + ) } if (songs.isNotEmpty()) { - songs.add( - 0, - Header( - name = context.getString(R.string.label_songs) - ) - ) + songs.add(0, Header(id = 0, name = context.getString(R.string.label_songs))) } mSearchResults.value = songs diff --git a/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt b/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt index 48c90bdce..359225458 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt @@ -13,6 +13,7 @@ import android.widget.TextView import android.widget.Toast import androidx.annotation.ColorInt import androidx.annotation.ColorRes +import androidx.annotation.PluralsRes import androidx.appcompat.app.AppCompatActivity import androidx.core.text.HtmlCompat import androidx.fragment.app.Fragment @@ -111,3 +112,13 @@ fun Fragment.requireCompatActivity(): AppCompatActivity { error("Required AppCompatActivity, got ${activity::class.simpleName} instead.") } } + +/** + * Convenience method for getting a plural. + * @param pluralsRes Resource for the plural + * @param value Int value for the plural. + * @return The formatted string requested + */ +fun Context.getPlural(@PluralsRes pluralsRes: Int, value: Int): String { + return resources.getQuantityString(pluralsRes, value, value) +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d1e840884..ffc6540b0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -174,5 +174,4 @@ %s Album %s Albums - \ No newline at end of file