Reintroduce "loop none" option (#276)
This commit is contained in:
parent
720c73d9fb
commit
fc569ea5f9
4 changed files with 67 additions and 37 deletions
|
@ -27,7 +27,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat.startForegroundService
|
import androidx.core.content.ContextCompat.startForegroundService
|
||||||
import androidx.core.content.edit
|
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.text.isDigitsOnly
|
import androidx.core.text.isDigitsOnly
|
||||||
|
@ -63,6 +62,10 @@ import androidx.media3.exoplayer.source.MediaSource
|
||||||
import androidx.media3.extractor.ExtractorsFactory
|
import androidx.media3.extractor.ExtractorsFactory
|
||||||
import androidx.media3.extractor.mkv.MatroskaExtractor
|
import androidx.media3.extractor.mkv.MatroskaExtractor
|
||||||
import androidx.media3.extractor.mp4.FragmentedMp4Extractor
|
import androidx.media3.extractor.mp4.FragmentedMp4Extractor
|
||||||
|
import it.vfsfitvnm.innertube.Innertube
|
||||||
|
import it.vfsfitvnm.innertube.models.NavigationEndpoint
|
||||||
|
import it.vfsfitvnm.innertube.models.bodies.PlayerBody
|
||||||
|
import it.vfsfitvnm.innertube.requests.player
|
||||||
import it.vfsfitvnm.vimusic.Database
|
import it.vfsfitvnm.vimusic.Database
|
||||||
import it.vfsfitvnm.vimusic.MainActivity
|
import it.vfsfitvnm.vimusic.MainActivity
|
||||||
import it.vfsfitvnm.vimusic.R
|
import it.vfsfitvnm.vimusic.R
|
||||||
|
@ -88,15 +91,12 @@ import it.vfsfitvnm.vimusic.utils.isShowingThumbnailInLockscreenKey
|
||||||
import it.vfsfitvnm.vimusic.utils.mediaItems
|
import it.vfsfitvnm.vimusic.utils.mediaItems
|
||||||
import it.vfsfitvnm.vimusic.utils.persistentQueueKey
|
import it.vfsfitvnm.vimusic.utils.persistentQueueKey
|
||||||
import it.vfsfitvnm.vimusic.utils.preferences
|
import it.vfsfitvnm.vimusic.utils.preferences
|
||||||
import it.vfsfitvnm.vimusic.utils.repeatModeKey
|
import it.vfsfitvnm.vimusic.utils.queueLoopEnabledKey
|
||||||
import it.vfsfitvnm.vimusic.utils.shouldBePlaying
|
import it.vfsfitvnm.vimusic.utils.shouldBePlaying
|
||||||
import it.vfsfitvnm.vimusic.utils.skipSilenceKey
|
import it.vfsfitvnm.vimusic.utils.skipSilenceKey
|
||||||
import it.vfsfitvnm.vimusic.utils.timer
|
import it.vfsfitvnm.vimusic.utils.timer
|
||||||
|
import it.vfsfitvnm.vimusic.utils.trackLoopEnabledKey
|
||||||
import it.vfsfitvnm.vimusic.utils.volumeNormalizationKey
|
import it.vfsfitvnm.vimusic.utils.volumeNormalizationKey
|
||||||
import it.vfsfitvnm.innertube.Innertube
|
|
||||||
import it.vfsfitvnm.innertube.models.NavigationEndpoint
|
|
||||||
import it.vfsfitvnm.innertube.models.bodies.PlayerBody
|
|
||||||
import it.vfsfitvnm.innertube.requests.player
|
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
@ -219,10 +219,12 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
||||||
.setUsePlatformDiagnostics(false)
|
.setUsePlatformDiagnostics(false)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
player.repeatMode = when (preferences.getInt(repeatModeKey, Player.REPEAT_MODE_ALL)) {
|
player.repeatMode = when {
|
||||||
Player.REPEAT_MODE_ONE -> Player.REPEAT_MODE_ONE
|
preferences.getBoolean(trackLoopEnabledKey, false) -> Player.REPEAT_MODE_ONE
|
||||||
else -> Player.REPEAT_MODE_ALL
|
preferences.getBoolean(queueLoopEnabledKey, true) -> Player.REPEAT_MODE_ALL
|
||||||
|
else -> Player.REPEAT_MODE_OFF
|
||||||
}
|
}
|
||||||
|
|
||||||
player.skipSilenceEnabled = preferences.getBoolean(skipSilenceKey, false)
|
player.skipSilenceEnabled = preferences.getBoolean(skipSilenceKey, false)
|
||||||
player.addListener(this)
|
player.addListener(this)
|
||||||
player.addAnalyticsListener(PlaybackStatsListener(false, this))
|
player.addAnalyticsListener(PlaybackStatsListener(false, this))
|
||||||
|
@ -456,10 +458,6 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
||||||
else -> PlaybackState.STATE_NONE
|
else -> PlaybackState.STATE_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRepeatModeChanged(repeatMode: Int) {
|
|
||||||
preferences.edit { putInt(repeatModeKey, repeatMode) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEvents(player: Player, events: Player.Events) {
|
override fun onEvents(player: Player, events: Player.Events) {
|
||||||
if (player.duration != C.TIME_UNSET) {
|
if (player.duration != C.TIME_UNSET) {
|
||||||
metadataBuilder
|
metadataBuilder
|
||||||
|
@ -540,6 +538,13 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
||||||
isShowingThumbnailInLockscreen = sharedPreferences.getBoolean(key, true)
|
isShowingThumbnailInLockscreen = sharedPreferences.getBoolean(key, true)
|
||||||
maybeShowSongCoverInLockScreen()
|
maybeShowSongCoverInLockScreen()
|
||||||
}
|
}
|
||||||
|
trackLoopEnabledKey, queueLoopEnabledKey -> {
|
||||||
|
player.repeatMode = when {
|
||||||
|
preferences.getBoolean(trackLoopEnabledKey, false) -> Player.REPEAT_MODE_ONE
|
||||||
|
preferences.getBoolean(queueLoopEnabledKey, true) -> Player.REPEAT_MODE_ALL
|
||||||
|
else -> Player.REPEAT_MODE_OFF
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,13 +44,14 @@ import it.vfsfitvnm.vimusic.ui.components.SeekBar
|
||||||
import it.vfsfitvnm.vimusic.ui.components.themed.IconButton
|
import it.vfsfitvnm.vimusic.ui.components.themed.IconButton
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.favoritesIcon
|
import it.vfsfitvnm.vimusic.ui.styling.favoritesIcon
|
||||||
import it.vfsfitvnm.vimusic.utils.DisposableListener
|
|
||||||
import it.vfsfitvnm.vimusic.utils.bold
|
import it.vfsfitvnm.vimusic.utils.bold
|
||||||
import it.vfsfitvnm.vimusic.utils.forceSeekToNext
|
import it.vfsfitvnm.vimusic.utils.forceSeekToNext
|
||||||
import it.vfsfitvnm.vimusic.utils.forceSeekToPrevious
|
import it.vfsfitvnm.vimusic.utils.forceSeekToPrevious
|
||||||
import it.vfsfitvnm.vimusic.utils.formatAsDuration
|
import it.vfsfitvnm.vimusic.utils.formatAsDuration
|
||||||
|
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||||
import it.vfsfitvnm.vimusic.utils.secondary
|
import it.vfsfitvnm.vimusic.utils.secondary
|
||||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||||
|
import it.vfsfitvnm.vimusic.utils.trackLoopEnabledKey
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
|
@ -70,17 +71,7 @@ fun Controls(
|
||||||
val binder = LocalPlayerServiceBinder.current
|
val binder = LocalPlayerServiceBinder.current
|
||||||
binder?.player ?: return
|
binder?.player ?: return
|
||||||
|
|
||||||
var repeatMode by remember {
|
var trackLoopEnabled by rememberPreference(trackLoopEnabledKey, defaultValue = false)
|
||||||
mutableStateOf(binder.player.repeatMode)
|
|
||||||
}
|
|
||||||
|
|
||||||
binder.player.DisposableListener {
|
|
||||||
object : Player.Listener {
|
|
||||||
override fun onRepeatModeChanged(newRepeatMode: Int) {
|
|
||||||
repeatMode = newRepeatMode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var scrubbingPosition by remember(mediaId) {
|
var scrubbingPosition by remember(mediaId) {
|
||||||
mutableStateOf<Long?>(null)
|
mutableStateOf<Long?>(null)
|
||||||
|
@ -277,17 +268,8 @@ fun Controls(
|
||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
icon = R.drawable.infinite,
|
icon = R.drawable.infinite,
|
||||||
color = if (repeatMode == Player.REPEAT_MODE_ONE) {
|
color = if (trackLoopEnabled) colorPalette.text else colorPalette.textDisabled,
|
||||||
colorPalette.text
|
onClick = { trackLoopEnabled = !trackLoopEnabled },
|
||||||
} else {
|
|
||||||
colorPalette.textDisabled
|
|
||||||
},
|
|
||||||
onClick = {
|
|
||||||
binder.player.repeatMode = when (binder.player.repeatMode) {
|
|
||||||
Player.REPEAT_MODE_ONE -> Player.REPEAT_MODE_ALL
|
|
||||||
else -> Player.REPEAT_MODE_ONE
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.size(24.dp)
|
.size(24.dp)
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package it.vfsfitvnm.vimusic.ui.screens.player
|
package it.vfsfitvnm.vimusic.ui.screens.player
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
import androidx.compose.animation.AnimatedContentScope
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.ContentTransform
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.animation.core.updateTransition
|
import androidx.compose.animation.core.updateTransition
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
|
@ -14,6 +18,7 @@ import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.BoxScope
|
import androidx.compose.foundation.layout.BoxScope
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||||
import androidx.compose.foundation.layout.asPaddingValues
|
import androidx.compose.foundation.layout.asPaddingValues
|
||||||
|
@ -37,6 +42,7 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.drawBehind
|
import androidx.compose.ui.draw.drawBehind
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
@ -69,6 +75,8 @@ import it.vfsfitvnm.vimusic.ui.styling.onOverlay
|
||||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||||
import it.vfsfitvnm.vimusic.utils.DisposableListener
|
import it.vfsfitvnm.vimusic.utils.DisposableListener
|
||||||
import it.vfsfitvnm.vimusic.utils.medium
|
import it.vfsfitvnm.vimusic.utils.medium
|
||||||
|
import it.vfsfitvnm.vimusic.utils.queueLoopEnabledKey
|
||||||
|
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||||
import it.vfsfitvnm.vimusic.utils.shouldBePlaying
|
import it.vfsfitvnm.vimusic.utils.shouldBePlaying
|
||||||
import it.vfsfitvnm.vimusic.utils.shuffleQueue
|
import it.vfsfitvnm.vimusic.utils.shuffleQueue
|
||||||
import it.vfsfitvnm.vimusic.utils.smoothScrollToTop
|
import it.vfsfitvnm.vimusic.utils.smoothScrollToTop
|
||||||
|
@ -120,6 +128,8 @@ fun Queue(
|
||||||
|
|
||||||
val player = binder.player
|
val player = binder.player
|
||||||
|
|
||||||
|
var queueLoopEnabled by rememberPreference(queueLoopEnabledKey, defaultValue = true)
|
||||||
|
|
||||||
val menuState = LocalMenuState.current
|
val menuState = LocalMenuState.current
|
||||||
|
|
||||||
val thumbnailSizeDp = Dimensions.thumbnails.song
|
val thumbnailSizeDp = Dimensions.thumbnails.song
|
||||||
|
@ -340,6 +350,38 @@ fun Queue(
|
||||||
.align(Alignment.Center)
|
.align(Alignment.Center)
|
||||||
.size(18.dp)
|
.size(18.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(RoundedCornerShape(16.dp))
|
||||||
|
.clickable { queueLoopEnabled = !queueLoopEnabled }
|
||||||
|
.background(colorPalette.background1)
|
||||||
|
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||||
|
.align(Alignment.CenterEnd)
|
||||||
|
.animateContentSize()
|
||||||
|
) {
|
||||||
|
BasicText(
|
||||||
|
text = "Queue loop ",
|
||||||
|
style = typography.xxs.medium,
|
||||||
|
)
|
||||||
|
|
||||||
|
AnimatedContent(
|
||||||
|
targetState = queueLoopEnabled,
|
||||||
|
transitionSpec = {
|
||||||
|
val slideDirection = if (targetState) AnimatedContentScope.SlideDirection.Up else AnimatedContentScope.SlideDirection.Down
|
||||||
|
|
||||||
|
ContentTransform(
|
||||||
|
targetContentEnter = slideIntoContainer(slideDirection) + fadeIn(),
|
||||||
|
initialContentExit = slideOutOfContainer(slideDirection) + fadeOut(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
BasicText(
|
||||||
|
text = if (it) "on" else "off",
|
||||||
|
style = typography.xxs.medium,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,8 @@ const val albumSortOrderKey = "albumSortOrder"
|
||||||
const val albumSortByKey = "albumSortBy"
|
const val albumSortByKey = "albumSortBy"
|
||||||
const val artistSortOrderKey = "artistSortOrder"
|
const val artistSortOrderKey = "artistSortOrder"
|
||||||
const val artistSortByKey = "artistSortBy"
|
const val artistSortByKey = "artistSortBy"
|
||||||
const val repeatModeKey = "repeatMode"
|
const val trackLoopEnabledKey = "trackLoopEnabled"
|
||||||
|
const val queueLoopEnabledKey = "queueLoopEnabled"
|
||||||
const val skipSilenceKey = "skipSilence"
|
const val skipSilenceKey = "skipSilence"
|
||||||
const val volumeNormalizationKey = "volumeNormalization"
|
const val volumeNormalizationKey = "volumeNormalization"
|
||||||
const val persistentQueueKey = "persistentQueue"
|
const val persistentQueueKey = "persistentQueue"
|
||||||
|
|
Loading…
Reference in a new issue