From 0a0828684c08d83a4d332f024e47004e03d9272d Mon Sep 17 00:00:00 2001 From: OxygenCobalt Date: Thu, 3 Dec 2020 20:22:15 -0700 Subject: [PATCH] Add notification settings Add some notification settings to change the action & the colorization. --- .../auxio/playback/NotificationUtils.kt | 41 +++++++++++++++---- .../oxycblt/auxio/playback/PlaybackService.kt | 41 +++++++++++++++++-- .../oxycblt/auxio/settings/SettingUtils.kt | 3 ++ .../oxycblt/auxio/settings/SettingsManager.kt | 36 ++++++++++++---- ...loop_disabled.xml => ic_loop_inactive.xml} | 0 .../main/res/drawable/ic_shuffle_inactive.xml | 10 +++++ app/src/main/res/values/strings.xml | 11 ++++- app/src/main/res/xml-v27/prefs_main.xml | 23 +++++++++++ 8 files changed, 143 insertions(+), 22 deletions(-) rename app/src/main/res/drawable/{ic_loop_disabled.xml => ic_loop_inactive.xml} (100%) create mode 100644 app/src/main/res/drawable/ic_shuffle_inactive.xml diff --git a/app/src/main/java/org/oxycblt/auxio/playback/NotificationUtils.kt b/app/src/main/java/org/oxycblt/auxio/playback/NotificationUtils.kt index 8796e62a1..ebd2e4d18 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/NotificationUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/NotificationUtils.kt @@ -8,6 +8,7 @@ import android.content.Context import android.content.Intent import android.os.Build import android.support.v4.media.session.MediaSessionCompat +import android.util.Log import androidx.core.app.NotificationCompat import androidx.media.app.NotificationCompat.MediaStyle import org.oxycblt.auxio.MainActivity @@ -17,6 +18,7 @@ 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 +import org.oxycblt.auxio.settings.SettingsManager object NotificationUtils { const val CHANNEL_ID = "CHANNEL_AUXIO_PLAYBACK" @@ -24,6 +26,7 @@ object NotificationUtils { const val REQUEST_CODE = 0xA0C0 const val ACTION_LOOP = "ACTION_AUXIO_LOOP" + const val ACTION_SHUFFLE = "ACTION_AUXIO_SHUFFLE" const val ACTION_SKIP_PREV = "ACTION_AUXIO_SKIP_PREV" const val ACTION_PLAY_PAUSE = "ACTION_AUXIO_PLAY_PAUSE" const val ACTION_SKIP_NEXT = "ACTION_AUXIO_SKIP_NEXT" @@ -96,10 +99,17 @@ fun NotificationCompat.Builder.setMetadata(song: Song, context: Context, onDone: setSubText(song.album.name) } - // getBitmap() is concurrent, so only call back to the object calling this function when - // the loading is over. - getBitmap(song, context) { - setLargeIcon(it) + // Also set the cover art [If reasonable] + if (SettingsManager.getInstance().colorizeNotif) { + // getBitmap() is concurrent, so only call back to the object calling this function when + // the loading is over. + getBitmap(song, context) { + setLargeIcon(it) + + onDone() + } + } else { + setLargeIcon(null) onDone() } @@ -115,12 +125,16 @@ fun NotificationCompat.Builder.updatePlaying(context: Context) { } /** - * Update the loop button on the media notification + * Update the loop/shuffle button on the media notification * @param context The context required to refresh the action */ @SuppressLint("RestrictedApi") -fun NotificationCompat.Builder.updateLoop(context: Context) { - mActions[0] = newAction(NotificationUtils.ACTION_LOOP, context) +fun NotificationCompat.Builder.updateExtraAction(context: Context) { + mActions[0] = if (SettingsManager.getInstance().useAltNotifAction) { + newAction(NotificationUtils.ACTION_SHUFFLE, context) + } else { + newAction(NotificationUtils.ACTION_LOOP, context) + } } /** @@ -151,12 +165,22 @@ private fun newAction(action: String, context: Context): NotificationCompat.Acti val drawable = when (action) { NotificationUtils.ACTION_LOOP -> { when (playbackManager.loopMode) { - LoopMode.NONE -> R.drawable.ic_loop_disabled + LoopMode.NONE -> R.drawable.ic_loop_inactive LoopMode.ONCE -> R.drawable.ic_loop_one LoopMode.INFINITE -> R.drawable.ic_loop } } + NotificationUtils.ACTION_SHUFFLE -> { + Log.d("A function", "Jesus christ does this even call???") + + if (playbackManager.isShuffling) { + R.drawable.ic_shuffle + } else { + R.drawable.ic_shuffle_inactive + } + } + NotificationUtils.ACTION_SKIP_PREV -> R.drawable.ic_skip_prev NotificationUtils.ACTION_PLAY_PAUSE -> { @@ -170,7 +194,6 @@ private fun newAction(action: String, context: Context): NotificationCompat.Acti NotificationUtils.ACTION_SKIP_NEXT -> R.drawable.ic_skip_next NotificationUtils.ACTION_EXIT -> R.drawable.ic_exit - else -> R.drawable.ic_error } diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackService.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackService.kt index 40a63e49d..4ac6d8ca2 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackService.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackService.kt @@ -39,6 +39,7 @@ 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.PlaybackStateManager +import org.oxycblt.auxio.settings.SettingsManager /** * A service that manages the system-side aspects of playback, such as: @@ -52,12 +53,14 @@ import org.oxycblt.auxio.playback.state.PlaybackStateManager * to it to deliver commands. * @author OxygenCobalt */ -class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Callback { +class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Callback, SettingsManager.Callback { private val player: SimpleExoPlayer by lazy { SimpleExoPlayer.Builder(applicationContext).build() } private val playbackManager = PlaybackStateManager.getInstance() + private val settingsManager = SettingsManager.getInstance() + private lateinit var mediaSession: MediaSessionCompat private lateinit var systemReceiver: SystemEventReceiver @@ -121,6 +124,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca systemReceiver = SystemEventReceiver() IntentFilter().apply { addAction(NotificationUtils.ACTION_LOOP) + addAction(NotificationUtils.ACTION_SHUFFLE) addAction(NotificationUtils.ACTION_SKIP_PREV) addAction(NotificationUtils.ACTION_PLAY_PAUSE) addAction(NotificationUtils.ACTION_SKIP_NEXT) @@ -150,6 +154,10 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca restorePlayer() restoreNotification() } + + // --- SETTINGSMANAGER SETUP --- + + settingsManager.addCallback(this) } override fun onDestroy() { @@ -162,6 +170,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca player.release() mediaSession.release() playbackManager.removeCallback(this) + settingsManager.removeCallback(this) serviceScope.launch { playbackManager.saveStateToDatabase(this@PlaybackService) @@ -274,10 +283,18 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca } } - notification.updateLoop(this) + notification.updateExtraAction(this) startForegroundOrNotify("Loop") } + override fun onShuffleUpdate(isShuffling: Boolean) { + if (settingsManager.useAltNotifAction) { + notification.updateExtraAction(this) + + startForegroundOrNotify("Shuffle update") + } + } + override fun onSeekConfirm(position: Long) { changeIsFromAudioFocus = false @@ -290,6 +307,22 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca restorePlayer() } + // --- SETTINGSMANAGER OVERRIDES --- + + override fun onColorizeNotifUpdate(doColorize: Boolean) { + playbackManager.song?.let { + notification.setMetadata(it, this) { + startForegroundOrNotify("Colorize update") + } + } + } + + override fun onNotifActionUpdate(useAltAction: Boolean) { + notification.updateExtraAction(this) + + startForegroundOrNotify("Notif action update") + } + // --- OTHER FUNCTIONS --- private fun restorePlayer() { @@ -311,7 +344,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca } private fun restoreNotification() { - notification.updateLoop(this) + notification.updateExtraAction(this) notification.updateMode(this) notification.updatePlaying(this) @@ -436,6 +469,8 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca when (it) { NotificationUtils.ACTION_LOOP -> playbackManager.setLoopMode(playbackManager.loopMode.increment()) + NotificationUtils.ACTION_SHUFFLE -> + playbackManager.setShuffleStatus(!playbackManager.isShuffling) NotificationUtils.ACTION_SKIP_PREV -> playbackManager.prev() NotificationUtils.ACTION_PLAY_PAUSE -> { playbackManager.setPlayingStatus(!playbackManager.isPlaying) diff --git a/app/src/main/java/org/oxycblt/auxio/settings/SettingUtils.kt b/app/src/main/java/org/oxycblt/auxio/settings/SettingUtils.kt index 6a648b394..5b1e89909 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingUtils.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingUtils.kt @@ -18,6 +18,9 @@ fun String.toThemeInt(): Int { } } +/** + * Convert an theme integer into an icon that can be used. + */ @DrawableRes fun Int.toThemeIcon(): Int { return when (this) { 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 0b02af3b1..8bdad65f6 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/SettingsManager.kt @@ -2,7 +2,6 @@ package org.oxycblt.auxio.settings import android.content.Context import android.content.SharedPreferences -import androidx.appcompat.app.AppCompatDelegate import androidx.preference.PreferenceManager import org.oxycblt.auxio.recycler.SortMode import org.oxycblt.auxio.ui.ACCENTS @@ -19,10 +18,11 @@ class SettingsManager private constructor(context: Context) : sharedPrefs.registerOnSharedPreferenceChangeListener(this) } + // --- VALUES --- + val theme: Int get() { - return sharedPrefs.getString(Keys.KEY_THEME, EntryNames.THEME_AUTO)?.toThemeInt() - ?: AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM + return sharedPrefs.getString(Keys.KEY_THEME, EntryNames.THEME_AUTO)!!.toThemeInt() } var accent: Pair @@ -47,6 +47,16 @@ class SettingsManager private constructor(context: Context) : return sharedPrefs.getBoolean(Keys.KEY_EDGE_TO_EDGE, false) } + val colorizeNotif: Boolean + get() { + return sharedPrefs.getBoolean(Keys.KEY_COLORIZE_NOTIFICATION, true) + } + + val useAltNotifAction: Boolean + get() { + return sharedPrefs.getBoolean(Keys.KEY_USE_ALT_NOTIFICATION_ACTION, false) + } + var librarySortMode: SortMode get() { return SortMode.fromInt( @@ -77,6 +87,15 @@ class SettingsManager private constructor(context: Context) : // --- OVERRIDES --- override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + when (key) { + Keys.KEY_COLORIZE_NOTIFICATION -> callbacks.forEach { + it.onColorizeNotifUpdate(colorizeNotif) + } + + Keys.KEY_USE_ALT_NOTIFICATION_ACTION -> callbacks.forEach { + it.onNotifActionUpdate(useAltNotifAction) + } + } } companion object { @@ -113,6 +132,8 @@ class SettingsManager private constructor(context: Context) : const val KEY_THEME = "KEY_THEME" const val KEY_ACCENT = "KEY_ACCENT" const val KEY_EDGE_TO_EDGE = "KEY_EDGE" + const val KEY_COLORIZE_NOTIFICATION = "KEY_COLOR_NOTIF" + const val KEY_USE_ALT_NOTIFICATION_ACTION = "KEY_ALT_NOTIF_ACTION" } object EntryNames { @@ -121,9 +142,8 @@ class SettingsManager private constructor(context: Context) : const val THEME_DARK = "DARK" } - /** - * An interface for receiving some settings updates. - * [SharedPreferences.OnSharedPreferenceChangeListener]. - */ - interface Callback + interface Callback { + fun onColorizeNotifUpdate(doColorize: Boolean) {} + fun onNotifActionUpdate(useAltAction: Boolean) {} + } } diff --git a/app/src/main/res/drawable/ic_loop_disabled.xml b/app/src/main/res/drawable/ic_loop_inactive.xml similarity index 100% rename from app/src/main/res/drawable/ic_loop_disabled.xml rename to app/src/main/res/drawable/ic_loop_inactive.xml diff --git a/app/src/main/res/drawable/ic_shuffle_inactive.xml b/app/src/main/res/drawable/ic_shuffle_inactive.xml new file mode 100644 index 000000000..00f5aee33 --- /dev/null +++ b/app/src/main/res/drawable/ic_shuffle_inactive.xml @@ -0,0 +1,10 @@ + + + + \ 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 e1fbeb639..e840061e4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -44,8 +44,15 @@ Dark Accent Edge-To-Edge - Disable edge-to-edge - Enable edge-to-edge + Edge-to-edge is enabled + Edge-to-edge is disabled + Display + Colorize notification] + Show album art on notification + Hide album art on notification + Use alternate notification action + Prefer repeat mode action + Prefer shuffle action 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 e29f95673..c220ecf85 100644 --- a/app/src/main/res/xml-v27/prefs_main.xml +++ b/app/src/main/res/xml-v27/prefs_main.xml @@ -25,6 +25,29 @@ app:summaryOn="@string/setting_edge_desc_on" app:summaryOff="@string/setting_edge_desc_off" app:iconSpaceReserved="false" + app:allowDividerBelow="false" android:defaultValue="false" /> + + + + + + + + \ No newline at end of file