Make Notification show currently played model

Make the playback notification show the currently played music model [e.g the genre/artist/album thats being played].
This commit is contained in:
OxygenCobalt 2020-11-01 19:58:20 -07:00
parent 344e566aa3
commit 188d7e047f
6 changed files with 45 additions and 15 deletions

View file

@ -10,7 +10,7 @@ android {
defaultConfig {
applicationId "org.oxycblt.auxio"
minSdkVersion 24
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
@ -56,7 +56,7 @@ dependencies {
implementation 'androidx.fragment:fragment-ktx:1.3.0-beta01'
// Layout
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
// Lifecycle
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"

View file

@ -5,14 +5,22 @@ import android.content.Intent
import android.util.AttributeSet
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import org.oxycblt.auxio.playback.PlaybackService
import org.oxycblt.auxio.theme.accent
// FIXME: Fix bug where fast navigation will break the animations and
// lead to nothing being displayed [Possibly Un-fixable]
// TODO: Test for compatibility
// API 30 - No Issues
// API 29 - No Issues [Primary Testing Version]
// API 28-23 - Not tested yet
// API 22 - ProgressBar/SeekBar look wonky, RecyclerView dividers don't show
// API 21 - Not tested yet
class MainActivity : AppCompatActivity(R.layout.activity_main) {
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
// Apply the theme
setTheme(accent.second)

View file

@ -15,6 +15,7 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.coil.getBitmap
import org.oxycblt.auxio.playback.state.LoopMode
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.playback.state.PlaybackStateManager
object NotificationUtils {
@ -52,8 +53,7 @@ fun NotificationManager.createMediaNotification(
)
// TODO: Things that probably aren't possible but would be nice
// - Swipe to close instead of a button to press
// - Playing intent takes you to now playing screen instead of elsewhere
// - Playing intent takes you to PlaybackFragment instead of MainFragment
return NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID)
.setSmallIcon(R.drawable.ic_song)
.setStyle(
@ -64,12 +64,12 @@ fun NotificationManager.createMediaNotification(
.setCategory(NotificationCompat.CATEGORY_SERVICE)
.setChannelId(NotificationUtils.CHANNEL_ID)
.setShowWhen(false)
.setTicker(context.getString(R.string.title_playback))
.addAction(newAction(NotificationUtils.ACTION_LOOP, context))
.addAction(newAction(NotificationUtils.ACTION_SKIP_PREV, context))
.addAction(newAction(NotificationUtils.ACTION_PLAY_PAUSE, context))
.addAction(newAction(NotificationUtils.ACTION_SKIP_NEXT, context))
.addAction(newAction(NotificationUtils.ACTION_EXIT, context))
.setNotificationSilent()
.setSubText(context.getString(R.string.title_playback))
.setContentIntent(mainIntent)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
@ -91,8 +91,6 @@ fun NotificationCompat.Builder.setMetadata(song: Song, context: Context, onDone:
@SuppressLint("RestrictedApi")
fun NotificationCompat.Builder.updatePlaying(context: Context) {
mActions[2] = newAction(NotificationUtils.ACTION_PLAY_PAUSE, context)
setOngoing(PlaybackStateManager.getInstance().isPlaying)
}
@SuppressLint("RestrictedApi")
@ -100,6 +98,18 @@ fun NotificationCompat.Builder.updateLoop(context: Context) {
mActions[0] = newAction(NotificationUtils.ACTION_LOOP, context)
}
@SuppressLint("RestrictedApi")
fun NotificationCompat.Builder.updateMode(context: Context) {
val playbackManager = PlaybackStateManager.getInstance()
// If the mode is ALL_SONGS, then just put a string, otherwise put the parent model's name.
if (playbackManager.mode == PlaybackMode.ALL_SONGS) {
setSubText(context.getString(R.string.title_all_songs))
} else {
setSubText(playbackManager.parent!!.name)
}
}
private fun newAction(action: String, context: Context): NotificationCompat.Action {
val playbackManager = PlaybackStateManager.getInstance()

View file

@ -38,6 +38,7 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.coil.getBitmap
import org.oxycblt.auxio.music.toURI
import org.oxycblt.auxio.playback.state.LoopMode
import org.oxycblt.auxio.playback.state.PlaybackMode
import org.oxycblt.auxio.playback.state.PlaybackStateCallback
import org.oxycblt.auxio.playback.state.PlaybackStateManager
@ -57,7 +58,6 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
private var changeIsFromAudioFocus = true
private var isForeground = false
private var isDetachedFromUI = false
private val serviceJob = Job()
private val serviceScope = CoroutineScope(
@ -220,6 +220,12 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateCallback {
stopForegroundAndNotification()
}
override fun onModeUpdate(mode: PlaybackMode) {
notification.updateMode(this)
startForegroundOrNotify()
}
override fun onPlayingUpdate(isPlaying: Boolean) {
changeIsFromAudioFocus = false

View file

@ -6,6 +6,7 @@ interface PlaybackStateCallback {
fun onSongUpdate(song: Song?) {}
fun onPositionUpdate(position: Long) {}
fun onQueueUpdate(queue: MutableList<Song>) {}
fun onModeUpdate(mode: PlaybackMode) {}
fun onIndexUpdate(index: Int) {}
fun onPlayingUpdate(isPlaying: Boolean) {}
fun onShuffleUpdate(isShuffling: Boolean) {}

View file

@ -11,7 +11,7 @@ import org.oxycblt.auxio.music.Song
import kotlin.random.Random
// The manager of the current playback state [Current Song, Queue, Shuffling]
// This class is for sole use by the classes in /playback/.
// This class is for sole use by the code in /playback/.
// If you want to add system-side things, add to PlaybackService.
// If you want to add ui-side things, add to PlaybackViewModel.
// [Yes, I know MediaSessionCompat exists, but I like having full control over the
@ -42,6 +42,10 @@ class PlaybackStateManager private constructor() {
callbacks.forEach { it.onIndexUpdate(value) }
}
private var mMode = PlaybackMode.ALL_SONGS
set(value) {
field = value
callbacks.forEach { it.onModeUpdate(value) }
}
private var mIsPlaying = false
set(value) {
@ -62,9 +66,11 @@ class PlaybackStateManager private constructor() {
}
val song: Song? get() = mSong
val parent: BaseModel? get() = mParent
val position: Long get() = mPosition
val queue: MutableList<Song> get() = mQueue
val index: Int get() = mIndex
val mode: PlaybackMode get() = mMode
val isPlaying: Boolean get() = mIsPlaying
val isShuffling: Boolean get() = mIsShuffling
val loopMode: LoopMode get() = mLoopMode
@ -136,6 +142,10 @@ class PlaybackStateManager private constructor() {
Log.d(this::class.simpleName, "Playing ${baseModel.name}")
mParent = baseModel
mIndex = 0
mIsShuffling = shuffled
when (baseModel) {
is Album -> {
mQueue = orderSongsInAlbum(baseModel)
@ -157,10 +167,6 @@ class PlaybackStateManager private constructor() {
updatePlayback(mQueue[0])
mIndex = 0
mParent = baseModel
mIsShuffling = shuffled
if (mIsShuffling) {
genShuffle(false)
} else {
@ -178,8 +184,7 @@ class PlaybackStateManager private constructor() {
}
fun setPosition(position: Long) {
// Due to the hacky way I poll ExoPlayer positions, don't accept any bugged positions
// that are over the duration of the song.
// Don't accept any bugged positions that are over the duration of the song.
mSong?.let {
if (position <= it.duration) {
mPosition = position