@@ -15,21 +15,24 @@ import androidx.compose.foundation.layout.Column
1515import androidx.compose.foundation.layout.PaddingValues
1616import androidx.compose.foundation.layout.Spacer
1717import androidx.compose.foundation.layout.fillMaxSize
18+ import androidx.compose.foundation.layout.fillMaxWidth
1819import androidx.compose.foundation.layout.height
1920import androidx.compose.foundation.layout.padding
2021import androidx.compose.foundation.lazy.grid.GridCells
22+ import androidx.compose.foundation.lazy.grid.GridItemSpan
2123import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
2224import androidx.compose.foundation.lazy.grid.items
25+ import androidx.compose.foundation.lazy.grid.rememberLazyGridState
2326import androidx.compose.material.icons.Icons
2427import androidx.compose.material.icons.automirrored.filled.ArrowBack
2528import androidx.compose.material.icons.filled.Add
2629import androidx.compose.material3.Button
2730import androidx.compose.material3.CenterAlignedTopAppBar
28- import androidx.compose.material3.CircularProgressIndicator
2931import androidx.compose.material3.ExperimentalMaterial3Api
3032import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
3133import androidx.compose.material3.Icon
3234import androidx.compose.material3.IconButton
35+ import androidx.compose.material3.LoadingIndicator
3336import androidx.compose.material3.MaterialTheme
3437import androidx.compose.material3.Scaffold
3538import androidx.compose.material3.Text
@@ -46,6 +49,7 @@ import androidx.compose.runtime.getValue
4649import androidx.compose.runtime.mutableStateOf
4750import androidx.compose.runtime.remember
4851import androidx.compose.runtime.setValue
52+ import androidx.compose.runtime.snapshotFlow
4953import androidx.compose.ui.Alignment
5054import androidx.compose.ui.Modifier
5155import androidx.compose.ui.graphics.graphicsLayer
@@ -80,6 +84,8 @@ fun MyPlayListScreen(
8084 var isRefreshing by remember { mutableStateOf(false ) }
8185 val refreshState = rememberPullToRefreshState()
8286 val showSheet by viewModel.showSheet.collectAsState()
87+ val isLoadingMorePlaylists by viewModel.isLoadingMorePlaylists.collectAsState()
88+ val noMorePlaylists by viewModel.noMorePlaylists.collectAsState()
8389 val selectedListCode = remember { mutableStateOf(" " ) }
8490 val listTitle = remember { mutableStateOf(" " ) }
8591 val context = LocalContext .current
@@ -184,12 +190,18 @@ fun MyPlayListScreen(
184190 when (val result = state) {
185191 is WebsiteState .Loading -> {
186192 if (playlists.isEmpty()) {
187- CircularProgressIndicator (Modifier .align(Alignment .Center ))
193+ LoadingIndicator (Modifier .align(Alignment .Center ))
188194 } else {
189195 // 显示旧数据,刷新中不替换内容
190196 AnimatedPageContent (
191197 state,
192- playlists = playlists
198+ playlists = playlists,
199+ playlistPage = viewModel.playlistPage,
200+ isLoadingMore = isLoadingMorePlaylists,
201+ noMorePlaylists = noMorePlaylists,
202+ onLoadNextPage = {
203+ viewModel.loadMyPlayList(viewModel.playlistPage + 1 )
204+ }
193205 ){ listCode, playListTitle ->
194206 selectedListCode.value = listCode
195207 viewModel.setShowSheet(true )
@@ -208,7 +220,13 @@ fun MyPlayListScreen(
208220 // 显示旧缓存内容(保持体验)
209221 AnimatedPageContent (
210222 state,
211- playlists = playlists
223+ playlists = playlists,
224+ playlistPage = viewModel.playlistPage,
225+ isLoadingMore = isLoadingMorePlaylists,
226+ noMorePlaylists = noMorePlaylists,
227+ onLoadNextPage = {
228+ viewModel.loadMyPlayList(viewModel.playlistPage + 1 )
229+ }
212230 ){ listCode, playListTitle ->
213231 selectedListCode.value = listCode
214232 viewModel.setShowSheet(true )
@@ -221,7 +239,13 @@ fun MyPlayListScreen(
221239 // 统一渲染缓存(成功后缓存已更新)
222240 AnimatedPageContent (
223241 state,
224- playlists = playlists
242+ playlists = playlists,
243+ playlistPage = viewModel.playlistPage,
244+ isLoadingMore = isLoadingMorePlaylists,
245+ noMorePlaylists = noMorePlaylists,
246+ onLoadNextPage = {
247+ viewModel.loadMyPlayList(viewModel.playlistPage + 1 )
248+ }
225249 ) { listCode, playListTitle ->
226250 selectedListCode.value = listCode
227251 viewModel.setShowSheet(true )
@@ -257,9 +281,9 @@ fun MyPlayListScreen(
257281 playListTitle = listTitle.value,
258282 onClickItem = { item ->
259283 onClickItem(item)
260- viewModel.setShowSheet(false )
261- viewModel.currentPage = 1
262- viewModel.clearCurrentList()
284+ // viewModel.setShowSheet(false)
285+ // viewModel.currentPage = 1
286+ // viewModel.clearCurrentList()
263287 } ,
264288 onLongClickItem = onLongClickItem,
265289 vm = viewModel,
@@ -270,13 +294,37 @@ fun MyPlayListScreen(
270294 }
271295}
272296
297+ @OptIn(ExperimentalMaterial3ExpressiveApi ::class )
273298@Composable
274299fun AnimatedPageContent (
275300 state : WebsiteState <Playlists >,
276301 playlists : List <Playlists .Playlist >,
302+ isLoadingMore : Boolean = false,
303+ noMorePlaylists : Boolean = false,
304+ playlistPage : Int = 1,
305+ onLoadNextPage : () -> Unit = {},
277306 onRetry : () -> Unit = {},
278307 onPlaylistClick : (listCode: String , playListTitle: String ) -> Unit
279308) {
309+ val gridState = rememberLazyGridState()
310+
311+ LaunchedEffect (gridState) {
312+ snapshotFlow {
313+ val layoutInfo = gridState.layoutInfo
314+ val totalItems = layoutInfo.totalItemsCount
315+ val lastVisibleItem = layoutInfo.visibleItemsInfo.lastOrNull()?.index ? : 0
316+ Triple (
317+ lastVisibleItem >= totalItems - 3 && playlists.isNotEmpty(),
318+ isLoadingMore,
319+ noMorePlaylists
320+ )
321+ }
322+ .collect { (shouldLoad, loading, noMore) ->
323+ if (shouldLoad && ! loading && ! noMore) {
324+ onLoadNextPage()
325+ }
326+ }
327+ }
280328
281329 AnimatedContent (
282330 targetState = state,
@@ -288,7 +336,7 @@ fun AnimatedPageContent(
288336 when (target) {
289337 is WebsiteState .Loading -> {
290338 Box (Modifier .fillMaxSize(), contentAlignment = Alignment .Center ) {
291- CircularProgressIndicator ()
339+ LoadingIndicator ()
292340 }
293341 }
294342
@@ -305,11 +353,12 @@ fun AnimatedPageContent(
305353 }
306354
307355 is WebsiteState .Success -> {
308- if (target.info.playlists.isEmpty()){
356+ if (target.info.playlists.isEmpty() && playlists.isEmpty() ){
309357 EmptyView (stringResource(R .string.empty_content))
310358 return @AnimatedContent
311359 }
312360 LazyVerticalGrid (
361+ state = gridState,
313362 columns = GridCells .Fixed (getColumnCount(180 )),
314363 contentPadding = PaddingValues (16 .dp),
315364 verticalArrangement = Arrangement .spacedBy(16 .dp),
@@ -324,6 +373,35 @@ fun AnimatedPageContent(
324373 onPlaylistClick(playlist.listCode, playlist.title)
325374 }
326375 }
376+ if (isLoadingMore) {
377+ item(span = { GridItemSpan (maxLineSpan) }) {
378+ Box (
379+ Modifier
380+ .fillMaxWidth()
381+ .padding(16 .dp),
382+ contentAlignment = Alignment .Center
383+ ) {
384+ LoadingIndicator ()
385+ }
386+ }
387+ }
388+ if (noMorePlaylists && playlists.isNotEmpty()) {
389+ item(span = { GridItemSpan (maxLineSpan) }) {
390+ Box (
391+ Modifier
392+ .fillMaxWidth()
393+ .padding(vertical = 16 .dp),
394+ contentAlignment = Alignment .Center
395+ ) {
396+ Text (
397+ text = stringResource(R .string.load_complete_with_pages, playlistPage - 1 ),
398+ style = MaterialTheme .typography.bodySmall.copy(
399+ color = MaterialTheme .colorScheme.onSurfaceVariant
400+ )
401+ )
402+ }
403+ }
404+ }
327405 }
328406 }
329407 }
0 commit comments