From 08143eb5844002516bbbfb73b42ca1e3d925110d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=80lex=20Magaz=20Gra=C3=A7a?= Date: Fri, 1 May 2026 11:47:43 +0200 Subject: [PATCH 1/3] Extract code rendering the actual playlist list into a new composable --- .../screens/library/playlists/PlaylistList.kt | 115 +++++++++++------- 1 file changed, 73 insertions(+), 42 deletions(-) diff --git a/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt b/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt index 73fcb64e5..6f5d8fcb8 100644 --- a/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt +++ b/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt @@ -19,6 +19,8 @@ import com.simplecityapps.shuttle.model.SmartPlaylist import com.simplecityapps.shuttle.ui.common.components.CircularLoadingState import com.simplecityapps.shuttle.ui.common.components.HorizontalLoadingView import com.simplecityapps.shuttle.ui.common.components.LoadingStatusIndicator +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList @Composable fun PlaylistList( @@ -65,48 +67,77 @@ fun PlaylistList( } PlaylistListUiState.LoadingState.Ready -> { - LazyColumn( - modifier = modifier.fillMaxWidth(), - contentPadding = PaddingValues(vertical = 8.dp), - ) { - if (uiState.smartPlaylists.isNotEmpty()) { - item { - Text( - text = stringResource(R.string.playlists_title_smart_playlists), - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onBackground, - modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp) - ) - } - items(uiState.smartPlaylists) { smartPlaylist -> - SmartPlaylistListItem( - smartPlaylist = smartPlaylist, - onSmartPlaylistClick = onSmartPlaylistClick, - ) - } - } - if (uiState.playlists.isNotEmpty()) { - item { - Text( - text = stringResource(R.string.playlists_title_playlists), - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onBackground, - modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp) - ) - } - items(uiState.playlists) { playlist -> - PlaylistListItem( - playlist = playlist, - onPlaylistClick = onPlaylistClick, - onPlay = onPlay, - onAddToQueue = onAddToQueue, - onPlayNext = onPlayNext, - onDelete = onDelete, - onClear = onClear, - onRename = onRename, - ) - } - } + PlaylistList( + smartPlaylists = uiState.smartPlaylists.toImmutableList(), + playlists = uiState.playlists.toImmutableList(), + onSmartPlaylistClick = onSmartPlaylistClick, + onPlaylistClick = onPlaylistClick, + onPlay = onPlay, + onAddToQueue = onAddToQueue, + onPlayNext = onPlayNext, + onDelete = onDelete, + onClear = onClear, + onRename = onRename, + modifier = modifier, + ) + } + } +} + +@Composable +private fun PlaylistList( + smartPlaylists: ImmutableList, + playlists: ImmutableList, + onSmartPlaylistClick: (SmartPlaylist) -> Unit, + onPlaylistClick: (Playlist) -> Unit, + onPlay: (Playlist) -> Unit, + onAddToQueue: (Playlist) -> Unit, + onPlayNext: (Playlist) -> Unit, + onDelete: (Playlist) -> Unit, + onClear: (Playlist) -> Unit, + onRename: (Playlist) -> Unit, + modifier: Modifier = Modifier, +) { + LazyColumn( + modifier = modifier.fillMaxWidth(), + contentPadding = PaddingValues(vertical = 8.dp), + ) { + if (smartPlaylists.isNotEmpty()) { + item { + Text( + text = stringResource(R.string.playlists_title_smart_playlists), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onBackground, + modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp) + ) + } + items(smartPlaylists) { smartPlaylist -> + SmartPlaylistListItem( + smartPlaylist = smartPlaylist, + onSmartPlaylistClick = onSmartPlaylistClick, + ) + } + } + if (playlists.isNotEmpty()) { + item { + Text( + text = stringResource(R.string.playlists_title_playlists), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onBackground, + modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp) + ) + } + items(playlists) { playlist -> + PlaylistListItem( + playlist = playlist, + onPlaylistClick = onPlaylistClick, + onPlay = onPlay, + onAddToQueue = onAddToQueue, + onPlayNext = onPlayNext, + onDelete = onDelete, + onClear = onClear, + onRename = onRename, + ) } } } From b1ae552e77bf55150d6489f2239122d78ff87ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=80lex=20Magaz=20Gra=C3=A7a?= Date: Fri, 1 May 2026 19:05:56 +0200 Subject: [PATCH 2/3] Add scrollbar to Playlists tab --- .../screens/library/playlists/PlaylistList.kt | 93 +++++++++++-------- 1 file changed, 54 insertions(+), 39 deletions(-) diff --git a/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt b/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt index 6f5d8fcb8..492784c14 100644 --- a/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt +++ b/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt @@ -1,5 +1,6 @@ package com.simplecityapps.shuttle.ui.screens.library.playlists +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -7,6 +8,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -17,8 +19,10 @@ import com.simplecityapps.shuttle.R import com.simplecityapps.shuttle.model.Playlist import com.simplecityapps.shuttle.model.SmartPlaylist import com.simplecityapps.shuttle.ui.common.components.CircularLoadingState +import com.simplecityapps.shuttle.ui.common.components.FastScroller import com.simplecityapps.shuttle.ui.common.components.HorizontalLoadingView import com.simplecityapps.shuttle.ui.common.components.LoadingStatusIndicator +import com.simplecityapps.shuttle.ui.common.components.NoPopup import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -98,47 +102,58 @@ private fun PlaylistList( onRename: (Playlist) -> Unit, modifier: Modifier = Modifier, ) { - LazyColumn( - modifier = modifier.fillMaxWidth(), - contentPadding = PaddingValues(vertical = 8.dp), - ) { - if (smartPlaylists.isNotEmpty()) { - item { - Text( - text = stringResource(R.string.playlists_title_smart_playlists), - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onBackground, - modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp) - ) - } - items(smartPlaylists) { smartPlaylist -> - SmartPlaylistListItem( - smartPlaylist = smartPlaylist, - onSmartPlaylistClick = onSmartPlaylistClick, - ) - } - } - if (playlists.isNotEmpty()) { - item { - Text( - text = stringResource(R.string.playlists_title_playlists), - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onBackground, - modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp) - ) + val state = rememberLazyListState() + + Box(modifier = modifier.fillMaxSize()) { + LazyColumn( + modifier = Modifier.fillMaxWidth(), + contentPadding = PaddingValues(vertical = 8.dp), + state = state, + ) { + if (smartPlaylists.isNotEmpty()) { + item { + Text( + text = stringResource(R.string.playlists_title_smart_playlists), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onBackground, + modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp) + ) + } + items(smartPlaylists) { smartPlaylist -> + SmartPlaylistListItem( + smartPlaylist = smartPlaylist, + onSmartPlaylistClick = onSmartPlaylistClick, + ) + } } - items(playlists) { playlist -> - PlaylistListItem( - playlist = playlist, - onPlaylistClick = onPlaylistClick, - onPlay = onPlay, - onAddToQueue = onAddToQueue, - onPlayNext = onPlayNext, - onDelete = onDelete, - onClear = onClear, - onRename = onRename, - ) + if (playlists.isNotEmpty()) { + item { + Text( + text = stringResource(R.string.playlists_title_playlists), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onBackground, + modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp) + ) + } + items(playlists) { playlist -> + PlaylistListItem( + playlist = playlist, + onPlaylistClick = onPlaylistClick, + onPlay = onPlay, + onAddToQueue = onAddToQueue, + onPlayNext = onPlayNext, + onDelete = onDelete, + onClear = onClear, + onRename = onRename, + ) + } } } + FastScroller( + modifier = Modifier.fillMaxSize().padding(vertical = 8.dp), + state = state, + popup = ::NoPopup, + getPopupText = { null }, + ) } } From 564036089aaf0c32a2c63579ec248372247568ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=80lex=20Magaz=20Gra=C3=A7a?= Date: Fri, 1 May 2026 19:34:47 +0200 Subject: [PATCH 3/3] Add convenience noPopupText function to use with NoPopup composable --- .../shuttle/ui/common/components/FastScroller.kt | 3 +++ .../shuttle/ui/screens/library/playlists/PlaylistList.kt | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/simplecityapps/shuttle/ui/common/components/FastScroller.kt b/android/app/src/main/java/com/simplecityapps/shuttle/ui/common/components/FastScroller.kt index 0b2dcb328..a28dd2f60 100644 --- a/android/app/src/main/java/com/simplecityapps/shuttle/ui/common/components/FastScroller.kt +++ b/android/app/src/main/java/com/simplecityapps/shuttle/ui/common/components/FastScroller.kt @@ -297,6 +297,9 @@ fun DefaultPopup( @Composable fun NoPopup(index: Int) = Unit +/** Pass this to the getPopupText parameter in FastScroller when using [NoPopup]. */ +fun noPopupText(index: Int): String? = null + @Preview(showBackground = true) @Composable private fun FastScrollPreview() { diff --git a/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt b/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt index 492784c14..d9b062b01 100644 --- a/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt +++ b/android/app/src/main/java/com/simplecityapps/shuttle/ui/screens/library/playlists/PlaylistList.kt @@ -23,6 +23,7 @@ import com.simplecityapps.shuttle.ui.common.components.FastScroller import com.simplecityapps.shuttle.ui.common.components.HorizontalLoadingView import com.simplecityapps.shuttle.ui.common.components.LoadingStatusIndicator import com.simplecityapps.shuttle.ui.common.components.NoPopup +import com.simplecityapps.shuttle.ui.common.components.noPopupText import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -153,7 +154,7 @@ private fun PlaylistList( modifier = Modifier.fillMaxSize().padding(vertical = 8.dp), state = state, popup = ::NoPopup, - getPopupText = { null }, + getPopupText = ::noPopupText, ) } }