Update sorting
Make some changes to the sorting system.
This commit is contained in:
parent
119078fc77
commit
fcc6a7e8d7
8 changed files with 72 additions and 65 deletions
|
|
@ -137,19 +137,27 @@ class AlbumDetailFragment : DetailFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the position and and scroll to a currently playing item.
|
* Scroll to the currently playing item.
|
||||||
*/
|
*/
|
||||||
private fun scrollToPlayingItem() {
|
private fun scrollToPlayingItem() {
|
||||||
// Calculate where the item for the currently played song is, and scroll to there
|
// Calculate where the item for the currently played song is, -1 if it isnt here
|
||||||
val pos = detailModel.albumSortMode.value!!.getSortedSongList(
|
val pos = detailModel.albumSortMode.value!!.getSortedSongList(
|
||||||
detailModel.currentAlbum.value!!.songs
|
detailModel.currentAlbum.value!!.songs
|
||||||
).indexOf(playbackModel.song.value)
|
).indexOf(playbackModel.song.value)
|
||||||
|
|
||||||
if (pos != -1) {
|
if (pos != -1) {
|
||||||
binding.detailRecycler.post {
|
binding.detailRecycler.post {
|
||||||
|
// Make sure to increment the position to make up for the detail header
|
||||||
binding.detailRecycler.layoutManager?.startSmoothScroll(
|
binding.detailRecycler.layoutManager?.startSmoothScroll(
|
||||||
CenterSmoothScroller(requireContext(), pos.inc())
|
CenterSmoothScroller(requireContext(), pos.inc())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// If the recyclerview can scroll, its certain that it will have to scroll to
|
||||||
|
// correctly center the playing item, so make sure that the Toolbar is lifted in
|
||||||
|
// that case.
|
||||||
|
if (binding.detailRecycler.computeVerticalScrollRange() > binding.detailRecycler.height) {
|
||||||
|
binding.detailAppbar.isLifted = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
detailModel.doneWithNavToItem()
|
detailModel.doneWithNavToItem()
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import kotlin.random.Random
|
||||||
*
|
*
|
||||||
* All access should be done with [PlaybackStateManager.getInstance].
|
* All access should be done with [PlaybackStateManager.getInstance].
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
|
* // TODO: Sort queues
|
||||||
*/
|
*/
|
||||||
class PlaybackStateManager private constructor() {
|
class PlaybackStateManager private constructor() {
|
||||||
// Playback
|
// Playback
|
||||||
|
|
@ -675,7 +676,7 @@ class PlaybackStateManager private constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Back the current state into a [PlaybackState] to be saved.
|
* Pack the current state into a [PlaybackState] to be saved.
|
||||||
* @return A [PlaybackState] reflecting the current state.
|
* @return A [PlaybackState] reflecting the current state.
|
||||||
*/
|
*/
|
||||||
private fun packToPlaybackState(): PlaybackState {
|
private fun packToPlaybackState(): PlaybackState {
|
||||||
|
|
@ -696,28 +697,6 @@ class PlaybackStateManager private constructor() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Pack the queue into a list of [QueueItem]s to be saved.
|
|
||||||
* @return A list of packed queue items.
|
|
||||||
*/
|
|
||||||
private fun packQueue(): List<QueueItem> {
|
|
||||||
val unified = mutableListOf<QueueItem>()
|
|
||||||
|
|
||||||
var queueItemId = 0L
|
|
||||||
|
|
||||||
mUserQueue.forEach {
|
|
||||||
unified.add(QueueItem(queueItemId, it.name, it.album.name, true))
|
|
||||||
queueItemId++
|
|
||||||
}
|
|
||||||
|
|
||||||
mQueue.forEach {
|
|
||||||
unified.add(QueueItem(queueItemId, it.name, it.album.name, false))
|
|
||||||
queueItemId++
|
|
||||||
}
|
|
||||||
|
|
||||||
return unified
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unpack the state from a [PlaybackState]
|
* Unpack the state from a [PlaybackState]
|
||||||
* @param playbackState The state to unpack.
|
* @param playbackState The state to unpack.
|
||||||
|
|
@ -742,6 +721,28 @@ class PlaybackStateManager private constructor() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pack the queue into a list of [QueueItem]s to be saved.
|
||||||
|
* @return A list of packed queue items.
|
||||||
|
*/
|
||||||
|
private fun packQueue(): List<QueueItem> {
|
||||||
|
val unified = mutableListOf<QueueItem>()
|
||||||
|
|
||||||
|
var queueItemId = 0L
|
||||||
|
|
||||||
|
mUserQueue.forEach {
|
||||||
|
unified.add(QueueItem(queueItemId, it.name, it.album.name, true))
|
||||||
|
queueItemId++
|
||||||
|
}
|
||||||
|
|
||||||
|
mQueue.forEach {
|
||||||
|
unified.add(QueueItem(queueItemId, it.name, it.album.name, false))
|
||||||
|
queueItemId++
|
||||||
|
}
|
||||||
|
|
||||||
|
return unified
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unpack a list of queue items into a queue & user queue.
|
* Unpack a list of queue items into a queue & user queue.
|
||||||
* @param queueItems The list of [QueueItem]s to unpack.
|
* @param queueItems The list of [QueueItem]s to unpack.
|
||||||
|
|
@ -810,20 +811,14 @@ class PlaybackStateManager private constructor() {
|
||||||
* Create an ordered queue based on an [Album].
|
* Create an ordered queue based on an [Album].
|
||||||
*/
|
*/
|
||||||
private fun orderSongsInAlbum(album: Album): MutableList<Song> {
|
private fun orderSongsInAlbum(album: Album): MutableList<Song> {
|
||||||
return album.songs.sortedBy { it.track }.toMutableList()
|
return SortMode.NUMERIC_DOWN.getSortedSongList(album.songs).toMutableList()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an ordered queue based on an [Artist].
|
* Create an ordered queue based on an [Artist].
|
||||||
*/
|
*/
|
||||||
private fun orderSongsInArtist(artist: Artist): MutableList<Song> {
|
private fun orderSongsInArtist(artist: Artist): MutableList<Song> {
|
||||||
val final = mutableListOf<Song>()
|
return SortMode.NUMERIC_DOWN.getSortedArtistSongList(artist.songs).toMutableList()
|
||||||
|
|
||||||
artist.albums.sortedByDescending { it.year }.forEach { album ->
|
|
||||||
final.addAll(album.songs.sortedBy { it.track })
|
|
||||||
}
|
|
||||||
|
|
||||||
return final
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import org.oxycblt.auxio.music.Song
|
||||||
/**
|
/**
|
||||||
* An enum for the current sorting mode. Contains helper functions to sort lists based
|
* An enum for the current sorting mode. Contains helper functions to sort lists based
|
||||||
* off the given sorting mode.
|
* off the given sorting mode.
|
||||||
|
* TODO: Improve sorting by separating UP/DOWN from what should be sorted (Names, Tracks, etc)
|
||||||
* @property iconRes The icon for this [SortMode]
|
* @property iconRes The icon for this [SortMode]
|
||||||
* @author OxygenCobalt
|
* @author OxygenCobalt
|
||||||
*/
|
*/
|
||||||
|
|
@ -85,6 +86,28 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a sorted list of songs with regards to an artist.
|
||||||
|
* @param songs An unsorted list of songs
|
||||||
|
* @return The sorted list of songs
|
||||||
|
*/
|
||||||
|
fun getSortedArtistSongList(songs: List<Song>): List<Song> {
|
||||||
|
return when (this) {
|
||||||
|
ALPHA_UP -> songs.sortedWith(
|
||||||
|
compareByDescending(String.CASE_INSENSITIVE_ORDER) { it.name }
|
||||||
|
)
|
||||||
|
|
||||||
|
ALPHA_DOWN -> songs.sortedWith(
|
||||||
|
compareBy(String.CASE_INSENSITIVE_ORDER) { it.name }
|
||||||
|
)
|
||||||
|
|
||||||
|
NUMERIC_UP -> songs.sortedWith(compareBy { it.album.year })
|
||||||
|
NUMERIC_DOWN -> songs.sortedWith(compareByDescending { it.album.year })
|
||||||
|
|
||||||
|
else -> songs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a sorted list of BaseModels. Supports alpha + numeric sorting.
|
* Get a sorted list of BaseModels. Supports alpha + numeric sorting.
|
||||||
* @param baseModels An unsorted list of BaseModels.
|
* @param baseModels An unsorted list of BaseModels.
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,8 @@ import org.oxycblt.auxio.playback.state.PlaybackMode
|
||||||
* @param activity [AppCompatActivity] required as both a context and ViewModelStore owner.
|
* @param activity [AppCompatActivity] required as both a context and ViewModelStore owner.
|
||||||
* @param anchor [View] This should be centered around
|
* @param anchor [View] This should be centered around
|
||||||
* @param data [BaseModel] this menu corresponds to
|
* @param data [BaseModel] this menu corresponds to
|
||||||
* @param flag Any extra flags to accompany the data. See [Companion] for more details.
|
* @param flag Any extra flags to accompany the data.
|
||||||
|
* See [FLAG_NONE], [FLAG_IN_ALBUM], [FLAG_IN_ARTIST] and [FLAG_IN_GENRE] for more details.
|
||||||
*/
|
*/
|
||||||
class ActionMenu(
|
class ActionMenu(
|
||||||
activity: AppCompatActivity,
|
activity: AppCompatActivity,
|
||||||
|
|
@ -84,11 +85,13 @@ class ActionMenu(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine what to do when a MenuItem is clicked.
|
||||||
|
*/
|
||||||
private fun onMenuClick(@IdRes id: Int) {
|
private fun onMenuClick(@IdRes id: Int) {
|
||||||
when (id) {
|
when (id) {
|
||||||
R.id.action_play -> {
|
R.id.action_play -> {
|
||||||
when (data) {
|
when (data) {
|
||||||
is Song -> playbackModel.playSong(data, getPlaybackModeFromFlag())
|
|
||||||
is Album -> playbackModel.playAlbum(data, false)
|
is Album -> playbackModel.playAlbum(data, false)
|
||||||
is Artist -> playbackModel.playArtist(data, false)
|
is Artist -> playbackModel.playArtist(data, false)
|
||||||
is Genre -> playbackModel.playGenre(data, false)
|
is Genre -> playbackModel.playGenre(data, false)
|
||||||
|
|
@ -114,21 +117,17 @@ class ActionMenu(
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_queue_add -> {
|
R.id.action_queue_add -> {
|
||||||
val success = when (data) {
|
when (data) {
|
||||||
is Song -> {
|
is Song -> {
|
||||||
playbackModel.addToUserQueue(data)
|
playbackModel.addToUserQueue(data)
|
||||||
true
|
context.getString(R.string.label_queue_added).createToast(context)
|
||||||
}
|
}
|
||||||
is Album -> {
|
is Album -> {
|
||||||
playbackModel.addToUserQueue(data)
|
playbackModel.addToUserQueue(data)
|
||||||
true
|
context.getString(R.string.label_queue_added).createToast(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> false
|
else -> {}
|
||||||
}
|
|
||||||
|
|
||||||
if (success) {
|
|
||||||
context.getString(R.string.label_queue_added).createToast(context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -156,17 +155,6 @@ class ActionMenu(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPlaybackModeFromFlag(): PlaybackMode {
|
|
||||||
return when (flag) {
|
|
||||||
FLAG_NONE -> PlaybackMode.ALL_SONGS
|
|
||||||
FLAG_IN_ALBUM -> PlaybackMode.IN_ALBUM
|
|
||||||
FLAG_IN_ARTIST -> PlaybackMode.IN_ARTIST
|
|
||||||
FLAG_IN_GENRE -> PlaybackMode.IN_GENRE
|
|
||||||
|
|
||||||
else -> PlaybackMode.ALL_SONGS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/** No Flags **/
|
/** No Flags **/
|
||||||
const val FLAG_NONE = -1
|
const val FLAG_NONE = -1
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import android.view.WindowManager
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if we are in the "Irregular" landscape mode [e.g landscape, but nav bar is on the sides]
|
* Check if we are in the "Irregular" landscape mode [e.g landscape, but nav bar is on the sides]
|
||||||
* Used to disable most of edge-to-edge if that's the case, as I cant get it to work on this mode yet.
|
* Used to disable most of edge-to-edge if that's the case, as I cant get it to work on this mode.
|
||||||
* @return True if we are in the irregular landscape mode, false if not.
|
* @return True if we are in the irregular landscape mode, false if not.
|
||||||
*/
|
*/
|
||||||
fun Activity.isIrregularLandscape(): Boolean {
|
fun Activity.isIrregularLandscape(): Boolean {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import kotlin.reflect.KProperty
|
||||||
* A delegate that creates a binding that can be used as a member variable without nullability or
|
* A delegate that creates a binding that can be used as a member variable without nullability or
|
||||||
* memory leaks.
|
* memory leaks.
|
||||||
* @param bindingFactory The ViewBinding inflation method that should be used
|
* @param bindingFactory The ViewBinding inflation method that should be used
|
||||||
* @param onDestroy Any code that should be run when the binding is destroyed.
|
* @param onDestroy Any code that should be run when the binding is destroyed
|
||||||
*/
|
*/
|
||||||
fun <T : ViewBinding> Fragment.memberBinding(
|
fun <T : ViewBinding> Fragment.memberBinding(
|
||||||
bindingFactory: (LayoutInflater) -> T,
|
bindingFactory: (LayoutInflater) -> T,
|
||||||
|
|
|
||||||
|
|
@ -13,19 +13,11 @@ import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
import androidx.annotation.ColorRes
|
import androidx.annotation.ColorRes
|
||||||
import androidx.annotation.MenuRes
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.PopupMenu
|
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import org.oxycblt.auxio.R
|
import org.oxycblt.auxio.R
|
||||||
import org.oxycblt.auxio.detail.DetailViewModel
|
|
||||||
import org.oxycblt.auxio.music.Album
|
|
||||||
import org.oxycblt.auxio.music.Artist
|
|
||||||
import org.oxycblt.auxio.music.Genre
|
|
||||||
import org.oxycblt.auxio.music.Song
|
|
||||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a text color to a [MenuItem]
|
* Apply a text color to a [MenuItem]
|
||||||
|
|
@ -116,6 +108,6 @@ fun Fragment.requireCompatActivity(): AppCompatActivity {
|
||||||
if (activity is AppCompatActivity) {
|
if (activity is AppCompatActivity) {
|
||||||
return activity
|
return activity
|
||||||
} else {
|
} else {
|
||||||
error("Required activity to be AppCompatActivity, however it wasn't.")
|
error("Required AppCompatActivity, got ${activity::class.simpleName} instead.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:id="@+id/detail_appbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:liftOnScroll="true">
|
app:liftOnScroll="true">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue