diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt index 3153f98..ce219db 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/service/PlayerService.kt @@ -27,7 +27,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat.startForegroundService -import androidx.core.content.edit import androidx.core.content.getSystemService import androidx.core.net.toUri import androidx.core.text.isDigitsOnly @@ -63,6 +62,10 @@ import androidx.media3.exoplayer.source.MediaSource import androidx.media3.extractor.ExtractorsFactory import androidx.media3.extractor.mkv.MatroskaExtractor 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.MainActivity 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.persistentQueueKey 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.skipSilenceKey import it.vfsfitvnm.vimusic.utils.timer +import it.vfsfitvnm.vimusic.utils.trackLoopEnabledKey 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.system.exitProcess import kotlinx.coroutines.CoroutineScope @@ -219,10 +219,12 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene .setUsePlatformDiagnostics(false) .build() - player.repeatMode = when (preferences.getInt(repeatModeKey, Player.REPEAT_MODE_ALL)) { - Player.REPEAT_MODE_ONE -> Player.REPEAT_MODE_ONE - else -> Player.REPEAT_MODE_ALL + player.repeatMode = when { + preferences.getBoolean(trackLoopEnabledKey, false) -> Player.REPEAT_MODE_ONE + preferences.getBoolean(queueLoopEnabledKey, true) -> Player.REPEAT_MODE_ALL + else -> Player.REPEAT_MODE_OFF } + player.skipSilenceEnabled = preferences.getBoolean(skipSilenceKey, false) player.addListener(this) player.addAnalyticsListener(PlaybackStatsListener(false, this)) @@ -456,10 +458,6 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene else -> PlaybackState.STATE_NONE } - override fun onRepeatModeChanged(repeatMode: Int) { - preferences.edit { putInt(repeatModeKey, repeatMode) } - } - override fun onEvents(player: Player, events: Player.Events) { if (player.duration != C.TIME_UNSET) { metadataBuilder @@ -540,6 +538,13 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene isShowingThumbnailInLockscreen = sharedPreferences.getBoolean(key, true) 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 + } + } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Controls.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Controls.kt index f97d3ba..c89167f 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Controls.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Controls.kt @@ -44,13 +44,14 @@ import it.vfsfitvnm.vimusic.ui.components.SeekBar import it.vfsfitvnm.vimusic.ui.components.themed.IconButton import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance import it.vfsfitvnm.vimusic.ui.styling.favoritesIcon -import it.vfsfitvnm.vimusic.utils.DisposableListener import it.vfsfitvnm.vimusic.utils.bold import it.vfsfitvnm.vimusic.utils.forceSeekToNext import it.vfsfitvnm.vimusic.utils.forceSeekToPrevious import it.vfsfitvnm.vimusic.utils.formatAsDuration +import it.vfsfitvnm.vimusic.utils.rememberPreference import it.vfsfitvnm.vimusic.utils.secondary import it.vfsfitvnm.vimusic.utils.semiBold +import it.vfsfitvnm.vimusic.utils.trackLoopEnabledKey import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn @@ -70,17 +71,7 @@ fun Controls( val binder = LocalPlayerServiceBinder.current binder?.player ?: return - var repeatMode by remember { - mutableStateOf(binder.player.repeatMode) - } - - binder.player.DisposableListener { - object : Player.Listener { - override fun onRepeatModeChanged(newRepeatMode: Int) { - repeatMode = newRepeatMode - } - } - } + var trackLoopEnabled by rememberPreference(trackLoopEnabledKey, defaultValue = false) var scrubbingPosition by remember(mediaId) { mutableStateOf(null) @@ -277,17 +268,8 @@ fun Controls( IconButton( icon = R.drawable.infinite, - color = if (repeatMode == Player.REPEAT_MODE_ONE) { - colorPalette.text - } else { - colorPalette.textDisabled - }, - onClick = { - binder.player.repeatMode = when (binder.player.repeatMode) { - Player.REPEAT_MODE_ONE -> Player.REPEAT_MODE_ALL - else -> Player.REPEAT_MODE_ONE - } - }, + color = if (trackLoopEnabled) colorPalette.text else colorPalette.textDisabled, + onClick = { trackLoopEnabled = !trackLoopEnabled }, modifier = Modifier .weight(1f) .size(24.dp) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Queue.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Queue.kt index 3cf814a..b7a77f6 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Queue.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/player/Queue.kt @@ -1,7 +1,11 @@ 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.ContentTransform import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.tween import androidx.compose.animation.core.updateTransition 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.BoxScope import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.asPaddingValues @@ -37,6 +42,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.Color 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.utils.DisposableListener 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.shuffleQueue import it.vfsfitvnm.vimusic.utils.smoothScrollToTop @@ -120,6 +128,8 @@ fun Queue( val player = binder.player + var queueLoopEnabled by rememberPreference(queueLoopEnabledKey, defaultValue = true) + val menuState = LocalMenuState.current val thumbnailSizeDp = Dimensions.thumbnails.song @@ -340,6 +350,38 @@ fun Queue( .align(Alignment.Center) .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, + ) + } + } } } } diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Preferences.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Preferences.kt index 163cca7..774138a 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Preferences.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Preferences.kt @@ -25,7 +25,8 @@ const val albumSortOrderKey = "albumSortOrder" const val albumSortByKey = "albumSortBy" const val artistSortOrderKey = "artistSortOrder" const val artistSortByKey = "artistSortBy" -const val repeatModeKey = "repeatMode" +const val trackLoopEnabledKey = "trackLoopEnabled" +const val queueLoopEnabledKey = "queueLoopEnabled" const val skipSilenceKey = "skipSilence" const val volumeNormalizationKey = "volumeNormalization" const val persistentQueueKey = "persistentQueue"