Add equalizer shortcut
This commit is contained in:
@@ -58,6 +58,8 @@ val DeleteSongCacheCommand = SessionCommand("DeleteSongCacheCommand", Bundle.EMP
|
|||||||
|
|
||||||
val SetSkipSilenceCommand = SessionCommand("SetSkipSilenceCommand", Bundle.EMPTY)
|
val SetSkipSilenceCommand = SessionCommand("SetSkipSilenceCommand", Bundle.EMPTY)
|
||||||
|
|
||||||
|
val GetAudioSessionIdCommand = SessionCommand("GetAudioSessionIdCommand", Bundle.EMPTY)
|
||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@ExperimentalFoundationApi
|
@ExperimentalFoundationApi
|
||||||
class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
|
class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
|
||||||
@@ -107,6 +109,8 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
|
|||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
player.repeatMode = preferences.repeatMode
|
player.repeatMode = preferences.repeatMode
|
||||||
player.skipSilenceEnabled = preferences.skipSilence
|
player.skipSilenceEnabled = preferences.skipSilence
|
||||||
player.playWhenReady = true
|
player.playWhenReady = true
|
||||||
@@ -189,6 +193,7 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
|
|||||||
.add(GetCacheSizeCommand)
|
.add(GetCacheSizeCommand)
|
||||||
.add(DeleteSongCacheCommand)
|
.add(DeleteSongCacheCommand)
|
||||||
.add(SetSkipSilenceCommand)
|
.add(SetSkipSilenceCommand)
|
||||||
|
.add(GetAudioSessionIdCommand)
|
||||||
.build()
|
.build()
|
||||||
val playerCommands = Player.Commands.Builder().addAllCommands().build()
|
val playerCommands = Player.Commands.Builder().addAllCommands().build()
|
||||||
return MediaSession.ConnectionResult.accept(sessionCommands, playerCommands)
|
return MediaSession.ConnectionResult.accept(sessionCommands, playerCommands)
|
||||||
@@ -230,6 +235,9 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
|
|||||||
SetSkipSilenceCommand -> {
|
SetSkipSilenceCommand -> {
|
||||||
player.skipSilenceEnabled = args.getBoolean("skipSilence")
|
player.skipSilenceEnabled = args.getBoolean("skipSilence")
|
||||||
}
|
}
|
||||||
|
GetAudioSessionIdCommand -> {
|
||||||
|
return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS, bundleOf("audioSessionId" to player.audioSessionId)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onCustomCommand(session, controller, customCommand, args)
|
return super.onCustomCommand(session, controller, customCommand, args)
|
||||||
|
|||||||
@@ -188,8 +188,8 @@ fun SettingsScreen() {
|
|||||||
Entry(
|
Entry(
|
||||||
color = colorPalette.magenta,
|
color = colorPalette.magenta,
|
||||||
icon = R.drawable.play,
|
icon = R.drawable.play,
|
||||||
title = "Player",
|
title = "Player & Audio",
|
||||||
description = "Tune the player behavior",
|
description = "Player and audio settings",
|
||||||
route = playerSettingsRoute,
|
route = playerSettingsRoute,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -311,23 +311,38 @@ fun SwitchSettingEntry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@NonRestartableComposable
|
|
||||||
fun SettingsEntry(
|
fun SettingsEntry(
|
||||||
title: String,
|
title: String,
|
||||||
text: String,
|
text: String,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit,
|
||||||
|
isEnabled: Boolean = true
|
||||||
) {
|
) {
|
||||||
BaseSettingsEntry(
|
val typography = LocalTypography.current
|
||||||
title = title,
|
val colorPalette = LocalColorPalette.current
|
||||||
text = text,
|
|
||||||
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.clickable(
|
.clickable(
|
||||||
indication = rememberRipple(bounded = true),
|
indication = rememberRipple(bounded = true),
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
onClick = onClick
|
onClick = onClick,
|
||||||
|
enabled = isEnabled
|
||||||
)
|
)
|
||||||
)
|
.padding(start = 24.dp)
|
||||||
|
.padding(horizontal = 32.dp, vertical = 16.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
BasicText(
|
||||||
|
text = title,
|
||||||
|
style = typography.xs.semiBold.copy(color = if (isEnabled) colorPalette.text else colorPalette.darkGray),
|
||||||
|
)
|
||||||
|
|
||||||
|
BasicText(
|
||||||
|
text = text,
|
||||||
|
style = typography.xs.semiBold.copy(color = if (isEnabled) colorPalette.textSecondary else colorPalette.darkGray),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@@ -1,17 +1,27 @@
|
|||||||
package it.vfsfitvnm.vimusic.ui.screens.settings
|
package it.vfsfitvnm.vimusic.ui.screens.settings
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.media.audiofx.AudioEffect
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.text.BasicText
|
import androidx.compose.foundation.text.BasicText
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.produceState
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
|
import androidx.media3.common.C
|
||||||
import it.vfsfitvnm.route.RouteHandler
|
import it.vfsfitvnm.route.RouteHandler
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
|
import it.vfsfitvnm.vimusic.services.GetAudioSessionIdCommand
|
||||||
import it.vfsfitvnm.vimusic.services.SetSkipSilenceCommand
|
import it.vfsfitvnm.vimusic.services.SetSkipSilenceCommand
|
||||||
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
import it.vfsfitvnm.vimusic.ui.components.TopAppBar
|
||||||
import it.vfsfitvnm.vimusic.ui.screens.*
|
import it.vfsfitvnm.vimusic.ui.screens.*
|
||||||
@@ -20,6 +30,8 @@ import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
|
|||||||
import it.vfsfitvnm.vimusic.utils.LocalPreferences
|
import it.vfsfitvnm.vimusic.utils.LocalPreferences
|
||||||
import it.vfsfitvnm.vimusic.utils.LocalYoutubePlayer
|
import it.vfsfitvnm.vimusic.utils.LocalYoutubePlayer
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
|
import kotlinx.coroutines.guava.await
|
||||||
|
|
||||||
|
|
||||||
@ExperimentalAnimationApi
|
@ExperimentalAnimationApi
|
||||||
@Composable
|
@Composable
|
||||||
@@ -43,11 +55,32 @@ fun PlayerSettingsScreen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
host {
|
host {
|
||||||
|
val context = LocalContext.current
|
||||||
val colorPalette = LocalColorPalette.current
|
val colorPalette = LocalColorPalette.current
|
||||||
val typography = LocalTypography.current
|
val typography = LocalTypography.current
|
||||||
val preferences = LocalPreferences.current
|
val preferences = LocalPreferences.current
|
||||||
val mediaController = LocalYoutubePlayer.current?.mediaController
|
val mediaController = LocalYoutubePlayer.current?.mediaController
|
||||||
|
|
||||||
|
val activityResultLauncher =
|
||||||
|
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
val audioSessionId by produceState(initialValue = C.AUDIO_SESSION_ID_UNSET) {
|
||||||
|
val hasEqualizer = context.packageManager.resolveActivity(
|
||||||
|
Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL),
|
||||||
|
0
|
||||||
|
) != null
|
||||||
|
|
||||||
|
println("hasEqualizer? $hasEqualizer")
|
||||||
|
|
||||||
|
if (hasEqualizer) {
|
||||||
|
value =
|
||||||
|
mediaController?.sendCustomCommand(GetAudioSessionIdCommand, Bundle.EMPTY)
|
||||||
|
?.await()?.extras?.getInt("audioSessionId", C.AUDIO_SESSION_ID_UNSET)
|
||||||
|
?: C.AUDIO_SESSION_ID_UNSET
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(colorPalette.background)
|
.background(colorPalette.background)
|
||||||
@@ -70,7 +103,7 @@ fun PlayerSettingsScreen() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
BasicText(
|
BasicText(
|
||||||
text = "Player",
|
text = "Player & Audio",
|
||||||
style = typography.m.semiBold
|
style = typography.m.semiBold
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -96,10 +129,27 @@ fun PlayerSettingsScreen() {
|
|||||||
text = "Skip silent parts during playback",
|
text = "Skip silent parts during playback",
|
||||||
isChecked = preferences.skipSilence,
|
isChecked = preferences.skipSilence,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
mediaController?.sendCustomCommand(SetSkipSilenceCommand, bundleOf("skipSilence" to it))
|
mediaController?.sendCustomCommand(
|
||||||
|
SetSkipSilenceCommand,
|
||||||
|
bundleOf("skipSilence" to it)
|
||||||
|
)
|
||||||
preferences.skipSilence = it
|
preferences.skipSilence = it
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SettingsEntry(
|
||||||
|
title = "Equalizer",
|
||||||
|
text = "Interact with the system equalizer",
|
||||||
|
onClick = {
|
||||||
|
activityResultLauncher.launch(
|
||||||
|
Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL).apply {
|
||||||
|
putExtra(AudioEffect.EXTRA_AUDIO_SESSION, audioSessionId)
|
||||||
|
putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
isEnabled = audioSessionId != C.AUDIO_SESSION_ID_UNSET && audioSessionId != AudioEffect.ERROR_BAD_VALUE
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user