Reintroduce "loop none" option (#276)

This commit is contained in:
vfsfitvnm 2022-10-19 14:22:34 +02:00
parent 720c73d9fb
commit fc569ea5f9
4 changed files with 67 additions and 37 deletions

View file

@ -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
}
}
} }
} }

View file

@ -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)

View file

@ -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,
)
}
}
} }
} }
} }

View file

@ -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"