From 046ea22a5021902e179d12009ce172129fed85f1 Mon Sep 17 00:00:00 2001 From: manum45 Date: Mon, 31 Aug 2026 23:25:30 +0200 Subject: [PATCH 1/6] add reverse sorting option --- .../gramophone/ui/adapters/ArtistAdapter.kt | 38 +-- .../ui/adapters/BaseDecorAdapter.kt | 231 +++++++++++++----- .../ui/adapters/DetailedFolderAdapter.kt | 23 +- .../gramophone/ui/adapters/SongAdapter.kt | 7 +- .../gramophone/ui/adapters/Sorter.kt | 44 +++- .../uk/akane/libphonograph/items/FileNode.kt | 2 +- .../main/res/layout/item_popup_divider.xml | 7 + app/src/main/res/layout/item_sort_radio.xml | 27 ++ app/src/main/res/layout/switch_item.xml | 29 +++ app/src/main/res/menu/sort_menu.xml | 8 +- app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/strings.xml | 2 + 12 files changed, 317 insertions(+), 102 deletions(-) create mode 100644 app/src/main/res/layout/item_popup_divider.xml create mode 100644 app/src/main/res/layout/item_sort_radio.xml create mode 100644 app/src/main/res/layout/switch_item.xml diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/ArtistAdapter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/ArtistAdapter.kt index 97a0b41f90..5155c43d11 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/ArtistAdapter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/ArtistAdapter.kt @@ -18,7 +18,6 @@ package org.akanework.gramophone.ui.adapters import android.content.SharedPreferences -import android.view.MenuItem import androidx.appcompat.widget.PopupMenu import androidx.core.content.edit import androidx.core.view.iterator @@ -157,31 +156,20 @@ class ArtistAdapter( artistAdapter: ArtistAdapter ) : BaseDecorAdapter(artistAdapter, R.plurals.artists) { - override fun onSortButtonPressed(popupMenu: PopupMenu) { - popupMenu.menu.findItem(R.id.album_artist_checkbox).isVisible = true - popupMenu.menu.findItem(R.id.album_artist_checkbox).isChecked = adapter.isAlbumArtist - } - - override fun onExtraMenuButtonPressed(menuItem: MenuItem): Boolean { - return when (menuItem.itemId) { - R.id.album_artist_checkbox -> { - menuItem.isChecked = !menuItem.isChecked - adapter.isAlbumArtist = menuItem.isChecked - - adapter.prefs.edit { - putBoolean( - "isDisplayingAlbumArtist", - adapter.isAlbumArtist - ) - } - adapter.liveDataAgent.value = - if (adapter.isAlbumArtist) adapter.mainActivity.reader.albumArtistListFlow else - adapter.mainActivity.reader.artistListFlow - true + override fun onSortPopupPopulating(items: MutableList) { + items.add(PopupItem.Switch( + R.id.album_artist_checkbox, + context.getString(R.string.album_artist), + adapter.isAlbumArtist + ) { isChecked -> + adapter.isAlbumArtist = isChecked + adapter.prefs.edit { + putBoolean("isDisplayingAlbumArtist", isChecked) } - - else -> false - } + adapter.liveDataAgent.value = + if (isChecked) adapter.mainActivity.reader.albumArtistListFlow else + adapter.mainActivity.reader.artistListFlow + }) } } diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt index c479e7d59b..b74bfbe23c 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt @@ -18,17 +18,21 @@ package org.akanework.gramophone.ui.adapters import android.content.Context -import android.view.MenuItem +import android.view.Gravity +import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.RadioButton import android.widget.TextView -import androidx.appcompat.widget.PopupMenu +import androidx.appcompat.widget.ListPopupWindow import androidx.core.content.edit import androidx.core.content.pm.ShortcutManagerCompat import androidx.media3.common.Player.REPEAT_MODE_OFF import androidx.preference.PreferenceManager import androidx.recyclerview.widget.RecyclerView import com.google.android.material.button.MaterialButton +import com.google.android.material.materialswitch.MaterialSwitch import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking import org.akanework.gramophone.R @@ -77,8 +81,12 @@ open class BaseDecorAdapter>( holder.sortButton.visibility = if (adapter.sortType.value != Sorter.Type.None || adapter.canChangeLayout) View.VISIBLE else View.GONE holder.sortButton.setOnClickListener { view -> - val popupMenu = PopupMenu(context, view) - popupMenu.inflate(R.menu.sort_menu) + val listPopupWindow = ListPopupWindow(context) + listPopupWindow.anchorView = view + listPopupWindow.setDropDownGravity(Gravity.END) + listPopupWindow.isModal = true + listPopupWindow.width = context.resources.getDimensionPixelSize(R.dimen.sort_popup_width) + val buttonMap = mapOf( Pair(R.id.natural, Sorter.Type.NaturalOrder), Pair(R.id.name, Sorter.Type.ByTitleAscending), @@ -94,78 +102,111 @@ open class BaseDecorAdapter>( Pair(R.id.mod_date, Sorter.Type.ByModifiedDateDescending), Pair(R.id.file_path, Sorter.Type.ByFilePathAscending) ) + val layoutMap = mapOf( Pair(R.id.list, BaseAdapter.LayoutType.LIST), Pair(R.id.compact_list, BaseAdapter.LayoutType.COMPACT_LIST), Pair(R.id.grid, BaseAdapter.LayoutType.GRID), Pair(R.id.compact_grid, BaseAdapter.LayoutType.COMPACT_GRID) ) - buttonMap.forEach { - popupMenu.menu.findItem(it.key).isVisible = adapter.sortTypes.contains(it.value) - } - layoutMap.forEach { - popupMenu.menu.findItem(it.key).isVisible = adapter.canChangeLayout - } - popupMenu.menu.findItem(R.id.display).isVisible = adapter.canChangeLayout - if (adapter.sortType.value != Sorter.Type.None) { - when (adapter.sortType.value) { - in buttonMap.values -> { - popupMenu.menu.findItem( - buttonMap.entries - .first { it.value == adapter.sortType.value }.key - ).isChecked = true + + val items = mutableListOf() + + // 1. Reverse Toggle + val inverse = Sorter.Type.inverse(adapter.sortType.value) + if (inverse != null) { + val currentSort = adapter.sortType.value + val activeEntry = buttonMap.entries.find { it.value == currentSort || Sorter.Type.inverse(it.value) == currentSort } + val defaultSort = activeEntry?.value ?: Sorter.Type.None + + items.add(PopupItem.Switch( + R.id.reverse_order, + context.getString(R.string.reverse_order), + currentSort != defaultSort && currentSort != Sorter.Type.None + ) { isChecked -> + val activeId = buttonMap.entries.find { + it.value == adapter.sortType.value || Sorter.Type.inverse(it.value) == adapter.sortType.value + }?.key ?: -1 + val baseType = buttonMap[activeId] + if (baseType != null) { + val targetType = if (isChecked) Sorter.Type.inverse(baseType) ?: baseType else baseType + if (adapter.sortType.value != targetType) { + adapter.sort(targetType) + prefs.edit { putString("S" + getAdapterType(adapter).toString(), targetType.toString()) } + } } + }) + items.add(PopupItem.Divider) + } - else -> throw IllegalStateException("Invalid sortType ${adapter.sortType.value.name}") - } + // 2. Extra items (Album Artist etc) + val extraItems = mutableListOf() + onSortPopupPopulating(extraItems) + if (extraItems.isNotEmpty()) { + items.addAll(extraItems) + items.add(PopupItem.Divider) } - if (adapter.canChangeLayout) { - when (adapter.layoutType) { - in layoutMap.values -> { - popupMenu.menu.findItem( - layoutMap.entries - .first { it.value == adapter.layoutType }.key - ).isChecked = true - } - else -> throw IllegalStateException("Invalid layoutType ${adapter.layoutType?.name}") + // 3. Sort Modes + buttonMap.forEach { (resId, type) -> + if (adapter.sortTypes.contains(type)) { + val currentSort = adapter.sortType.value + val isSelected = currentSort == type || Sorter.Type.inverse(type) == currentSort + items.add(PopupItem.Radio( + resId, + context.getString(when (resId) { + R.id.natural -> R.string.natural_order + R.id.name -> R.string.sort_by_name + R.id.artist -> R.string.sort_by_artist + R.id.artist_year -> R.string.sort_by_artist_year + R.id.album -> R.string.sort_by_album + R.id.album_artist -> R.string.sort_by_album_artist + R.id.album_artist_year -> R.string.sort_by_album_artist_year + R.id.album_year -> R.string.sort_by_album_year + R.id.size -> R.string.sort_by_size + R.id.add_date -> R.string.sort_by_add_date + R.id.release_date -> R.string.sort_by_release_date + R.id.mod_date -> R.string.sort_by_modified_date + R.id.file_path -> R.string.sort_by_file_path + else -> 0 + }), + isSelected + ) { + val isReversed = (items.find { it is PopupItem.Switch && it.id == R.id.reverse_order } as? PopupItem.Switch)?.isChecked == true + val targetType = if (isReversed) Sorter.Type.inverse(type) ?: type else type + adapter.sort(targetType) + prefs.edit { putString("S" + getAdapterType(adapter).toString(), targetType.toString()) } + listPopupWindow.dismiss() + }) } } - popupMenu.setOnMenuItemClickListener { menuItem -> - when (menuItem.itemId) { - in buttonMap.keys -> { - if (!menuItem.isChecked) { - adapter.sort(buttonMap[menuItem.itemId]!!) - menuItem.isChecked = true - prefs.edit { - putString( - "S" + getAdapterType(adapter).toString(), - buttonMap[menuItem.itemId].toString() - ) - } - } - true - } - - in layoutMap.keys -> { - if (!menuItem.isChecked) { - adapter.layoutType = layoutMap[menuItem.itemId]!! - menuItem.isChecked = true - prefs.edit { - putString( - "L" + getAdapterType(adapter).toString(), - layoutMap[menuItem.itemId].toString() - ) - } - } - true - } - else -> onExtraMenuButtonPressed(menuItem) + // 4. Layout Modes + if (adapter.canChangeLayout) { + items.add(PopupItem.Divider) + items.add(PopupItem.Header(context.getString(R.string.layout))) + layoutMap.forEach { (resId, type) -> + items.add(PopupItem.Radio( + resId, + context.getString(when (resId) { + R.id.list -> R.string.list + R.id.compact_list -> R.string.compact_list + R.id.grid -> R.string.grid + R.id.compact_grid -> R.string.compact_grid + else -> 0 + }), + adapter.layoutType == type + ) { + adapter.layoutType = type + prefs.edit { putString("L" + getAdapterType(adapter).toString(), type.toString()) } + listPopupWindow.dismiss() + }) } } - onSortButtonPressed(popupMenu) - popupMenu.show() + + val adapter2 = SortPopupAdapter(context, items) + listPopupWindow.setAdapter(adapter2) + listPopupWindow.show() } holder.playAll.setOnClickListener { if (adapter is SongAdapter) { @@ -296,8 +337,7 @@ open class BaseDecorAdapter>( recyclerView?.startSmoothScrollCompat(smoothScroller) } - protected open fun onSortButtonPressed(popupMenu: PopupMenu) {} - protected open fun onExtraMenuButtonPressed(menuItem: MenuItem): Boolean = false + protected open fun onSortPopupPopulating(items: MutableList) {} override fun getItemCount(): Int = 1 override fun getItemViewType(position: Int): Int = R.layout.general_decor @@ -321,4 +361,69 @@ open class BaseDecorAdapter>( override fun getItemHeightFromZeroTo(to: Int): Int { return if (to > 0) dpHeight else 0 } + + sealed class PopupItem { + object Divider : PopupItem() + data class Header(val title: String) : PopupItem() + data class Radio(val id: Int, val title: String, val isSelected: Boolean, val onClick: () -> Unit) : PopupItem() + data class Switch(val id: Int, val title: String, var isChecked: Boolean, val onToggle: (Boolean) -> Unit) : PopupItem() + } + + private class SortPopupAdapter( + private val context: Context, + private val items: List + ) : android.widget.BaseAdapter() { + override fun getCount(): Int = items.size + override fun getItem(position: Int): Any = items[position] + override fun getItemId(position: Int): Long = position.toLong() + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val item = items[position] + return when (item) { + is PopupItem.Divider -> { + LayoutInflater.from(context).inflate(R.layout.item_popup_divider, parent, false) + } + is PopupItem.Header -> { + TextView(context).apply { + text = item.title + val px8 = (8 * context.resources.displayMetrics.density).toInt() + val px16 = (16 * context.resources.displayMetrics.density).toInt() + setPadding(px16, px8, px16, px8 / 2) + setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_LabelLarge) + setTextColor(context.getColor(R.color.md_theme_primary)) + } + } + is PopupItem.Radio -> { + val view = convertView?.takeIf { it.id == R.id.sort_radio_item_root } + ?: LayoutInflater.from(context).inflate(R.layout.item_sort_radio, parent, false) + + val title = view.findViewById(R.id.title) + val radio = view.findViewById(R.id.radio) + + title.text = item.title + radio.isChecked = item.isSelected + + view.setOnClickListener { item.onClick() } + view + } + is PopupItem.Switch -> { + val view = convertView?.takeIf { it.id == R.id.sort_switch_item_root } + ?: LayoutInflater.from(context).inflate(R.layout.switch_item, parent, false) + + val title = view.findViewById(R.id.title) + val switch = view.findViewById(R.id.switch_view) + + title.text = item.title + switch.isChecked = item.isChecked + + view.setOnClickListener { + item.isChecked = !item.isChecked + switch.isChecked = item.isChecked + item.onToggle(item.isChecked) + } + view + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt index 4af5ecd5bd..27b77c7e23 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt @@ -93,7 +93,9 @@ class DetailedFolderAdapter( } override val sortTypes = setOf( Sorter.Type.ByFilePathAscending, Sorter.Type.BySizeDescending, - Sorter.Type.ByAddDateDescending, Sorter.Type.ByModifiedDateDescending + Sorter.Type.ByAddDateDescending, Sorter.Type.ByModifiedDateDescending, + Sorter.Type.ByFilePathDescending, Sorter.Type.BySizeAscending, + Sorter.Type.ByAddDateAscending, Sorter.Type.ByModifiedDateAscending ) override val sortType = MutableStateFlow( if (prefSortType != Sorter.Type.None && sortTypes.contains(prefSortType)) @@ -138,14 +140,32 @@ class DetailedFolderAdapter( it.folderList.size + it.songList.size } + Sorter.Type.BySizeAscending -> item.folderList.values.sortedBy { + it.folderList.size + it.songList.size + } + Sorter.Type.ByAddDateDescending -> item.folderList.values.sortedByDescending { it.addDate ?: Long.MIN_VALUE } + Sorter.Type.ByAddDateAscending -> item.folderList.values.sortedBy { + it.addDate ?: Long.MIN_VALUE + } + Sorter.Type.ByModifiedDateDescending -> item.folderList.values.sortedByDescending { it.modifiedDate ?: Long.MIN_VALUE } + Sorter.Type.ByModifiedDateAscending -> item.folderList.values.sortedBy { + it.modifiedDate ?: Long.MIN_VALUE + } + + Sorter.Type.ByFilePathDescending -> item.folderList.values.sortedWith( + SupportComparator.createAlphanumericComparator(inverted = true, cnv = { + it.folderName + }) + ) + else -> item.folderList.values.sortedWith( SupportComparator.createAlphanumericComparator(cnv = { it.folderName @@ -261,6 +281,7 @@ class DetailedFolderAdapter( override fun sort(type: Sorter.Type) { sortType.value = type + songAdapter.sort(type) } private class DiffCallback( diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/SongAdapter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/SongAdapter.kt index a5fcb0b7ba..5c669583c6 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/SongAdapter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/SongAdapter.kt @@ -379,6 +379,7 @@ class SongAdapter( Sorter.Type.ByReleaseDateDescending, Sorter.Type.ByReleaseDateAscending, Sorter.Type.ByModifiedDateDescending, Sorter.Type.ByModifiedDateAscending, Sorter.Type.ByFilePathDescending, Sorter.Type.ByFilePathAscending, + Sorter.Type.BySizeDescending, Sorter.Type.BySizeAscending, Sorter.Type.ByDiscAndTrack ) ) { @@ -445,5 +446,9 @@ class SongAdapter( override fun getModifiedDate(item: MediaItem): Long { return item.mediaMetadata.modifiedDate ?: -1 } + + override fun getSize(item: MediaItem): Int { + return (item.getFile()?.length() ?: 0L).toInt() + } } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/Sorter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/Sorter.kt index 240d09aacf..47fde9fb67 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/Sorter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/Sorter.kt @@ -100,11 +100,11 @@ class Sorter( ByAlbumYearDescending, ByAlbumYearAscending, BySizeDescending, BySizeAscending, ByAlbumSizeDescending, ByAlbumSizeAscending, - NaturalOrder, ByAddDateDescending, ByAddDateAscending, + NaturalOrder, NaturalOrderDescending, ByAddDateDescending, ByAddDateAscending, ByReleaseDateDescending, ByReleaseDateAscending, ByModifiedDateDescending, ByModifiedDateAscending, ByFilePathDescending, ByFilePathAscending, - ByDiscAndTrack, + ByDiscAndTrack, ByDiscAndTrackDescending, None; companion object { @@ -127,7 +127,8 @@ class Sorter( BySizeAscending -> BySizeDescending ByAlbumSizeDescending -> ByAlbumSizeAscending ByAlbumSizeAscending -> ByAlbumSizeDescending - NaturalOrder -> null + NaturalOrder -> NaturalOrderDescending + NaturalOrderDescending -> NaturalOrder ByAddDateDescending -> ByAddDateAscending ByAddDateAscending -> ByAddDateDescending ByReleaseDateDescending -> ByReleaseDateAscending @@ -136,7 +137,8 @@ class Sorter( ByModifiedDateAscending -> ByModifiedDateDescending ByFilePathDescending -> ByFilePathAscending ByFilePathAscending -> ByFilePathDescending - ByDiscAndTrack -> null + ByDiscAndTrack -> ByDiscAndTrackDescending + ByDiscAndTrackDescending -> ByDiscAndTrack None -> null } } @@ -144,9 +146,19 @@ class Sorter( fun getSupportedTypes(): Set { return sortingHelper.typesSupported.let { types -> + var res = types if (naturalOrderHelper != null || rawOrderExposed == Type.NaturalOrder) - types + Type.NaturalOrder - else types + res = res + Type.NaturalOrder + Type.NaturalOrderDescending + if (res.contains(Type.ByDiscAndTrack)) + res = res + Type.ByDiscAndTrackDescending + + // Automatically add inverse for everything supported + val allWithInverses = mutableSetOf() + res.forEach { + allWithInverses.add(it) + Type.inverse(it)?.let { inv -> allWithInverses.add(inv) } + } + allWithInverses } } @@ -343,12 +355,24 @@ class Sorter( compareBy { sortingHelper.getDiscAndTrack(it) } } + Type.ByDiscAndTrackDescending -> { + SupportComparator.createInversionComparator( + compareBy { sortingHelper.getDiscAndTrack(it) }, true + ) + } + Type.NaturalOrder -> { SupportComparator.createInversionComparator( compareBy { naturalOrderHelper!!.lookup(it) }, false ) } + Type.NaturalOrderDescending -> { + SupportComparator.createInversionComparator( + compareBy { naturalOrderHelper!!.lookup(it) }, true + ) + } + Type.None -> throw IllegalStateException() } ) @@ -396,7 +420,7 @@ class Sorter( sortingHelper.getAlbumSize(item).toString() } - Type.ByDiscAndTrack -> { + Type.ByDiscAndTrack, Type.ByDiscAndTrackDescending -> { sortingHelper.getDiscAndTrack(item).toString() } @@ -409,11 +433,11 @@ class Sorter( } Type.ByModifiedDateDescending, Type.ByModifiedDateAscending -> { - CalculationUtils.convertUnixTimestampToMonthDay(sortingHelper.getAddDate(item)) + CalculationUtils.convertUnixTimestampToMonthDay(sortingHelper.getModifiedDate(item)) } - Type.NaturalOrder -> { - (if (rawOrderExposed == sortType) { + Type.NaturalOrder, Type.NaturalOrderDescending -> { + (if (rawOrderExposed == sortType || (rawOrderExposed != null && Type.inverse(rawOrderExposed) == sortType)) { pos } else { naturalOrderHelper!!.lookup(item) diff --git a/app/src/main/java/uk/akane/libphonograph/items/FileNode.kt b/app/src/main/java/uk/akane/libphonograph/items/FileNode.kt index 9e3caf2fe1..4487861293 100644 --- a/app/src/main/java/uk/akane/libphonograph/items/FileNode.kt +++ b/app/src/main/java/uk/akane/libphonograph/items/FileNode.kt @@ -32,7 +32,7 @@ interface FileNode { if (it == Long.MAX_VALUE) null else it } val modifiedDate: Long? - get() = min(songList.maxOfOrNull { it.mediaMetadata.modifiedDate ?: Long.MIN_VALUE } + get() = maxOf(songList.maxOfOrNull { it.mediaMetadata.modifiedDate ?: Long.MIN_VALUE } ?: Long.MIN_VALUE, folderList.maxOfOrNull { it.value.modifiedDate ?: Long.MIN_VALUE } ?: Long.MIN_VALUE).let { diff --git a/app/src/main/res/layout/item_popup_divider.xml b/app/src/main/res/layout/item_popup_divider.xml new file mode 100644 index 0000000000..b973009c1f --- /dev/null +++ b/app/src/main/res/layout/item_popup_divider.xml @@ -0,0 +1,7 @@ + + diff --git a/app/src/main/res/layout/item_sort_radio.xml b/app/src/main/res/layout/item_sort_radio.xml new file mode 100644 index 0000000000..97964a2e0f --- /dev/null +++ b/app/src/main/res/layout/item_sort_radio.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/app/src/main/res/layout/switch_item.xml b/app/src/main/res/layout/switch_item.xml new file mode 100644 index 0000000000..5e8625b0e2 --- /dev/null +++ b/app/src/main/res/layout/switch_item.xml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/app/src/main/res/menu/sort_menu.xml b/app/src/main/res/menu/sort_menu.xml index 22af6d1b03..b33097f2ae 100644 --- a/app/src/main/res/menu/sort_menu.xml +++ b/app/src/main/res/menu/sort_menu.xml @@ -2,6 +2,12 @@ + - \ No newline at end of file + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 5e5f59b22c..67bbddaeea 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -30,4 +30,5 @@ 15sp 12sp 75dp + 250dp \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 00f135e288..48a0f74584 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -153,6 +153,8 @@ Folders App theme + + Reverse order Natural order From d3c0003ba2b8f9f550a6c18cf9c61d79419b1144 Mon Sep 17 00:00:00 2001 From: manum45 Date: Tue, 1 Sep 2026 21:38:33 +0200 Subject: [PATCH 2/6] cleanup --- .../gramophone/ui/adapters/DetailedFolderAdapter.kt | 8 ++++---- .../org/akanework/gramophone/ui/adapters/SongAdapter.kt | 5 ----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt index 27b77c7e23..73e9868352 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt @@ -92,10 +92,10 @@ class DetailedFolderAdapter( Sorter.Type.None } override val sortTypes = setOf( - Sorter.Type.ByFilePathAscending, Sorter.Type.BySizeDescending, - Sorter.Type.ByAddDateDescending, Sorter.Type.ByModifiedDateDescending, - Sorter.Type.ByFilePathDescending, Sorter.Type.BySizeAscending, - Sorter.Type.ByAddDateAscending, Sorter.Type.ByModifiedDateAscending + Sorter.Type.ByFilePathAscending, Sorter.Type.ByFilePathDescending, + Sorter.Type.BySizeDescending, Sorter.Type.BySizeAscending, + Sorter.Type.ByAddDateDescending, Sorter.Type.ByAddDateAscending, + Sorter.Type.ByModifiedDateDescending, Sorter.Type.ByModifiedDateAscending ) override val sortType = MutableStateFlow( if (prefSortType != Sorter.Type.None && sortTypes.contains(prefSortType)) diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/SongAdapter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/SongAdapter.kt index 5c669583c6..4ec89c7044 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/SongAdapter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/SongAdapter.kt @@ -379,7 +379,6 @@ class SongAdapter( Sorter.Type.ByReleaseDateDescending, Sorter.Type.ByReleaseDateAscending, Sorter.Type.ByModifiedDateDescending, Sorter.Type.ByModifiedDateAscending, Sorter.Type.ByFilePathDescending, Sorter.Type.ByFilePathAscending, - Sorter.Type.BySizeDescending, Sorter.Type.BySizeAscending, Sorter.Type.ByDiscAndTrack ) ) { @@ -446,9 +445,5 @@ class SongAdapter( override fun getModifiedDate(item: MediaItem): Long { return item.mediaMetadata.modifiedDate ?: -1 } - - override fun getSize(item: MediaItem): Int { - return (item.getFile()?.length() ?: 0L).toInt() - } } } From 967baf24aa8e90ad2d641ecae62cffda1301ea3d Mon Sep 17 00:00:00 2001 From: manum45 Date: Tue, 1 Sep 2026 21:51:16 +0200 Subject: [PATCH 3/6] go back to old menu style --- .../gramophone/ui/adapters/ArtistAdapter.kt | 38 ++- .../ui/adapters/BaseDecorAdapter.kt | 258 ++++++------------ .../main/res/layout/item_popup_divider.xml | 7 - app/src/main/res/layout/item_sort_radio.xml | 27 -- app/src/main/res/layout/switch_item.xml | 29 -- app/src/main/res/menu/sort_menu.xml | 2 +- 6 files changed, 116 insertions(+), 245 deletions(-) delete mode 100644 app/src/main/res/layout/item_popup_divider.xml delete mode 100644 app/src/main/res/layout/item_sort_radio.xml delete mode 100644 app/src/main/res/layout/switch_item.xml diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/ArtistAdapter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/ArtistAdapter.kt index 5155c43d11..97a0b41f90 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/ArtistAdapter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/ArtistAdapter.kt @@ -18,6 +18,7 @@ package org.akanework.gramophone.ui.adapters import android.content.SharedPreferences +import android.view.MenuItem import androidx.appcompat.widget.PopupMenu import androidx.core.content.edit import androidx.core.view.iterator @@ -156,20 +157,31 @@ class ArtistAdapter( artistAdapter: ArtistAdapter ) : BaseDecorAdapter(artistAdapter, R.plurals.artists) { - override fun onSortPopupPopulating(items: MutableList) { - items.add(PopupItem.Switch( - R.id.album_artist_checkbox, - context.getString(R.string.album_artist), - adapter.isAlbumArtist - ) { isChecked -> - adapter.isAlbumArtist = isChecked - adapter.prefs.edit { - putBoolean("isDisplayingAlbumArtist", isChecked) + override fun onSortButtonPressed(popupMenu: PopupMenu) { + popupMenu.menu.findItem(R.id.album_artist_checkbox).isVisible = true + popupMenu.menu.findItem(R.id.album_artist_checkbox).isChecked = adapter.isAlbumArtist + } + + override fun onExtraMenuButtonPressed(menuItem: MenuItem): Boolean { + return when (menuItem.itemId) { + R.id.album_artist_checkbox -> { + menuItem.isChecked = !menuItem.isChecked + adapter.isAlbumArtist = menuItem.isChecked + + adapter.prefs.edit { + putBoolean( + "isDisplayingAlbumArtist", + adapter.isAlbumArtist + ) + } + adapter.liveDataAgent.value = + if (adapter.isAlbumArtist) adapter.mainActivity.reader.albumArtistListFlow else + adapter.mainActivity.reader.artistListFlow + true } - adapter.liveDataAgent.value = - if (isChecked) adapter.mainActivity.reader.albumArtistListFlow else - adapter.mainActivity.reader.artistListFlow - }) + + else -> false + } } } diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt index b74bfbe23c..bb7036555e 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt @@ -18,21 +18,17 @@ package org.akanework.gramophone.ui.adapters import android.content.Context -import android.view.Gravity -import android.view.LayoutInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup -import android.widget.LinearLayout -import android.widget.RadioButton import android.widget.TextView -import androidx.appcompat.widget.ListPopupWindow +import androidx.appcompat.widget.PopupMenu import androidx.core.content.edit import androidx.core.content.pm.ShortcutManagerCompat import androidx.media3.common.Player.REPEAT_MODE_OFF import androidx.preference.PreferenceManager import androidx.recyclerview.widget.RecyclerView import com.google.android.material.button.MaterialButton -import com.google.android.material.materialswitch.MaterialSwitch import kotlinx.coroutines.flow.first import kotlinx.coroutines.runBlocking import org.akanework.gramophone.R @@ -81,12 +77,8 @@ open class BaseDecorAdapter>( holder.sortButton.visibility = if (adapter.sortType.value != Sorter.Type.None || adapter.canChangeLayout) View.VISIBLE else View.GONE holder.sortButton.setOnClickListener { view -> - val listPopupWindow = ListPopupWindow(context) - listPopupWindow.anchorView = view - listPopupWindow.setDropDownGravity(Gravity.END) - listPopupWindow.isModal = true - listPopupWindow.width = context.resources.getDimensionPixelSize(R.dimen.sort_popup_width) - + val popupMenu = PopupMenu(context, view) + popupMenu.inflate(R.menu.sort_menu) val buttonMap = mapOf( Pair(R.id.natural, Sorter.Type.NaturalOrder), Pair(R.id.name, Sorter.Type.ByTitleAscending), @@ -102,111 +94,105 @@ open class BaseDecorAdapter>( Pair(R.id.mod_date, Sorter.Type.ByModifiedDateDescending), Pair(R.id.file_path, Sorter.Type.ByFilePathAscending) ) - val layoutMap = mapOf( Pair(R.id.list, BaseAdapter.LayoutType.LIST), Pair(R.id.compact_list, BaseAdapter.LayoutType.COMPACT_LIST), Pair(R.id.grid, BaseAdapter.LayoutType.GRID), Pair(R.id.compact_grid, BaseAdapter.LayoutType.COMPACT_GRID) ) + buttonMap.forEach { + popupMenu.menu.findItem(it.key).isVisible = adapter.sortTypes.contains(it.value) + } + layoutMap.forEach { + popupMenu.menu.findItem(it.key).isVisible = adapter.canChangeLayout + } + popupMenu.menu.findItem(R.id.display).isVisible = adapter.canChangeLayout + + val currentSort = adapter.sortType.value + val activeEntry = buttonMap.entries.find { it.value == currentSort || Sorter.Type.inverse(it.value) == currentSort } + val defaultSort = activeEntry?.value ?: Sorter.Type.None + + if (activeEntry != null) { + popupMenu.menu.findItem(activeEntry.key).isChecked = true + } + + if (adapter.canChangeLayout) { + when (adapter.layoutType) { + in layoutMap.values -> { + popupMenu.menu.findItem( + layoutMap.entries + .first { it.value == adapter.layoutType }.key + ).isChecked = true + } - val items = mutableListOf() - - // 1. Reverse Toggle + else -> throw IllegalStateException("Invalid layoutType ${adapter.layoutType?.name}") + } + } + + val reverseItem = popupMenu.menu.findItem(R.id.reverse_order) val inverse = Sorter.Type.inverse(adapter.sortType.value) - if (inverse != null) { - val currentSort = adapter.sortType.value - val activeEntry = buttonMap.entries.find { it.value == currentSort || Sorter.Type.inverse(it.value) == currentSort } - val defaultSort = activeEntry?.value ?: Sorter.Type.None - - items.add(PopupItem.Switch( - R.id.reverse_order, - context.getString(R.string.reverse_order), - currentSort != defaultSort && currentSort != Sorter.Type.None - ) { isChecked -> - val activeId = buttonMap.entries.find { - it.value == adapter.sortType.value || Sorter.Type.inverse(it.value) == adapter.sortType.value - }?.key ?: -1 - val baseType = buttonMap[activeId] - if (baseType != null) { - val targetType = if (isChecked) Sorter.Type.inverse(baseType) ?: baseType else baseType - if (adapter.sortType.value != targetType) { + if (inverse == null) { + reverseItem.isVisible = false + } else { + reverseItem.isChecked = currentSort != defaultSort && currentSort != Sorter.Type.None + } + + popupMenu.setOnMenuItemClickListener { menuItem -> + when (menuItem.itemId) { + in buttonMap.keys -> { + if (!menuItem.isChecked) { + val baseType = buttonMap[menuItem.itemId]!! + val targetType = if (reverseItem.isChecked) Sorter.Type.inverse(baseType) ?: baseType else baseType adapter.sort(targetType) - prefs.edit { putString("S" + getAdapterType(adapter).toString(), targetType.toString()) } + menuItem.isChecked = true + prefs.edit { + putString( + "S" + getAdapterType(adapter).toString(), + targetType.toString() + ) + } } + true } - }) - items.add(PopupItem.Divider) - } - // 2. Extra items (Album Artist etc) - val extraItems = mutableListOf() - onSortPopupPopulating(extraItems) - if (extraItems.isNotEmpty()) { - items.addAll(extraItems) - items.add(PopupItem.Divider) - } + in layoutMap.keys -> { + if (!menuItem.isChecked) { + adapter.layoutType = layoutMap[menuItem.itemId]!! + menuItem.isChecked = true + prefs.edit { + putString( + "L" + getAdapterType(adapter).toString(), + layoutMap[menuItem.itemId].toString() + ) + } + } + true + } - // 3. Sort Modes - buttonMap.forEach { (resId, type) -> - if (adapter.sortTypes.contains(type)) { - val currentSort = adapter.sortType.value - val isSelected = currentSort == type || Sorter.Type.inverse(type) == currentSort - items.add(PopupItem.Radio( - resId, - context.getString(when (resId) { - R.id.natural -> R.string.natural_order - R.id.name -> R.string.sort_by_name - R.id.artist -> R.string.sort_by_artist - R.id.artist_year -> R.string.sort_by_artist_year - R.id.album -> R.string.sort_by_album - R.id.album_artist -> R.string.sort_by_album_artist - R.id.album_artist_year -> R.string.sort_by_album_artist_year - R.id.album_year -> R.string.sort_by_album_year - R.id.size -> R.string.sort_by_size - R.id.add_date -> R.string.sort_by_add_date - R.id.release_date -> R.string.sort_by_release_date - R.id.mod_date -> R.string.sort_by_modified_date - R.id.file_path -> R.string.sort_by_file_path - else -> 0 - }), - isSelected - ) { - val isReversed = (items.find { it is PopupItem.Switch && it.id == R.id.reverse_order } as? PopupItem.Switch)?.isChecked == true - val targetType = if (isReversed) Sorter.Type.inverse(type) ?: type else type - adapter.sort(targetType) - prefs.edit { putString("S" + getAdapterType(adapter).toString(), targetType.toString()) } - listPopupWindow.dismiss() - }) - } - } + R.id.reverse_order -> { + menuItem.isChecked = !menuItem.isChecked + val activeId = buttonMap.entries.find { + it.value == adapter.sortType.value || Sorter.Type.inverse(it.value) == adapter.sortType.value + }?.key ?: -1 + val baseType = buttonMap[activeId] + if (baseType != null) { + val targetType = if (menuItem.isChecked) Sorter.Type.inverse(baseType) ?: baseType else baseType + adapter.sort(targetType) + prefs.edit { + putString( + "S" + getAdapterType(adapter).toString(), + targetType.toString() + ) + } + } + true + } - // 4. Layout Modes - if (adapter.canChangeLayout) { - items.add(PopupItem.Divider) - items.add(PopupItem.Header(context.getString(R.string.layout))) - layoutMap.forEach { (resId, type) -> - items.add(PopupItem.Radio( - resId, - context.getString(when (resId) { - R.id.list -> R.string.list - R.id.compact_list -> R.string.compact_list - R.id.grid -> R.string.grid - R.id.compact_grid -> R.string.compact_grid - else -> 0 - }), - adapter.layoutType == type - ) { - adapter.layoutType = type - prefs.edit { putString("L" + getAdapterType(adapter).toString(), type.toString()) } - listPopupWindow.dismiss() - }) + else -> onExtraMenuButtonPressed(menuItem) } } - - val adapter2 = SortPopupAdapter(context, items) - listPopupWindow.setAdapter(adapter2) - listPopupWindow.show() + onSortButtonPressed(popupMenu) + popupMenu.show() } holder.playAll.setOnClickListener { if (adapter is SongAdapter) { @@ -337,7 +323,8 @@ open class BaseDecorAdapter>( recyclerView?.startSmoothScrollCompat(smoothScroller) } - protected open fun onSortPopupPopulating(items: MutableList) {} + protected open fun onSortButtonPressed(popupMenu: PopupMenu) {} + protected open fun onExtraMenuButtonPressed(menuItem: MenuItem): Boolean = false override fun getItemCount(): Int = 1 override fun getItemViewType(position: Int): Int = R.layout.general_decor @@ -361,69 +348,4 @@ open class BaseDecorAdapter>( override fun getItemHeightFromZeroTo(to: Int): Int { return if (to > 0) dpHeight else 0 } - - sealed class PopupItem { - object Divider : PopupItem() - data class Header(val title: String) : PopupItem() - data class Radio(val id: Int, val title: String, val isSelected: Boolean, val onClick: () -> Unit) : PopupItem() - data class Switch(val id: Int, val title: String, var isChecked: Boolean, val onToggle: (Boolean) -> Unit) : PopupItem() - } - - private class SortPopupAdapter( - private val context: Context, - private val items: List - ) : android.widget.BaseAdapter() { - override fun getCount(): Int = items.size - override fun getItem(position: Int): Any = items[position] - override fun getItemId(position: Int): Long = position.toLong() - - override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { - val item = items[position] - return when (item) { - is PopupItem.Divider -> { - LayoutInflater.from(context).inflate(R.layout.item_popup_divider, parent, false) - } - is PopupItem.Header -> { - TextView(context).apply { - text = item.title - val px8 = (8 * context.resources.displayMetrics.density).toInt() - val px16 = (16 * context.resources.displayMetrics.density).toInt() - setPadding(px16, px8, px16, px8 / 2) - setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_LabelLarge) - setTextColor(context.getColor(R.color.md_theme_primary)) - } - } - is PopupItem.Radio -> { - val view = convertView?.takeIf { it.id == R.id.sort_radio_item_root } - ?: LayoutInflater.from(context).inflate(R.layout.item_sort_radio, parent, false) - - val title = view.findViewById(R.id.title) - val radio = view.findViewById(R.id.radio) - - title.text = item.title - radio.isChecked = item.isSelected - - view.setOnClickListener { item.onClick() } - view - } - is PopupItem.Switch -> { - val view = convertView?.takeIf { it.id == R.id.sort_switch_item_root } - ?: LayoutInflater.from(context).inflate(R.layout.switch_item, parent, false) - - val title = view.findViewById(R.id.title) - val switch = view.findViewById(R.id.switch_view) - - title.text = item.title - switch.isChecked = item.isChecked - - view.setOnClickListener { - item.isChecked = !item.isChecked - switch.isChecked = item.isChecked - item.onToggle(item.isChecked) - } - view - } - } - } - } -} \ No newline at end of file +} diff --git a/app/src/main/res/layout/item_popup_divider.xml b/app/src/main/res/layout/item_popup_divider.xml deleted file mode 100644 index b973009c1f..0000000000 --- a/app/src/main/res/layout/item_popup_divider.xml +++ /dev/null @@ -1,7 +0,0 @@ - - diff --git a/app/src/main/res/layout/item_sort_radio.xml b/app/src/main/res/layout/item_sort_radio.xml deleted file mode 100644 index 97964a2e0f..0000000000 --- a/app/src/main/res/layout/item_sort_radio.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/switch_item.xml b/app/src/main/res/layout/switch_item.xml deleted file mode 100644 index 5e8625b0e2..0000000000 --- a/app/src/main/res/layout/switch_item.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/menu/sort_menu.xml b/app/src/main/res/menu/sort_menu.xml index b33097f2ae..db7d3a95bb 100644 --- a/app/src/main/res/menu/sort_menu.xml +++ b/app/src/main/res/menu/sort_menu.xml @@ -4,9 +4,9 @@ xmlns:tools="http://schemas.android.com/tools"> Date: Tue, 1 Sep 2026 21:58:43 +0200 Subject: [PATCH 4/6] remove unused parameter, move reverse order to top of sort menu --- app/src/main/res/menu/sort_menu.xml | 1 - app/src/main/res/values/dimens.xml | 1 - 2 files changed, 2 deletions(-) diff --git a/app/src/main/res/menu/sort_menu.xml b/app/src/main/res/menu/sort_menu.xml index db7d3a95bb..7932a525bb 100644 --- a/app/src/main/res/menu/sort_menu.xml +++ b/app/src/main/res/menu/sort_menu.xml @@ -5,7 +5,6 @@ diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 67bbddaeea..5e5f59b22c 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -30,5 +30,4 @@ 15sp 12sp 75dp - 250dp \ No newline at end of file From c8027446982fd70903aceedb0ecc5ac8ed7f0776 Mon Sep 17 00:00:00 2001 From: manum45 Date: Tue, 1 Sep 2026 22:17:46 +0200 Subject: [PATCH 5/6] readd exception in case of unsupported sort type --- .../org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt index bb7036555e..bbea45e913 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt @@ -115,6 +115,9 @@ open class BaseDecorAdapter>( if (activeEntry != null) { popupMenu.menu.findItem(activeEntry.key).isChecked = true } + else { + throw IllegalStateException("Invalid sortType ${adapter.sortType.value.name}") + } if (adapter.canChangeLayout) { when (adapter.layoutType) { From 99c52abe921887a266426dab968663d94d28d7a7 Mon Sep 17 00:00:00 2001 From: manum45 Date: Wed, 2 Sep 2026 23:25:32 +0200 Subject: [PATCH 6/6] fix review findings --- .../gramophone/ui/adapters/BaseDecorAdapter.kt | 16 ++++++++-------- .../ui/adapters/DetailedFolderAdapter.kt | 1 - .../akanework/gramophone/ui/adapters/Sorter.kt | 4 +--- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt index bbea45e913..948677cfc2 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/BaseDecorAdapter.kt @@ -110,15 +110,13 @@ open class BaseDecorAdapter>( val currentSort = adapter.sortType.value val activeEntry = buttonMap.entries.find { it.value == currentSort || Sorter.Type.inverse(it.value) == currentSort } - val defaultSort = activeEntry?.value ?: Sorter.Type.None - if (activeEntry != null) { - popupMenu.menu.findItem(activeEntry.key).isChecked = true - } - else { + if (activeEntry == null) { throw IllegalStateException("Invalid sortType ${adapter.sortType.value.name}") } + popupMenu.menu.findItem(activeEntry.key).isChecked = true + if (adapter.canChangeLayout) { when (adapter.layoutType) { in layoutMap.values -> { @@ -137,15 +135,17 @@ open class BaseDecorAdapter>( if (inverse == null) { reverseItem.isVisible = false } else { - reverseItem.isChecked = currentSort != defaultSort && currentSort != Sorter.Type.None + reverseItem.isChecked = currentSort != activeEntry.value && currentSort != Sorter.Type.None } popupMenu.setOnMenuItemClickListener { menuItem -> when (menuItem.itemId) { in buttonMap.keys -> { if (!menuItem.isChecked) { - val baseType = buttonMap[menuItem.itemId]!! - val targetType = if (reverseItem.isChecked) Sorter.Type.inverse(baseType) ?: baseType else baseType + // always use default direction for this sort mode if sort mode is changed, + // and reset the reverseOrder checkbox + val targetType = buttonMap[menuItem.itemId]!! + reverseItem.isChecked = false adapter.sort(targetType) menuItem.isChecked = true prefs.edit { diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt index 73e9868352..0092a7283c 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/DetailedFolderAdapter.kt @@ -281,7 +281,6 @@ class DetailedFolderAdapter( override fun sort(type: Sorter.Type) { sortType.value = type - songAdapter.sort(type) } private class DiffCallback( diff --git a/app/src/main/java/org/akanework/gramophone/ui/adapters/Sorter.kt b/app/src/main/java/org/akanework/gramophone/ui/adapters/Sorter.kt index 47fde9fb67..ee6fd90b1f 100644 --- a/app/src/main/java/org/akanework/gramophone/ui/adapters/Sorter.kt +++ b/app/src/main/java/org/akanework/gramophone/ui/adapters/Sorter.kt @@ -148,9 +148,7 @@ class Sorter( return sortingHelper.typesSupported.let { types -> var res = types if (naturalOrderHelper != null || rawOrderExposed == Type.NaturalOrder) - res = res + Type.NaturalOrder + Type.NaturalOrderDescending - if (res.contains(Type.ByDiscAndTrack)) - res = res + Type.ByDiscAndTrackDescending + res = res + Type.NaturalOrder // Automatically add inverse for everything supported val allWithInverses = mutableSetOf()