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.
This commit is contained in:
OxygenCobalt 2020-12-12 13:50:46 -07:00
parent 859391e69b
commit aaa1ad1a3d
14 changed files with 137 additions and 50 deletions

View file

@ -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
}

View file

@ -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]

View file

@ -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

View file

@ -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<MutableList<Song>> get() = mUserQueue
private val mIndex = MutableLiveData(0)
val index: LiveData<Int> get() = mIndex
// val index: LiveData<Int> get() = mIndex
private val mMode = MutableLiveData(PlaybackMode.ALL_SONGS)
val mode: LiveData<PlaybackMode> get() = mMode

View file

@ -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
}
}
}
}

View file

@ -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)

View file

@ -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"
}

View file

@ -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

View file

@ -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,

View file

@ -4,6 +4,10 @@
android:id="@+id/action_queue_add"
android:title="@string/label_queue_add"
android:icon="@drawable/ic_queue_add" />
<item
android:id="@+id/action_play_all_songs"
android:title="@string/label_play_all_songs"
android:icon="@drawable/ic_song" />
<item
android:id="@+id/action_play_artist"
android:title="@string/label_play_artist"

View file

@ -23,4 +23,16 @@
<item>SHOW_ARTISTS</item>
<item>SHOW_ALBUMS</item>
</array>
<array name="song_playback_mode_entries">
<item>@string/label_play_all_songs</item>
<item>@string/label_play_artist</item>
<item>@string/label_play_album</item>
</array>
<array name="song_playback_mode_values">
<item>ALL_SONGS</item>
<item>IN_ARTIST</item>
<item>IN_ALBUM</item>
</array>
</resources>

View file

@ -23,8 +23,9 @@
<string name="label_play">Play</string>
<string name="label_shuffle">Shuffle</string>
<string name="label_play_artist">Play from artist</string>
<string name="label_play_all_songs">Play from all songs</string>
<string name="label_play_album">Play from album</string>
<string name="label_play_artist">Play from artist</string>
<string name="label_go_artist">Go to artist</string>
<string name="label_queue">Queue</string>
@ -38,30 +39,37 @@
<!-- Settings namespace | Settings-related labels -->
<string name="setting_title">Settings</string>
<string name="setting_ui">Appearance</string>
<string name="setting_theme">Theme</string>
<string name="setting_theme_auto">Automatic</string>
<string name="setting_theme_day">Light</string>
<string name="setting_theme_night">Dark</string>
<string name="setting_accent">Accent</string>
<string name="setting_accent_unknown">Unknown Accent</string>
<string name="setting_edge">Edge-To-Edge</string>
<string name="setting_edge_desc_on">Edge-to-edge is enabled</string>
<string name="setting_edge_desc_off">Edge-to-edge is disabled</string>
<string name="setting_edge_desc">Enable edge-to-edge</string>
<string name="setting_display">Display</string>
<string name="setting_lib_display">Library Items</string>
<string name="setting_color_notif">Colorize notification</string>]
<string name="setting_color_desc_on">Show album art on notification</string>
<string name="setting_color_desc_off">Hide album art on notification</string>
<string name="setting_color_desc">Show album art on notification</string>
<string name="setting_use_alt_action">Use alternate notification action</string>
<string name="setting_use_alt_loop">Prefer repeat mode action</string>
<string name="setting_use_alt_shuffle">Prefer shuffle action</string>
<string name="setting_playback">Audio</string>
<string name="setting_playback_audio_focus">Audio focus</string>
<string name="setting_playback_focus_desc_on">Audio focus is enabled</string>
<string name="setting_playback_focus_desc_off">Audio focus is disabled</string>
<string name="setting_playback_focus_desc">Pause when other audio plays [ex. Alarms]</string>
<string name="setting_playback_plug_mgt">Headset plug management</string>
<string name="setting_playback_plug_mgt_desc_on">Headset plug management is enabled</string>
<string name="setting_playback_plug_mgt_desc_off">Headset plug management is disabled</string>
<string name="setting_playback_plug_mgt_desc">Play/Pause when headset connection changes</string>
<string name="setting_behavior">Behavior</string>
<string name="setting_behavior_song_play">When a song is selected</string>
<!-- Debug Namespace | Debug labels -->
<string name="debug_state_saved">State saved</string>

View file

@ -22,8 +22,7 @@
<SwitchPreferenceCompat
app:key="KEY_EDGE"
android:title="@string/setting_edge"
app:summaryOn="@string/setting_edge_desc_on"
app:summaryOff="@string/setting_edge_desc_off"
app:summary="@string/setting_edge_desc"
app:iconSpaceReserved="false"
app:allowDividerBelow="false"
app:defaultValue="false" />
@ -45,8 +44,7 @@
<SwitchPreferenceCompat
app:key="KEY_COLOR_NOTIF"
android:title="@string/setting_color_notif"
app:summaryOn="@string/setting_color_desc_on"
app:summaryOff="@string/setting_color_desc_off"
app:summary="@string/setting_color_desc"
app:iconSpaceReserved="false"
app:defaultValue="true" />
@ -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" />
<SwitchPreferenceCompat
app:key="KEY_PLUG_MGT"
android:title="@string/setting_playback_plug_mgt"
app:iconSpaceReserved="false"
app:defaultValue="true"
app:summaryOn="@string/setting_playback_plug_mgt_desc_on"
app:summaryOff="@string/setting_playback_plug_mgt_desc_off" />
app:allowDividerBelow="false"
app:summary="@string/setting_playback_plug_mgt_desc" />
</PreferenceCategory>
<PreferenceCategory
android:title="@string/setting_behavior"
android:layout="@layout/item_header">
<ListPreference
app:key="KEY_SONG_PLAY_MODE"
android:title="@string/setting_behavior_song_play"
app:defaultValue="ALL_SONGS"
app:entries="@array/song_playback_mode_entries"
app:entryValues="@array/song_playback_mode_values"
app:iconSpaceReserved="false"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
</PreferenceScreen>

View file

@ -36,8 +36,7 @@
<SwitchPreferenceCompat
app:key="KEY_COLOR_NOTIF"
android:title="@string/setting_color_notif"
app:summaryOn="@string/setting_color_desc_on"
app:summaryOff="@string/setting_color_desc_off"
app:summary="@string/setting_color_desc"
app:iconSpaceReserved="false"
app:defaultValue="true" />
@ -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" />
<SwitchPreferenceCompat
app:key="KEY_PLUG_MGT"
android:title="@string/setting_playback_plug_mgt"
app:iconSpaceReserved="false"
app:defaultValue="true"
app:summaryOn="@string/setting_playback_plug_mgt_desc_on"
app:summaryOff="@string/setting_playback_plug_mgt_desc_off" />
app:allowDividerBelow="false"
app:summary="@string/setting_playback_plug_mgt_desc" />
</PreferenceCategory>
<PreferenceCategory
android:title="@string/setting_behavior"
android:layout="@layout/item_header">
<ListPreference
app:key="KEY_SONG_PLAY_MODE"
android:title="@string/setting_behavior_song_play"
app:defaultValue="ALL_SONGS"
app:entries="@array/song_playback_mode_entries"
app:entryValues="@array/song_playback_mode_values"
app:iconSpaceReserved="false"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
</PreferenceScreen>