From aaa1ad1a3d088de09b6435fc603b4fc66eb7cf0c Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Sat, 12 Dec 2020 13:50:46 -0700 Subject: [PATCH] Add song playback mode option Add an option to customize whether a song should play from its artist, its album, or all songs when selected. --- .../oxycblt/auxio/library/LibraryFragment.kt | 6 ++-- .../auxio/library/adapters/LibraryAdapter.kt | 7 ----- .../auxio/library/adapters/SearchAdapter.kt | 2 -- .../auxio/playback/PlaybackViewModel.kt | 4 +-- .../auxio/playback/state/PlaybackMode.kt | 14 +++++++++ .../auxio/settings/SettingsListFragment.kt | 3 +- .../oxycblt/auxio/settings/SettingsManager.kt | 22 +++++++++----- .../org/oxycblt/auxio/songs/SongsFragment.kt | 5 ++-- .../org/oxycblt/auxio/ui/InterfaceUtils.kt | 28 ++++++++++++++++-- app/src/main/res/menu/menu_song_actions.xml | 4 +++ app/src/main/res/values/arrays.xml | 12 ++++++++ app/src/main/res/values/strings.xml | 26 +++++++++++------ app/src/main/res/xml-v27/prefs_main.xml | 29 ++++++++++++++----- app/src/main/res/xml/prefs_main.xml | 25 ++++++++++++---- 14 files changed, 137 insertions(+), 50 deletions(-) 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 13b215bdb..709b415cf 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt @@ -25,7 +25,7 @@ import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.PlaybackViewModel -import org.oxycblt.auxio.playback.state.PlaybackMode +import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.ui.applyColor import org.oxycblt.auxio.ui.resolveAttr import org.oxycblt.auxio.ui.setupAlbumActions @@ -197,7 +197,9 @@ class LibraryFragment : Fragment(), SearchView.OnQueryTextListener { // If the item is a song [That was selected through search], then update the playback // to that song instead of doing any navigation if (baseModel is Song) { - playbackModel.playSong(baseModel, PlaybackMode.ALL_SONGS) + val settingsManager = SettingsManager.getInstance() + + playbackModel.playSong(baseModel, settingsManager.songPlaybackMode) return } diff --git a/app/src/main/java/org/oxycblt/auxio/library/adapters/LibraryAdapter.kt b/app/src/main/java/org/oxycblt/auxio/library/adapters/LibraryAdapter.kt index d85d9189e..bc334ac88 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/adapters/LibraryAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/adapters/LibraryAdapter.kt @@ -1,23 +1,16 @@ package org.oxycblt.auxio.library.adapters -import android.util.Log import android.view.View import android.view.ViewGroup -import androidx.recyclerview.widget.AsyncListDiffer import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.BaseModel import org.oxycblt.auxio.music.Genre -import org.oxycblt.auxio.music.Header -import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.recycler.DiffCallback import org.oxycblt.auxio.recycler.viewholders.AlbumViewHolder import org.oxycblt.auxio.recycler.viewholders.ArtistViewHolder import org.oxycblt.auxio.recycler.viewholders.GenreViewHolder -import org.oxycblt.auxio.recycler.viewholders.HeaderViewHolder -import org.oxycblt.auxio.recycler.viewholders.SongViewHolder /** * A near-identical adapter as [SearchAdapter] but this one isn't a [ListAdapter] diff --git a/app/src/main/java/org/oxycblt/auxio/library/adapters/SearchAdapter.kt b/app/src/main/java/org/oxycblt/auxio/library/adapters/SearchAdapter.kt index bb375ae2a..eea6968c1 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/adapters/SearchAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/adapters/SearchAdapter.kt @@ -1,9 +1,7 @@ package org.oxycblt.auxio.library.adapters -import android.util.Log import android.view.View import android.view.ViewGroup -import androidx.recyclerview.widget.AsyncListDiffer import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.music.Album diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt index a3268c0c8..805845d98 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt @@ -1,5 +1,3 @@ -@file:Suppress("unused") - package org.oxycblt.auxio.playback import android.content.Context @@ -45,7 +43,7 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback { val userQueue: LiveData> get() = mUserQueue private val mIndex = MutableLiveData(0) - val index: LiveData get() = mIndex + // val index: LiveData get() = mIndex private val mMode = MutableLiveData(PlaybackMode.ALL_SONGS) val mode: LiveData get() = mMode diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt index 235e8d396..97a9be83a 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackMode.kt @@ -1,5 +1,7 @@ package org.oxycblt.auxio.playback.state +import java.lang.IllegalArgumentException + // Enum for instruction how the queue should function. // ALL SONGS -> Play from all songs // IN_ARTIST -> Play from the songs of the artist @@ -32,5 +34,17 @@ enum class PlaybackMode { else -> null } } + + fun valueOfOrFallback(value: String?): PlaybackMode { + if (value == null) { + return ALL_SONGS + } + + return try { + valueOf(value) + } catch (e: IllegalArgumentException) { + ALL_SONGS + } + } } } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt index 5c124cb42..e721c4f43 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsListFragment.kt @@ -1,5 +1,3 @@ -@file:Suppress("unused") - package org.oxycblt.auxio.settings import android.os.Bundle @@ -21,6 +19,7 @@ import org.oxycblt.auxio.ui.ACCENTS import org.oxycblt.auxio.ui.accent import org.oxycblt.auxio.ui.getDetailedAccentSummary +@Suppress("UNUSED") class SettingsListFragment : PreferenceFragmentCompat() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt index 512039e36..0aaf190b9 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt @@ -3,6 +3,7 @@ package org.oxycblt.auxio.settings import android.content.Context import android.content.SharedPreferences import androidx.preference.PreferenceManager +import org.oxycblt.auxio.playback.state.PlaybackMode import org.oxycblt.auxio.recycler.DisplayMode import org.oxycblt.auxio.recycler.SortMode import org.oxycblt.auxio.ui.ACCENTS @@ -51,14 +52,12 @@ class SettingsManager private constructor(context: Context) : get() = sharedPrefs.getBoolean(Keys.KEY_USE_ALT_NOTIFICATION_ACTION, false) val libraryDisplayMode: DisplayMode - get() { - return DisplayMode.valueOfOrFallback( - sharedPrefs.getString( - Keys.KEY_LIBRARY_DISPLAY_MODE, - DisplayMode.SHOW_ARTISTS.toString() - ) + get() = DisplayMode.valueOfOrFallback( + sharedPrefs.getString( + Keys.KEY_LIBRARY_DISPLAY_MODE, + DisplayMode.SHOW_ARTISTS.toString() ) - } + ) val doAudioFocus: Boolean get() = sharedPrefs.getBoolean(Keys.KEY_AUDIO_FOCUS, true) @@ -66,6 +65,14 @@ class SettingsManager private constructor(context: Context) : val doPlugMgt: Boolean get() = sharedPrefs.getBoolean(Keys.KEY_PLUG_MANAGEMENT, true) + val songPlaybackMode: PlaybackMode + get() = PlaybackMode.valueOfOrFallback( + sharedPrefs.getString( + Keys.KEY_SONG_PLAYBACK_MODE, + PlaybackMode.ALL_SONGS.toString() + ) + ) + var librarySortMode: SortMode get() { return SortMode.fromInt( @@ -153,6 +160,7 @@ class SettingsManager private constructor(context: Context) : const val KEY_LIBRARY_DISPLAY_MODE = "KEY_LIBRARY_DISPLAY_MODE" const val KEY_AUDIO_FOCUS = "KEY_AUDIO_FOCUS" const val KEY_PLUG_MANAGEMENT = "KEY_PLUG_MGT" + const val KEY_SONG_PLAYBACK_MODE = "KEY_SONG_PLAY_MODE" const val KEY_LIBRARY_SORT_MODE = "KEY_LIBRARY_SORT_MODE" } 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 aa2a4b042..80628b074 100644 --- a/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt @@ -16,7 +16,7 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentSongsBinding import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.playback.PlaybackViewModel -import org.oxycblt.auxio.playback.state.PlaybackMode +import org.oxycblt.auxio.settings.SettingsManager import org.oxycblt.auxio.ui.setupSongActions import kotlin.math.ceil @@ -42,10 +42,11 @@ class SongsFragment : Fragment() { val binding = FragmentSongsBinding.inflate(inflater) val musicStore = MusicStore.getInstance() + val settingsManager = SettingsManager.getInstance() val songAdapter = SongsAdapter( musicStore.songs, - doOnClick = { playbackModel.playSong(it, PlaybackMode.ALL_SONGS) }, + doOnClick = { playbackModel.playSong(it, settingsManager.songPlaybackMode) }, doOnLongClick = { data, view -> PopupMenu(requireContext(), view).setupSongActions( data, requireContext(), playbackModel 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 d5b0a909c..93ca7240d 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/InterfaceUtils.kt @@ -8,6 +8,7 @@ import android.os.Build import android.text.SpannableString import android.text.Spanned import android.text.style.ForegroundColorSpan +import android.util.Log import android.view.MenuItem import android.view.View import android.view.Window @@ -26,6 +27,7 @@ import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.state.PlaybackMode +import org.oxycblt.auxio.settings.SettingsManager // Functions for managing UI elements [Not Colors] @@ -108,6 +110,8 @@ fun Window.handleTransparentSystemBars(config: Configuration) { * Show actions for a song item, such as the ones found in [org.oxycblt.auxio.songs.SongsFragment] */ fun PopupMenu.setupSongActions(song: Song, context: Context, playbackModel: PlaybackViewModel) { + inflateAndShow(R.menu.menu_song_actions) + setOnMenuItemClickListener { when (it.itemId) { R.id.action_queue_add -> { @@ -126,14 +130,34 @@ fun PopupMenu.setupSongActions(song: Song, context: Context, playbackModel: Play true } + R.id.action_play_all_songs -> { + playbackModel.playSong(song, PlaybackMode.ALL_SONGS) + true + } + else -> false } } - inflateAndShow(R.menu.menu_song_actions) + + val settingsManager = SettingsManager.getInstance() + + // Find the action that is redundant from the menu and hide it. + val idToRemove = when (settingsManager.songPlaybackMode) { + PlaybackMode.ALL_SONGS -> R.id.action_play_all_songs + PlaybackMode.IN_ARTIST -> R.id.action_play_artist + PlaybackMode.IN_ALBUM -> R.id.action_play_album + + else -> -1 + } + + Log.d(this::class.simpleName, (idToRemove == R.id.action_play_album).toString()) + + menu.findItem(idToRemove)?.isVisible = false } /** - * Show actions for a song item, such as the ones found in [org.oxycblt.auxio.songs.SongsFragment] + * Show actions for a album song item, such as the ones found in + * [org.oxycblt.auxio.detail.AlbumDetailFragment] */ fun PopupMenu.setupAlbumSongActions( song: Song, diff --git a/app/src/main/res/menu/menu_song_actions.xml b/app/src/main/res/menu/menu_song_actions.xml index 3856ad1e7..a4585fd26 100644 --- a/app/src/main/res/menu/menu_song_actions.xml +++ b/app/src/main/res/menu/menu_song_actions.xml @@ -4,6 +4,10 @@ android:id="@+id/action_queue_add" android:title="@string/label_queue_add" android:icon="@drawable/ic_queue_add" /> + SHOW_ARTISTS SHOW_ALBUMS + + + @string/label_play_all_songs + @string/label_play_artist + @string/label_play_album + + + + ALL_SONGS + IN_ARTIST + IN_ALBUM + \ 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 882eb2ce5..23cd136c1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -23,8 +23,9 @@ Play Shuffle - Play from artist + Play from all songs Play from album + Play from artist Go to artist Queue @@ -38,30 +39,37 @@ Settings Appearance + Theme Automatic Light Dark + Accent Unknown Accent + Edge-To-Edge - Edge-to-edge is enabled - Edge-to-edge is disabled + Enable edge-to-edge Display + Library Items + Colorize notification] - Show album art on notification - Hide album art on notification + Show album art on notification + Use alternate notification action Prefer repeat mode action Prefer shuffle action + Audio Audio focus - Audio focus is enabled - Audio focus is disabled + Pause when other audio plays [ex. Alarms] + Headset plug management - Headset plug management is enabled - Headset plug management is disabled + Play/Pause when headset connection changes + + Behavior + When a song is selected State saved diff --git a/app/src/main/res/xml-v27/prefs_main.xml b/app/src/main/res/xml-v27/prefs_main.xml index 8571df925..a15f8baa3 100644 --- a/app/src/main/res/xml-v27/prefs_main.xml +++ b/app/src/main/res/xml-v27/prefs_main.xml @@ -22,8 +22,7 @@ @@ -45,8 +44,7 @@ @@ -70,15 +68,30 @@ android:title="@string/setting_playback_audio_focus" app:iconSpaceReserved="false" app:defaultValue="true" - app:summaryOn="@string/setting_playback_focus_desc_on" - app:summaryOff="@string/setting_playback_focus_desc_off" /> + app:summary="@string/setting_playback_focus_desc" /> + app:allowDividerBelow="false" + app:summary="@string/setting_playback_plug_mgt_desc" /> + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/prefs_main.xml b/app/src/main/res/xml/prefs_main.xml index 708d53e72..eade6ffad 100644 --- a/app/src/main/res/xml/prefs_main.xml +++ b/app/src/main/res/xml/prefs_main.xml @@ -36,8 +36,7 @@ @@ -61,15 +60,29 @@ android:title="@string/setting_playback_audio_focus" app:iconSpaceReserved="false" app:defaultValue="true" - app:summaryOn="@string/setting_playback_focus_desc_on" - app:summaryOff="@string/setting_playback_focus_desc_off" /> + app:summary="@string/setting_playback_focus_desc" /> + app:allowDividerBelow="false" + app:summary="@string/setting_playback_plug_mgt_desc" /> + + + + + + \ No newline at end of file