playback: decouple fields and callback
Decouple the callback notifying code and the field code. This makes code more reasonable for future changes.
This commit is contained in:
parent
60367c45c3
commit
2bdbe212df
10 changed files with 186 additions and 158 deletions
|
@ -13,7 +13,7 @@
|
|||
- Made the layout of album songs more similar to other songs
|
||||
|
||||
#### Dev/Meta
|
||||
- Updated translations [Konstantin Tutsch -> German, cccClyde -> Chinese]
|
||||
- Updated translations [Konstantin Tutsch -> German, cccClyde -> Chinese, Gsset -> Russian]
|
||||
- Switched to spotless and ktfmt instead of ktlint
|
||||
- Migrated constants to centralized table
|
||||
- Introduced new RecyclerView framework
|
||||
|
|
|
@ -115,9 +115,9 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleRes: Int = 0)
|
|||
}
|
||||
|
||||
override fun isAutoMirrored(): Boolean = true
|
||||
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
|
||||
override fun setAlpha(alpha: Int) {}
|
||||
override fun setColorFilter(colorFilter: ColorFilter?) {}
|
||||
override fun getOpacity(): Int = PixelFormat.TRANSLUCENT
|
||||
|
||||
private fun updatePath() {
|
||||
val r = bounds.height().toFloat() / 2
|
||||
|
@ -168,6 +168,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleRes: Int = 0)
|
|||
}
|
||||
|
||||
companion object {
|
||||
// Cache sqrt(2) for faster calculations
|
||||
private const val SQRT2 = 1.4142135623730950488f
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,11 +135,11 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
removeCallbacks(hideThumbRunnable)
|
||||
showScrollbar()
|
||||
showPopup()
|
||||
onDragListener?.onFastScrollStart()
|
||||
listener?.onFastScrollStart()
|
||||
} else {
|
||||
postAutoHideScrollbar()
|
||||
hidePopup()
|
||||
onDragListener?.onFastScrollStop()
|
||||
listener?.onFastScrollStop()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
* A listener for when a drag event occurs. The value will be true if a drag has begun, and
|
||||
* false if a drag ended.
|
||||
*/
|
||||
var onDragListener: OnFastScrollListener? = null
|
||||
var listener: OnFastScrollListener? = null
|
||||
|
||||
init {
|
||||
overlay.add(thumbView)
|
||||
|
|
|
@ -52,7 +52,7 @@ abstract class HomeListFragment<T : Item> :
|
|||
override fun onBindingCreated(binding: FragmentHomeListBinding, savedInstanceState: Bundle?) {
|
||||
setupRecycler(binding.homeRecycler)
|
||||
binding.homeRecycler.popupProvider = this
|
||||
binding.homeRecycler.onDragListener = this
|
||||
binding.homeRecycler.listener = this
|
||||
}
|
||||
|
||||
override fun onDestroyBinding(binding: FragmentHomeListBinding) {
|
||||
|
@ -60,7 +60,7 @@ abstract class HomeListFragment<T : Item> :
|
|||
binding.homeRecycler.apply {
|
||||
adapter = null
|
||||
popupProvider = null
|
||||
onDragListener = null
|
||||
listener = null
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -314,13 +314,13 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
|
|||
private fun restorePlaybackState() {
|
||||
logD("Attempting to restore playback state")
|
||||
|
||||
onSongUpdate(playbackManager.song)
|
||||
onPositionUpdate(playbackManager.position)
|
||||
onParentUpdate(playbackManager.parent)
|
||||
onQueueUpdate(playbackManager.queue, playbackManager.index)
|
||||
onPlayingUpdate(playbackManager.isPlaying)
|
||||
onShuffleUpdate(playbackManager.isShuffling)
|
||||
onLoopUpdate(playbackManager.loopMode)
|
||||
onSongChanged(playbackManager.song)
|
||||
onPositionChanged(playbackManager.position)
|
||||
onParentChanged(playbackManager.parent)
|
||||
onQueueChanged(playbackManager.queue, playbackManager.index)
|
||||
onPlayingChanged(playbackManager.isPlaying)
|
||||
onShuffleChanged(playbackManager.isShuffling)
|
||||
onLoopModeChanged(playbackManager.loopMode)
|
||||
}
|
||||
|
||||
// --- OVERRIDES ---
|
||||
|
@ -329,31 +329,31 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
|
|||
playbackManager.removeCallback(this)
|
||||
}
|
||||
|
||||
override fun onSongUpdate(song: Song?) {
|
||||
override fun onSongChanged(song: Song?) {
|
||||
mSong.value = song
|
||||
}
|
||||
|
||||
override fun onParentUpdate(parent: MusicParent?) {
|
||||
override fun onParentChanged(parent: MusicParent?) {
|
||||
mParent.value = parent
|
||||
}
|
||||
|
||||
override fun onPositionUpdate(position: Long) {
|
||||
override fun onPositionChanged(position: Long) {
|
||||
mPositionSeconds.value = position / 1000
|
||||
}
|
||||
|
||||
override fun onQueueUpdate(queue: List<Song>, index: Int) {
|
||||
override fun onQueueChanged(queue: List<Song>, index: Int) {
|
||||
mNextUp.value = queue.slice(index.inc() until queue.size)
|
||||
}
|
||||
|
||||
override fun onPlayingUpdate(isPlaying: Boolean) {
|
||||
override fun onPlayingChanged(isPlaying: Boolean) {
|
||||
mIsPlaying.value = isPlaying
|
||||
}
|
||||
|
||||
override fun onShuffleUpdate(isShuffling: Boolean) {
|
||||
override fun onShuffleChanged(isShuffling: Boolean) {
|
||||
mIsShuffling.value = isShuffling
|
||||
}
|
||||
|
||||
override fun onLoopUpdate(loopMode: LoopMode) {
|
||||
override fun onLoopModeChanged(loopMode: LoopMode) {
|
||||
mLoopMode.value = loopMode
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,42 +48,17 @@ class PlaybackStateManager private constructor() {
|
|||
|
||||
// Playback
|
||||
private var mSong: Song? = null
|
||||
set(value) {
|
||||
field = value
|
||||
callbacks.forEach { it.onSongUpdate(value) }
|
||||
}
|
||||
private var mPosition: Long = 0
|
||||
set(value) {
|
||||
field = value
|
||||
callbacks.forEach { it.onPositionUpdate(value) }
|
||||
}
|
||||
private var mParent: MusicParent? = null
|
||||
set(value) {
|
||||
field = value
|
||||
callbacks.forEach { it.onParentUpdate(value) }
|
||||
}
|
||||
|
||||
// Queue
|
||||
private var mQueue = mutableListOf<Song>()
|
||||
private var mIndex = 0
|
||||
|
||||
// Status
|
||||
// State
|
||||
private var mIsPlaying = false
|
||||
set(value) {
|
||||
field = value
|
||||
callbacks.forEach { it.onPlayingUpdate(value) }
|
||||
}
|
||||
|
||||
private var mPosition: Long = 0
|
||||
private var mIsShuffling = false
|
||||
set(value) {
|
||||
field = value
|
||||
callbacks.forEach { it.onShuffleUpdate(value) }
|
||||
}
|
||||
private var mLoopMode = LoopMode.NONE
|
||||
set(value) {
|
||||
field = value
|
||||
callbacks.forEach { it.onLoopUpdate(value) }
|
||||
}
|
||||
|
||||
private var mIsRestored = false
|
||||
private var mHasPlayed = false
|
||||
|
@ -94,24 +69,26 @@ class PlaybackStateManager private constructor() {
|
|||
/** The parent the queue is based on, null if all_songs */
|
||||
val parent: MusicParent?
|
||||
get() = mParent
|
||||
/** The current playback progress */
|
||||
val position: Long
|
||||
get() = mPosition
|
||||
/** The current queue determined by [parent] and [playbackMode] */
|
||||
/** The current queue determined by [parent] */
|
||||
val queue: List<Song>
|
||||
get() = mQueue
|
||||
/** The current position in the queue */
|
||||
val index: Int
|
||||
get() = mIndex
|
||||
|
||||
/** Whether playback is paused or not */
|
||||
val isPlaying: Boolean
|
||||
get() = mIsPlaying
|
||||
/** Whether the queue is shuffled */
|
||||
val isShuffling: Boolean
|
||||
get() = mIsShuffling
|
||||
/** The current playback progress */
|
||||
val position: Long
|
||||
get() = mPosition
|
||||
/** The current [LoopMode] */
|
||||
val loopMode: LoopMode
|
||||
get() = mLoopMode
|
||||
/** Whether the queue is shuffled */
|
||||
val isShuffling: Boolean
|
||||
get() = mIsShuffling
|
||||
|
||||
/** Whether this instance has already been restored */
|
||||
val isRestored: Boolean
|
||||
get() = mIsRestored
|
||||
|
@ -165,9 +142,11 @@ class PlaybackStateManager private constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
notifyParentChanged()
|
||||
|
||||
updatePlayback(song)
|
||||
// Keep shuffle on, if enabled
|
||||
setShuffling(settingsManager.keepShuffle && mIsShuffling, keepSong = true)
|
||||
setShuffling(settingsManager.keepShuffle && isShuffling, keepSong = true)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,19 +157,21 @@ class PlaybackStateManager private constructor() {
|
|||
logD("Playing ${parent.rawName}")
|
||||
|
||||
mParent = parent
|
||||
notifyParentChanged()
|
||||
mIndex = 0
|
||||
|
||||
when (parent) {
|
||||
is Album -> {
|
||||
mQueue = parent.songs.toMutableList()
|
||||
mQueue =
|
||||
when (parent) {
|
||||
is Album -> {
|
||||
parent.songs.toMutableList()
|
||||
}
|
||||
is Artist -> {
|
||||
parent.songs.toMutableList()
|
||||
}
|
||||
is Genre -> {
|
||||
parent.songs.toMutableList()
|
||||
}
|
||||
}
|
||||
is Artist -> {
|
||||
mQueue = parent.songs.toMutableList()
|
||||
}
|
||||
is Genre -> {
|
||||
mQueue = parent.songs.toMutableList()
|
||||
}
|
||||
}
|
||||
|
||||
setShuffling(shuffled, keepSong = false)
|
||||
updatePlayback(mQueue[0])
|
||||
|
@ -211,6 +192,8 @@ class PlaybackStateManager private constructor() {
|
|||
private fun updatePlayback(song: Song, shouldPlay: Boolean = true) {
|
||||
mSong = song
|
||||
mPosition = 0
|
||||
notifySongChanged()
|
||||
notifyPositionChanged()
|
||||
setPlaying(shouldPlay)
|
||||
}
|
||||
|
||||
|
@ -225,10 +208,10 @@ class PlaybackStateManager private constructor() {
|
|||
updatePlayback(mQueue[mIndex])
|
||||
} else {
|
||||
mIndex = 0
|
||||
updatePlayback(mQueue[mIndex], shouldPlay = mLoopMode == LoopMode.ALL)
|
||||
updatePlayback(mQueue[mIndex], shouldPlay = loopMode == LoopMode.ALL)
|
||||
}
|
||||
|
||||
pushQueueUpdate()
|
||||
notifyQueueChanged()
|
||||
}
|
||||
|
||||
/** Go to the previous song, doing any checks that are needed. */
|
||||
|
@ -243,7 +226,7 @@ class PlaybackStateManager private constructor() {
|
|||
}
|
||||
|
||||
updatePlayback(mQueue[mIndex])
|
||||
pushQueueUpdate()
|
||||
notifyQueueChanged()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,7 +241,7 @@ class PlaybackStateManager private constructor() {
|
|||
|
||||
logD("Removing item ${mQueue[index].rawName}")
|
||||
mQueue.removeAt(index)
|
||||
pushQueueUpdate()
|
||||
notifyQueueChanged()
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -271,7 +254,7 @@ class PlaybackStateManager private constructor() {
|
|||
|
||||
logD("Moving item $from to position $to")
|
||||
mQueue.add(to, mQueue.removeAt(from))
|
||||
pushQueueUpdate()
|
||||
notifyQueueChanged()
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -282,7 +265,7 @@ class PlaybackStateManager private constructor() {
|
|||
}
|
||||
|
||||
mQueue.add(mIndex + 1, song)
|
||||
pushQueueUpdate()
|
||||
notifyQueueChanged()
|
||||
}
|
||||
|
||||
/** Add a list of [songs] to the top of the queue. */
|
||||
|
@ -292,24 +275,19 @@ class PlaybackStateManager private constructor() {
|
|||
}
|
||||
|
||||
mQueue.addAll(mIndex + 1, songs)
|
||||
pushQueueUpdate()
|
||||
notifyQueueChanged()
|
||||
}
|
||||
|
||||
/** Add a [song] to the end of the queue. */
|
||||
fun addToQueue(song: Song) {
|
||||
mQueue.add(song)
|
||||
pushQueueUpdate()
|
||||
notifyQueueChanged()
|
||||
}
|
||||
|
||||
/** Add a list of [songs] to the end of the queue. */
|
||||
fun addToQueue(songs: List<Song>) {
|
||||
mQueue.addAll(songs)
|
||||
pushQueueUpdate()
|
||||
}
|
||||
|
||||
/** Force any callbacks to receive a queue update. */
|
||||
private fun pushQueueUpdate() {
|
||||
callbacks.forEach { it.onQueueUpdate(mQueue, mIndex) }
|
||||
notifyQueueChanged()
|
||||
}
|
||||
|
||||
// --- SHUFFLE FUNCTIONS ---
|
||||
|
@ -320,6 +298,7 @@ class PlaybackStateManager private constructor() {
|
|||
*/
|
||||
fun setShuffling(shuffled: Boolean, keepSong: Boolean) {
|
||||
mIsShuffling = shuffled
|
||||
notifyShufflingChanged()
|
||||
|
||||
if (mIsShuffling) {
|
||||
genShuffle(keepSong)
|
||||
|
@ -348,7 +327,7 @@ class PlaybackStateManager private constructor() {
|
|||
mSong = mQueue[0]
|
||||
}
|
||||
|
||||
pushQueueUpdate()
|
||||
notifyQueueChanged()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -359,20 +338,20 @@ class PlaybackStateManager private constructor() {
|
|||
val library = musicStore.library ?: return
|
||||
val lastSong = mSong
|
||||
|
||||
val parent = parent
|
||||
mQueue =
|
||||
when (parent) {
|
||||
null -> settingsManager.libSongSort.songs(library.songs).toMutableList()
|
||||
is Album -> settingsManager.detailAlbumSort.album(mParent as Album).toMutableList()
|
||||
is Artist ->
|
||||
settingsManager.detailArtistSort.artist(mParent as Artist).toMutableList()
|
||||
is Genre -> settingsManager.detailGenreSort.genre(mParent as Genre).toMutableList()
|
||||
is Album -> settingsManager.detailAlbumSort.album(parent).toMutableList()
|
||||
is Artist -> settingsManager.detailArtistSort.artist(parent).toMutableList()
|
||||
is Genre -> settingsManager.detailGenreSort.genre(parent).toMutableList()
|
||||
}
|
||||
|
||||
if (keepSong) {
|
||||
mIndex = mQueue.indexOf(lastSong)
|
||||
}
|
||||
|
||||
pushQueueUpdate()
|
||||
notifyQueueChanged()
|
||||
}
|
||||
|
||||
// --- STATE FUNCTIONS ---
|
||||
|
@ -385,6 +364,10 @@ class PlaybackStateManager private constructor() {
|
|||
}
|
||||
|
||||
mIsPlaying = playing
|
||||
|
||||
for (callback in callbacks) {
|
||||
callback.onPlayingChanged(playing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,11 +376,12 @@ class PlaybackStateManager private constructor() {
|
|||
* @param position The new position in millis.
|
||||
* @see seekTo
|
||||
*/
|
||||
fun setPosition(position: Long) {
|
||||
fun synchronizePosition(position: Long) {
|
||||
mSong?.let { song ->
|
||||
// Don't accept any bugged positions that are over the duration of the song.
|
||||
if (position <= song.duration) {
|
||||
mPosition = position
|
||||
notifyPositionChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -409,6 +393,7 @@ class PlaybackStateManager private constructor() {
|
|||
*/
|
||||
fun seekTo(position: Long) {
|
||||
mPosition = position
|
||||
notifyPositionChanged()
|
||||
callbacks.forEach { it.onSeek(position) }
|
||||
}
|
||||
|
||||
|
@ -427,6 +412,7 @@ class PlaybackStateManager private constructor() {
|
|||
/** Set the [LoopMode] to [mode]. */
|
||||
fun setLoopMode(mode: LoopMode) {
|
||||
mLoopMode = mode
|
||||
notifyLoopModeChanged()
|
||||
}
|
||||
|
||||
/** Mark whether this instance has played or not */
|
||||
|
@ -463,13 +449,13 @@ class PlaybackStateManager private constructor() {
|
|||
|
||||
database.writeState(
|
||||
PlaybackStateDatabase.SavedState(
|
||||
mSong,
|
||||
mPosition,
|
||||
mParent,
|
||||
mIndex,
|
||||
song,
|
||||
position,
|
||||
parent,
|
||||
index,
|
||||
playbackMode,
|
||||
mIsShuffling,
|
||||
mLoopMode,
|
||||
isShuffling,
|
||||
loopMode,
|
||||
))
|
||||
|
||||
database.writeQueue(mQueue)
|
||||
|
@ -503,7 +489,7 @@ class PlaybackStateManager private constructor() {
|
|||
if (playbackState != null) {
|
||||
unpackFromPlaybackState(playbackState)
|
||||
mQueue = queue
|
||||
pushQueueUpdate()
|
||||
notifyQueueChanged()
|
||||
doParentSanityCheck(playbackState.playbackMode)
|
||||
doIndexSanityCheck()
|
||||
}
|
||||
|
@ -515,8 +501,6 @@ class PlaybackStateManager private constructor() {
|
|||
|
||||
/** Unpack a [playbackState] into this instance. */
|
||||
private fun unpackFromPlaybackState(playbackState: PlaybackStateDatabase.SavedState) {
|
||||
// Turn the simplified information from PlaybackState into usable data.
|
||||
|
||||
// Do queue setup first
|
||||
mParent = playbackState.parent
|
||||
mIndex = playbackState.queueIndex
|
||||
|
@ -526,7 +510,11 @@ class PlaybackStateManager private constructor() {
|
|||
mLoopMode = playbackState.loopMode
|
||||
mIsShuffling = playbackState.isShuffling
|
||||
|
||||
notifySongChanged()
|
||||
notifyParentChanged()
|
||||
seekTo(playbackState.position)
|
||||
notifyShufflingChanged()
|
||||
notifyLoopModeChanged()
|
||||
}
|
||||
|
||||
/** Do a sanity check to make sure the parent was not lost in the restore process. */
|
||||
|
@ -542,6 +530,8 @@ class PlaybackStateManager private constructor() {
|
|||
PlaybackMode.IN_ARTIST -> mQueue.firstOrNull()?.album?.artist
|
||||
PlaybackMode.IN_GENRE -> mQueue.firstOrNull()?.genre
|
||||
}
|
||||
|
||||
notifyParentChanged()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -554,7 +544,7 @@ class PlaybackStateManager private constructor() {
|
|||
if (correctedIndex > -1) {
|
||||
logD("Correcting malformed index to $correctedIndex")
|
||||
mIndex = correctedIndex
|
||||
pushQueueUpdate()
|
||||
notifyQueueChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -591,19 +581,57 @@ class PlaybackStateManager private constructor() {
|
|||
}
|
||||
}
|
||||
|
||||
// --- CALLBACKS ---
|
||||
|
||||
private fun notifySongChanged() {
|
||||
for (callback in callbacks) {
|
||||
callback.onSongChanged(song)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyParentChanged() {
|
||||
for (callback in callbacks) {
|
||||
callback.onParentChanged(parent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyPositionChanged() {
|
||||
for (callback in callbacks) {
|
||||
callback.onPositionChanged(position)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyLoopModeChanged() {
|
||||
for (callback in callbacks) {
|
||||
callback.onLoopModeChanged(loopMode)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyShufflingChanged() {
|
||||
for (callback in callbacks) {
|
||||
callback.onShuffleChanged(isShuffling)
|
||||
}
|
||||
}
|
||||
|
||||
/** Force any callbacks to receive a queue update. */
|
||||
private fun notifyQueueChanged() {
|
||||
for (callback in callbacks) {
|
||||
callback.onQueueChanged(mQueue, mIndex)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface for receiving updates from [PlaybackStateManager]. Add the callback to
|
||||
* [PlaybackStateManager] using [addCallback], remove them on destruction with [removeCallback].
|
||||
*/
|
||||
interface Callback {
|
||||
fun onSongUpdate(song: Song?) {}
|
||||
fun onParentUpdate(parent: MusicParent?) {}
|
||||
fun onPositionUpdate(position: Long) {}
|
||||
fun onQueueUpdate(queue: List<Song>, index: Int) {}
|
||||
fun onModeUpdate(mode: PlaybackMode) {}
|
||||
fun onPlayingUpdate(isPlaying: Boolean) {}
|
||||
fun onShuffleUpdate(isShuffling: Boolean) {}
|
||||
fun onLoopUpdate(loopMode: LoopMode) {}
|
||||
fun onSongChanged(song: Song?) {}
|
||||
fun onParentChanged(parent: MusicParent?) {}
|
||||
fun onPositionChanged(position: Long) {}
|
||||
fun onQueueChanged(queue: List<Song>, index: Int) {}
|
||||
fun onPlayingChanged(isPlaying: Boolean) {}
|
||||
fun onShuffleChanged(isShuffling: Boolean) {}
|
||||
fun onLoopModeChanged(loopMode: LoopMode) {}
|
||||
fun onSeek(position: Long) {}
|
||||
}
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ class PlaybackService :
|
|||
|
||||
positionScope.launch {
|
||||
while (true) {
|
||||
playbackManager.setPosition(player.currentPosition)
|
||||
playbackManager.synchronizePosition(player.currentPosition)
|
||||
delay(POS_POLL_INTERVAL)
|
||||
}
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ class PlaybackService :
|
|||
reason: Int
|
||||
) {
|
||||
if (reason == Player.DISCONTINUITY_REASON_SEEK) {
|
||||
playbackManager.setPosition(player.currentPosition)
|
||||
playbackManager.synchronizePosition(player.currentPosition)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,7 +258,7 @@ class PlaybackService :
|
|||
|
||||
// --- PLAYBACK STATE CALLBACK OVERRIDES ---
|
||||
|
||||
override fun onSongUpdate(song: Song?) {
|
||||
override fun onSongChanged(song: Song?) {
|
||||
if (song != null) {
|
||||
logD("Setting player to ${song.rawName}")
|
||||
player.setMediaItem(MediaItem.fromUri(song.uri))
|
||||
|
@ -273,25 +273,25 @@ class PlaybackService :
|
|||
stopForegroundAndNotification()
|
||||
}
|
||||
|
||||
override fun onParentUpdate(parent: MusicParent?) {
|
||||
override fun onParentChanged(parent: MusicParent?) {
|
||||
notification.setParent(parent)
|
||||
startForegroundOrNotify()
|
||||
}
|
||||
|
||||
override fun onPlayingUpdate(isPlaying: Boolean) {
|
||||
override fun onPlayingChanged(isPlaying: Boolean) {
|
||||
player.playWhenReady = isPlaying
|
||||
notification.setPlaying(isPlaying)
|
||||
startForegroundOrNotify()
|
||||
}
|
||||
|
||||
override fun onLoopUpdate(loopMode: LoopMode) {
|
||||
override fun onLoopModeChanged(loopMode: LoopMode) {
|
||||
if (!settingsManager.useAltNotifAction) {
|
||||
notification.setLoop(loopMode)
|
||||
startForegroundOrNotify()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onShuffleUpdate(isShuffling: Boolean) {
|
||||
override fun onShuffleChanged(isShuffling: Boolean) {
|
||||
if (settingsManager.useAltNotifAction) {
|
||||
notification.setShuffle(isShuffling)
|
||||
startForegroundOrNotify()
|
||||
|
@ -306,7 +306,7 @@ class PlaybackService :
|
|||
|
||||
override fun onColorizeNotifUpdate(doColorize: Boolean) {
|
||||
playbackManager.song?.let { song ->
|
||||
connector.onSongUpdate(song)
|
||||
connector.onSongChanged(song)
|
||||
notification.setMetadata(song, ::startForegroundOrNotify)
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ class PlaybackService :
|
|||
|
||||
override fun onShowCoverUpdate(showCovers: Boolean) {
|
||||
playbackManager.song?.let { song ->
|
||||
connector.onSongUpdate(song)
|
||||
connector.onSongChanged(song)
|
||||
notification.setMetadata(song, ::startForegroundOrNotify)
|
||||
}
|
||||
}
|
||||
|
@ -376,11 +376,11 @@ class PlaybackService :
|
|||
logD("Restoring the service state")
|
||||
|
||||
// Re-call existing callbacks with the current values to restore everything
|
||||
onParentUpdate(playbackManager.parent)
|
||||
onPlayingUpdate(playbackManager.isPlaying)
|
||||
onShuffleUpdate(playbackManager.isShuffling)
|
||||
onLoopUpdate(playbackManager.loopMode)
|
||||
onSongUpdate(playbackManager.song)
|
||||
onParentChanged(playbackManager.parent)
|
||||
onPlayingChanged(playbackManager.isPlaying)
|
||||
onShuffleChanged(playbackManager.isShuffling)
|
||||
onLoopModeChanged(playbackManager.loopMode)
|
||||
onSongChanged(playbackManager.song)
|
||||
onSeek(playbackManager.position)
|
||||
|
||||
// Notify other classes that rely on this service to also update.
|
||||
|
|
|
@ -47,8 +47,8 @@ class PlaybackSessionConnector(
|
|||
playbackManager.addCallback(this)
|
||||
player.addListener(this)
|
||||
|
||||
onSongUpdate(playbackManager.song)
|
||||
onPlayingUpdate(playbackManager.isPlaying)
|
||||
onSongChanged(playbackManager.song)
|
||||
onPlayingChanged(playbackManager.isPlaying)
|
||||
}
|
||||
|
||||
fun release() {
|
||||
|
@ -108,7 +108,7 @@ class PlaybackSessionConnector(
|
|||
|
||||
// --- PLAYBACKSTATEMANAGER CALLBACKS ---
|
||||
|
||||
override fun onSongUpdate(song: Song?) {
|
||||
override fun onSongChanged(song: Song?) {
|
||||
if (song == null) {
|
||||
mediaSession.setMetadata(emptyMetadata)
|
||||
return
|
||||
|
@ -137,7 +137,7 @@ class PlaybackSessionConnector(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onPlayingUpdate(isPlaying: Boolean) {
|
||||
override fun onPlayingChanged(isPlaying: Boolean) {
|
||||
invalidateSessionState()
|
||||
}
|
||||
|
||||
|
|
|
@ -64,41 +64,39 @@ class ReplayGainAudioProcessor : BaseAudioProcessor() {
|
|||
* Vanilla Music's implementation.
|
||||
*/
|
||||
fun applyReplayGain(metadata: Metadata?) {
|
||||
if (metadata == null) {
|
||||
logW("No metadata could be extracted from this track")
|
||||
if (metadata == null || settingsManager.replayGainMode == ReplayGainMode.OFF) {
|
||||
logW(
|
||||
"Not applying replaygain [" +
|
||||
"metadata: ${metadata != null}, " +
|
||||
"enabled: ${settingsManager.replayGainMode == ReplayGainMode.OFF}]")
|
||||
volume = 1f
|
||||
return
|
||||
}
|
||||
|
||||
// ReplayGain is configurable, so determine what to do based off of the mode.
|
||||
val useAlbumGain: (Gain) -> Boolean =
|
||||
when (settingsManager.replayGainMode) {
|
||||
ReplayGainMode.OFF -> {
|
||||
logD("ReplayGain is off")
|
||||
volume = 1f
|
||||
return
|
||||
}
|
||||
|
||||
// User wants track gain to be preferred. Default to album gain only if there
|
||||
// is no track gain.
|
||||
ReplayGainMode.TRACK -> { gain -> gain.track == 0f }
|
||||
|
||||
// User wants album gain to be preferred. Default to track gain only if there
|
||||
// is no album gain.
|
||||
ReplayGainMode.ALBUM -> { gain -> gain.album != 0f }
|
||||
|
||||
// User wants album gain to be used when in an album, track gain otherwise.
|
||||
ReplayGainMode.DYNAMIC -> { _ ->
|
||||
playbackManager.parent is Album &&
|
||||
playbackManager.song?.album == playbackManager.parent
|
||||
}
|
||||
}
|
||||
|
||||
val gain = parseReplayGain(metadata)
|
||||
|
||||
val adjust =
|
||||
if (gain != null) {
|
||||
if (useAlbumGain(gain)) {
|
||||
// ReplayGain is configurable, so determine what to do based off of the mode.
|
||||
val useAlbumGain =
|
||||
when (settingsManager.replayGainMode) {
|
||||
ReplayGainMode.OFF -> error("Unreachable")
|
||||
|
||||
// User wants track gain to be preferred. Default to album gain only if
|
||||
// there is no track gain.
|
||||
ReplayGainMode.TRACK -> gain.track == 0f
|
||||
|
||||
// User wants album gain to be preferred. Default to track gain only if
|
||||
// here is no album gain.
|
||||
ReplayGainMode.ALBUM -> gain.album != 0f
|
||||
|
||||
// User wants album gain to be used when in an album, track gain otherwise.
|
||||
ReplayGainMode.DYNAMIC ->
|
||||
playbackManager.parent is Album &&
|
||||
playbackManager.song?.album?.id == playbackManager.parent?.id
|
||||
}
|
||||
|
||||
if (useAlbumGain) {
|
||||
logD("Using album gain")
|
||||
gain.album
|
||||
} else {
|
||||
|
@ -177,6 +175,7 @@ class ReplayGainAudioProcessor : BaseAudioProcessor() {
|
|||
}
|
||||
|
||||
private fun parseReplayGainFloat(raw: String): Float {
|
||||
// Grok a float from a ReplayGain tag by removing everything that is not 0-9, , or -.
|
||||
return try {
|
||||
raw.replace(Regex("[^0-9.-]"), "").toFloat()
|
||||
} catch (e: Exception) {
|
||||
|
@ -211,11 +210,11 @@ class ReplayGainAudioProcessor : BaseAudioProcessor() {
|
|||
}
|
||||
} else {
|
||||
for (i in position until limit step 2) {
|
||||
var sample = inputBuffer.getLeShort(i)
|
||||
// Clamp the values to the minimum and maximum values possible for the
|
||||
// encoding. This prevents issues where samples amplified beyond 1 << 16
|
||||
// will end up becoming truncated during the conversion to a short,
|
||||
// Ensure we clamp the values to the minimum and maximum values possible
|
||||
// for the encoding. This prevents issues where samples amplified beyond
|
||||
// 1 << 16 will end up becoming truncated during the conversion to a short,
|
||||
// resulting in popping.
|
||||
var sample = inputBuffer.getLeShort(i)
|
||||
sample =
|
||||
(sample * volume)
|
||||
.toInt()
|
||||
|
|
|
@ -61,19 +61,19 @@ class WidgetController(private val context: Context) :
|
|||
|
||||
// --- PLAYBACKSTATEMANAGER CALLBACKS ---
|
||||
|
||||
override fun onSongUpdate(song: Song?) {
|
||||
override fun onSongChanged(song: Song?) {
|
||||
widget.update(context, playbackManager)
|
||||
}
|
||||
|
||||
override fun onPlayingUpdate(isPlaying: Boolean) {
|
||||
override fun onPlayingChanged(isPlaying: Boolean) {
|
||||
widget.update(context, playbackManager)
|
||||
}
|
||||
|
||||
override fun onShuffleUpdate(isShuffling: Boolean) {
|
||||
override fun onShuffleChanged(isShuffling: Boolean) {
|
||||
widget.update(context, playbackManager)
|
||||
}
|
||||
|
||||
override fun onLoopUpdate(loopMode: LoopMode) {
|
||||
override fun onLoopModeChanged(loopMode: LoopMode) {
|
||||
widget.update(context, playbackManager)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue