Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class AiPlaylistGenerator @Inject constructor(
val genre = song.genre?.replace("\"", "'")?.take(15) ?: "?"
if (index > 0) append(",\n")
if (useExtendedFields) {
val album = song.album?.replace("\"", "'")?.take(25) ?: "?"
val album = song.album.replace("\"", "'").take(25)
val dur = song.duration
val fav = if (song.isFavorite) "1" else "0"
append("""{"id":"${song.id}","t":"$title","a":"$artist","g":"$genre","al":"$album","d":$dur,"f":$fav,"s":$score}""")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ class UserPreferencesRepository @Inject constructor(
val DISABLE_CAST_AUTOPLAY = booleanPreferencesKey("disable_cast_autoplay")
val RESUME_ON_HEADSET_RECONNECT = booleanPreferencesKey("resume_on_headset_reconnect")
val SHOW_QUEUE_HISTORY = booleanPreferencesKey("show_queue_history")
val DISMISS_MINI_PLAYER_ON_SWIPE = booleanPreferencesKey("dismiss_mini_player_on_swipe")
val PLAYBACK_QUEUE_SNAPSHOT = stringPreferencesKey("playback_queue_snapshot_v1")
val FULL_PLAYER_SHOW_FILE_INFO = booleanPreferencesKey("full_player_show_file_info")
val FULL_PLAYER_DELAY_ALBUM = booleanPreferencesKey("full_player_delay_album")
Expand Down Expand Up @@ -377,6 +378,13 @@ class UserPreferencesRepository @Inject constructor(
dataStore.edit { it[PreferencesKeys.SHOW_QUEUE_HISTORY] = show }
}

val dismissMiniPlayerOnSwipeFlow: Flow<Boolean> =
pref { it[PreferencesKeys.DISMISS_MINI_PLAYER_ON_SWIPE] ?: false }

suspend fun setDismissMiniPlayerOnSwipe(enabled: Boolean) {
dataStore.edit { it[PreferencesKeys.DISMISS_MINI_PLAYER_ON_SWIPE] = enabled }
}

val playbackQueueSnapshotFlow: Flow<PlaybackQueueSnapshot?> =
pref { preferences ->
preferences[PreferencesKeys.PLAYBACK_QUEUE_SNAPSHOT]?.let { raw ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1109,11 +1109,23 @@ class MusicService : MediaLibraryService() {
widgetUpdateManager.requestFullUpdate(true)
}
PlayerActions.NEXT -> {
val shouldResumePlayback =
!player.playWhenReady && !player.isPlaying && player.hasNextMediaItem()
player.seekToNext()
if (shouldResumePlayback) player.play()
widgetUpdateManager.requestFullUpdate(true)
}
PlayerActions.PREVIOUS -> {
player.seekToPrevious()
val shouldRestartCurrent = player.currentPosition > 10_000L
val shouldResumePlayback =
!player.playWhenReady && !player.isPlaying &&
!shouldRestartCurrent && player.hasPreviousMediaItem()
if (shouldRestartCurrent) {
player.seekTo(0)
} else {
player.seekToPrevious()
}
if (shouldResumePlayback) player.play()
widgetUpdateManager.requestFullUpdate(true)
}
PlayerActions.FAVORITE -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,28 @@ class WearCommandReceiver : WearableListenerService() {
WearPlaybackCommand.TOGGLE_PLAY_PAUSE -> {
if (controller.isPlaying) controller.pause() else controller.play()
}
WearPlaybackCommand.NEXT -> controller.seekToNext()
WearPlaybackCommand.PREVIOUS -> controller.seekToPrevious()
WearPlaybackCommand.NEXT -> {
val shouldResumePlayback =
!controller.playWhenReady &&
!controller.isPlaying &&
controller.hasNextMediaItem()
controller.seekToNext()
if (shouldResumePlayback) controller.play()
}
WearPlaybackCommand.PREVIOUS -> {
val shouldRestartCurrent = controller.currentPosition > 10_000L
val shouldResumePlayback =
!controller.playWhenReady &&
!controller.isPlaying &&
!shouldRestartCurrent &&
controller.hasPreviousMediaItem()
if (shouldRestartCurrent) {
controller.seekTo(0)
} else {
controller.seekToPrevious()
}
if (shouldResumePlayback) controller.play()
}
WearPlaybackCommand.PLAY_QUEUE_INDEX -> {
val queueIndex = command.queueIndex
if (queueIndex == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ import com.theveloper.pixelplay.presentation.components.subcomps.FetchLyricsDial
import com.theveloper.pixelplay.presentation.components.subcomps.PlayerSeekBar
import com.theveloper.pixelplay.presentation.viewmodel.LyricsSearchUiState
import com.theveloper.pixelplay.presentation.viewmodel.StablePlayerState
import com.theveloper.pixelplay.ui.theme.GoogleSansRounded
import com.theveloper.pixelplay.utils.BubblesLine
import com.theveloper.pixelplay.utils.ProviderText
import com.theveloper.pixelplay.presentation.components.snapping.ExperimentalSnapperApi
Expand Down Expand Up @@ -686,7 +685,7 @@ fun LyricsSheet(
resetImmersiveTimer()
}
) {
val initialSyncedLineIndex = remember(lyrics, playbackPositionFlow, lyricsSyncOffset) {
val initialSyncedLineIndex = remember(currentSong?.id, lyrics, playbackPositionFlow, lyricsSyncOffset) {
resolveCurrentLineIndex(
lines = lyrics?.synced.orEmpty(),
position = (playbackPositionFlow.value + lyricsSyncOffset).coerceAtLeast(0L)
Expand All @@ -696,6 +695,10 @@ fun LyricsSheet(
initialFirstVisibleItemIndex = initialSyncedLineIndex
)
val staticListState = rememberLazyListState()
LaunchedEffect(currentSong?.id, stablePlayerState.currentMediaItemIndex) {
syncedListState.scrollToItem(0)
staticListState.scrollToItem(0)
}

// Lyrics Content (Weight 1)
Box(
Expand Down Expand Up @@ -776,6 +779,7 @@ fun LyricsSheet(
.padding(horizontal = 24.dp),
contentPadding = PaddingValues(top = 130.dp, bottom = 100.dp),
lines = synced,
currentTrackKey = currentSong?.id to stablePlayerState.currentMediaItemIndex,
listState = syncedListState,
playbackPositionFlow = playbackPositionFlow,
lyricsSyncOffset = lyricsSyncOffset,
Expand Down Expand Up @@ -1191,6 +1195,7 @@ private fun LyricsPlaybackSeekBar(
@Composable
fun SyncedLyricsList(
lines: List<SyncedLine>,
currentTrackKey: Pair<String?, Int>,
listState: LazyListState,
playbackPositionFlow: StateFlow<Long>,
lyricsSyncOffset: Int,
Expand Down Expand Up @@ -1225,6 +1230,18 @@ fun SyncedLyricsList(
}
var hasAlignedInitialLine by remember(lines) { mutableStateOf(false) }
var lastAutoScrolledLineIndex by remember(lines) { mutableIntStateOf(-1) }
var activeTrackKey by remember { mutableStateOf(currentTrackKey) }
var skipAutoScrollAfterTrackChange by remember { mutableStateOf(false) }

LaunchedEffect(currentTrackKey) {
if (activeTrackKey != currentTrackKey) {
activeTrackKey = currentTrackKey
hasAlignedInitialLine = true
lastAutoScrolledLineIndex = 0
skipAutoScrollAfterTrackChange = true
listState.scrollToItem(0)
}
}

BoxWithConstraints(modifier = modifier) {
val metrics = remember(maxHeight, highlightZoneFraction, highlightOffsetDp) {
Expand All @@ -1241,10 +1258,14 @@ fun SyncedLyricsList(
)
val flingBehavior = rememberSnapperFlingBehavior(layoutInfo = snapperLayoutInfo)

LaunchedEffect(currentLineIndex, lines.size, metrics, isPreviewSeeking) {
LaunchedEffect(currentTrackKey, currentLineIndex, lines.size, metrics, isPreviewSeeking) {
if (lines.isEmpty()) return@LaunchedEffect
if (currentLineIndex !in lines.indices) return@LaunchedEffect
if (listState.layoutInfo.totalItemsCount == 0) return@LaunchedEffect
if (skipAutoScrollAfterTrackChange) {
skipAutoScrollAfterTrackChange = false
return@LaunchedEffect
}

if (!hasAlignedInitialLine) {
listState.scrollToItem(currentLineIndex)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.derivedStateOf
Expand Down Expand Up @@ -219,44 +220,50 @@ internal fun BoxScope.UnifiedPlayerMiniAndFullLayers(
val onRepeatToggle = remember(playerViewModel) { playerViewModel::cycleRepeatMode }
val onFavoriteToggle = remember(playerViewModel) { playerViewModel::toggleFavorite }

FullPlayerContent(
currentSong = currentSongNonNull,
currentPlaybackQueue = currentPlaybackQueue,
currentQueueSourceName = currentQueueSourceName,
currentMediaItemIndex = infrequentPlayerState.currentMediaItemIndex,
isShuffleEnabled = infrequentPlayerState.isShuffleEnabled,
shuffleTransitionInProgress = infrequentPlayerState.isShuffleTransitionInProgress,
repeatMode = infrequentPlayerState.repeatMode,
allowRealtimeUpdates = fullPlayerRuntimePolicy.allowRealtimeUpdates,
expansionFractionProvider = expansionFractionProvider,
currentSheetState = currentSheetContentState,
carouselStyle = carouselStyle,
loadingTweaks = fullPlayerLoadingTweaks,
isSheetDragGestureActive = isSheetDragGestureActive,
playerViewModel = playerViewModel,
currentPositionProvider = currentPositionProvider,
isPlayingProvider = isPlayingProvider,
playWhenReadyProvider = playWhenReadyProvider,
repeatModeProvider = repeatModeProvider,
isShuffleEnabledProvider = isShuffleEnabledProvider,
totalDurationProvider = totalDurationProvider,
lyricsProvider = lyricsProvider,
isCastConnecting = isCastConnecting,
isFavoriteProvider = isFavoriteProvider,
onPlayPause = onPlayPause,
onSeek = onSeek,
onNext = onNext,
onPrevious = onPrevious,
onCollapse = onCollapse,
onShowQueueClicked = onShowQueueClicked,
onQueueDragStart = onQueueDragStart,
onQueueDrag = onQueueDrag,
onQueueRelease = onQueueRelease,
onShowCastClicked = onShowCastClicked,
onShuffleToggle = onShuffleToggle,
onRepeatToggle = onRepeatToggle,
onFavoriteToggle = onFavoriteToggle
)
MaterialTheme(
colorScheme = MaterialTheme.colorScheme,
typography = MaterialTheme.typography,
shapes = MaterialTheme.shapes
) {
FullPlayerContent(
currentSong = currentSongNonNull,
currentPlaybackQueue = currentPlaybackQueue,
currentQueueSourceName = currentQueueSourceName,
currentMediaItemIndex = infrequentPlayerState.currentMediaItemIndex,
isShuffleEnabled = infrequentPlayerState.isShuffleEnabled,
shuffleTransitionInProgress = infrequentPlayerState.isShuffleTransitionInProgress,
repeatMode = infrequentPlayerState.repeatMode,
allowRealtimeUpdates = fullPlayerRuntimePolicy.allowRealtimeUpdates,
expansionFractionProvider = expansionFractionProvider,
currentSheetState = currentSheetContentState,
carouselStyle = carouselStyle,
loadingTweaks = fullPlayerLoadingTweaks,
isSheetDragGestureActive = isSheetDragGestureActive,
playerViewModel = playerViewModel,
currentPositionProvider = currentPositionProvider,
isPlayingProvider = isPlayingProvider,
playWhenReadyProvider = playWhenReadyProvider,
repeatModeProvider = repeatModeProvider,
isShuffleEnabledProvider = isShuffleEnabledProvider,
totalDurationProvider = totalDurationProvider,
lyricsProvider = lyricsProvider,
isCastConnecting = isCastConnecting,
isFavoriteProvider = isFavoriteProvider,
onPlayPause = onPlayPause,
onSeek = onSeek,
onNext = onNext,
onPrevious = onPrevious,
onCollapse = onCollapse,
onShowQueueClicked = onShowQueueClicked,
onQueueDragStart = onQueueDragStart,
onQueueDrag = onQueueDrag,
onQueueRelease = onQueueRelease,
onShowCastClicked = onShowCastClicked,
onShuffleToggle = onShuffleToggle,
onRepeatToggle = onRepeatToggle,
onFavoriteToggle = onFavoriteToggle
)
}
}
}
}
Expand Down Expand Up @@ -317,43 +324,49 @@ internal fun UnifiedPlayerPrewarmLayer(
val onRepeatToggle = remember(playerViewModel) { playerViewModel::cycleRepeatMode }
val onFavoriteToggle = remember(playerViewModel) { playerViewModel::toggleFavorite }

FullPlayerContent(
currentSong = currentSong,
currentPlaybackQueue = currentPlaybackQueue,
currentQueueSourceName = currentQueueSourceName,
currentMediaItemIndex = infrequentPlayerState.currentMediaItemIndex,
isShuffleEnabled = infrequentPlayerState.isShuffleEnabled,
shuffleTransitionInProgress = infrequentPlayerState.isShuffleTransitionInProgress,
repeatMode = infrequentPlayerState.repeatMode,
allowRealtimeUpdates = false,
expansionFractionProvider = { 1f },
currentSheetState = PlayerSheetState.EXPANDED,
carouselStyle = carouselStyle,
loadingTweaks = fullPlayerLoadingTweaks,
playerViewModel = playerViewModel,
currentPositionProvider = currentPositionProvider,
isPlayingProvider = isPlayingProvider,
playWhenReadyProvider = playWhenReadyProvider,
repeatModeProvider = repeatModeProvider,
isShuffleEnabledProvider = isShuffleEnabledProvider,
totalDurationProvider = totalDurationProvider,
lyricsProvider = lyricsProvider,
isCastConnecting = isCastConnecting,
isFavoriteProvider = isFavoriteProvider,
onShowQueueClicked = onShowQueueClicked,
onQueueDragStart = onQueueDragStart,
onQueueDrag = onQueueDrag,
onQueueRelease = onQueueRelease,
onPlayPause = onPlayPause,
onSeek = onSeek,
onNext = onNext,
onPrevious = onPrevious,
onCollapse = {},
onShowCastClicked = {},
onShuffleToggle = onShuffleToggle,
onRepeatToggle = onRepeatToggle,
onFavoriteToggle = onFavoriteToggle
)
MaterialTheme(
colorScheme = MaterialTheme.colorScheme,
typography = MaterialTheme.typography,
shapes = MaterialTheme.shapes
) {
FullPlayerContent(
currentSong = currentSong,
currentPlaybackQueue = currentPlaybackQueue,
currentQueueSourceName = currentQueueSourceName,
currentMediaItemIndex = infrequentPlayerState.currentMediaItemIndex,
isShuffleEnabled = infrequentPlayerState.isShuffleEnabled,
shuffleTransitionInProgress = infrequentPlayerState.isShuffleTransitionInProgress,
repeatMode = infrequentPlayerState.repeatMode,
allowRealtimeUpdates = false,
expansionFractionProvider = { 1f },
currentSheetState = PlayerSheetState.EXPANDED,
carouselStyle = carouselStyle,
loadingTweaks = fullPlayerLoadingTweaks,
playerViewModel = playerViewModel,
currentPositionProvider = currentPositionProvider,
isPlayingProvider = isPlayingProvider,
playWhenReadyProvider = playWhenReadyProvider,
repeatModeProvider = repeatModeProvider,
isShuffleEnabledProvider = isShuffleEnabledProvider,
totalDurationProvider = totalDurationProvider,
lyricsProvider = lyricsProvider,
isCastConnecting = isCastConnecting,
isFavoriteProvider = isFavoriteProvider,
onShowQueueClicked = onShowQueueClicked,
onQueueDragStart = onQueueDragStart,
onQueueDrag = onQueueDrag,
onQueueRelease = onQueueRelease,
onPlayPause = onPlayPause,
onSeek = onSeek,
onNext = onNext,
onPrevious = onPrevious,
onCollapse = {},
onShowCastClicked = {},
onShuffleToggle = onShuffleToggle,
onRepeatToggle = onRepeatToggle,
onFavoriteToggle = onFavoriteToggle
)
}
}
}
}
Expand Down
Loading