Skip to content

Commit

Permalink
feat: auto scroll up and down when reordering, close #1498
Browse files Browse the repository at this point in the history
  • Loading branch information
z-huang committed Aug 31, 2024
1 parent 92f5878 commit cd6be33
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 44 deletions.
71 changes: 45 additions & 26 deletions app/src/main/java/com/zionhuang/music/ui/player/Queue.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
Expand Down Expand Up @@ -100,10 +101,8 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.burnoutcrew.reorderable.ReorderableItem
import org.burnoutcrew.reorderable.detectReorder
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
import org.burnoutcrew.reorderable.reorderable
import sh.calvin.reorderable.ReorderableItem
import sh.calvin.reorderable.rememberReorderableLazyListState
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
Expand Down Expand Up @@ -268,23 +267,46 @@ fun Queue(
}

val coroutineScope = rememberCoroutineScope()
val lazyListState = rememberLazyListState()
var dragInfo by remember {
mutableStateOf<Pair<Int, Int>?>(null)
}
val reorderableState = rememberReorderableLazyListState(
onMove = { from, to ->
mutableQueueWindows.move(from.index, to.index)
},
onDragEnd = { fromIndex, toIndex ->
if (!playerConnection.player.shuffleModeEnabled) {
playerConnection.player.moveMediaItem(fromIndex, toIndex)
} else {
playerConnection.player.setShuffleOrder(
DefaultShuffleOrder(
queueWindows.map { it.firstPeriodIndex }.toMutableList().move(fromIndex, toIndex).toIntArray(),
System.currentTimeMillis()
lazyListState = lazyListState,
scrollThresholdPadding = WindowInsets.systemBars.add(
WindowInsets(
top = ListItemHeight,
bottom = ListItemHeight
)
).asPaddingValues()
) { from, to ->
val currentDragInfo = dragInfo
dragInfo = if (currentDragInfo == null) {
from.index to to.index
} else {
currentDragInfo.first to to.index
}

mutableQueueWindows.move(from.index, to.index)
}

LaunchedEffect(reorderableState.isAnyItemDragging) {
if (!reorderableState.isAnyItemDragging) {
dragInfo?.let { (from, to) ->
if (!playerConnection.player.shuffleModeEnabled) {
playerConnection.player.moveMediaItem(from, to)
} else {
playerConnection.player.setShuffleOrder(
DefaultShuffleOrder(
queueWindows.map { it.firstPeriodIndex }.toMutableList().move(from, to).toIntArray(),
System.currentTimeMillis()
)
)
)
}
dragInfo = null
}
}
)
}

LaunchedEffect(queueWindows) {
mutableQueueWindows.apply {
Expand All @@ -300,12 +322,12 @@ fun Queue(

LaunchedEffect(mutableQueueWindows) {
if (currentWindowIndex != -1) {
reorderableState.listState.scrollToItem(currentWindowIndex)
lazyListState.scrollToItem(currentWindowIndex)
}
}

LazyColumn(
state = reorderableState.listState,
state = lazyListState,
contentPadding = WindowInsets.systemBars
.add(
WindowInsets(
Expand All @@ -314,16 +336,14 @@ fun Queue(
)
)
.asPaddingValues(),
modifier = Modifier
.reorderable(reorderableState)
.nestedScroll(state.preUpPostDownNestedScrollConnection)
modifier = Modifier.nestedScroll(state.preUpPostDownNestedScrollConnection)
) {
itemsIndexed(
items = mutableQueueWindows,
key = { _, item -> item.uid.hashCode() }
) { index, window ->
ReorderableItem(
reorderableState = reorderableState,
state = reorderableState,
key = window.uid.hashCode()
) {
val currentItem by rememberUpdatedState(window)
Expand Down Expand Up @@ -378,8 +398,7 @@ fun Queue(
if (!lockQueue) {
IconButton(
onClick = { },
modifier = Modifier
.detectReorder(reorderableState)
modifier = Modifier.draggableHandle()
) {
Icon(
painter = painterResource(R.drawable.drag_handle),
Expand Down Expand Up @@ -524,7 +543,7 @@ fun Queue(
modifier = Modifier.align(Alignment.CenterStart),
onClick = {
coroutineScope.launch {
reorderableState.listState.animateScrollToItem(
lazyListState.animateScrollToItem(
if (playerConnection.player.shuffleModeEnabled) playerConnection.player.currentMediaItemIndex else 0
)
}.invokeOnCompletion {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.union
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.Button
Expand Down Expand Up @@ -131,10 +132,8 @@ import com.zionhuang.music.viewmodels.LocalPlaylistViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.burnoutcrew.reorderable.ReorderableItem
import org.burnoutcrew.reorderable.detectReorder
import org.burnoutcrew.reorderable.rememberReorderableLazyListState
import org.burnoutcrew.reorderable.reorderable
import sh.calvin.reorderable.ReorderableItem
import sh.calvin.reorderable.rememberReorderableLazyListState

@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
@Composable
Expand Down Expand Up @@ -215,22 +214,40 @@ fun LocalPlaylistScreen(
}

val headerItems = 2
val lazyListState = rememberLazyListState()
var dragInfo by remember {
mutableStateOf<Pair<Int, Int>?>(null)
}
val reorderableState = rememberReorderableLazyListState(
onMove = { from, to ->
if (to.index >= headerItems && from.index >= headerItems) {
mutableSongs.move(from.index - headerItems, to.index - headerItems)
lazyListState = lazyListState,
scrollThresholdPadding = LocalPlayerAwareWindowInsets.current.asPaddingValues()
) { from, to ->
if (to.index >= headerItems && from.index >= headerItems) {
val currentDragInfo = dragInfo
dragInfo = if (currentDragInfo == null) {
(from.index - headerItems) to (to.index - headerItems)
} else {
currentDragInfo.first to (to.index - headerItems)
}
},
onDragEnd = { fromIndex, toIndex ->
database.transaction {
move(viewModel.playlistId, fromIndex - headerItems, toIndex - headerItems)

mutableSongs.move(from.index - headerItems, to.index - headerItems)
}
}

LaunchedEffect(reorderableState.isAnyItemDragging) {
if (!reorderableState.isAnyItemDragging) {
dragInfo?.let { (from, to) ->
database.transaction {
move(viewModel.playlistId, from, to)
}
dragInfo = null
}
}
)
}

val showTopBarTitle by remember {
derivedStateOf {
reorderableState.listState.firstVisibleItemIndex > 0
lazyListState.firstVisibleItemIndex > 0
}
}

Expand Down Expand Up @@ -294,9 +311,8 @@ fun LocalPlaylistScreen(
modifier = Modifier.fillMaxSize()
) {
LazyColumn(
state = reorderableState.listState,
state = lazyListState,
contentPadding = LocalPlayerAwareWindowInsets.current.union(WindowInsets.ime).asPaddingValues(),
modifier = Modifier.reorderable(reorderableState)
) {
playlist?.let { playlist ->
if (playlist.songCount == 0) {
Expand Down Expand Up @@ -366,7 +382,7 @@ fun LocalPlaylistScreen(
key = { _, song -> song.map.id }
) { index, song ->
ReorderableItem(
reorderableState = reorderableState,
state = reorderableState,
key = song.map.id
) {
val currentItem by rememberUpdatedState(song)
Expand Down Expand Up @@ -446,7 +462,7 @@ fun LocalPlaylistScreen(
if (sortType == PlaylistSongSortType.CUSTOM && !locked && !isSearching) {
IconButton(
onClick = { },
modifier = Modifier.detectReorder(reorderableState)
modifier = Modifier.draggableHandle()
) {
Icon(
painter = painterResource(R.drawable.drag_handle),
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ compose-ui-util = { group = "androidx.compose.ui", name = "ui-util", version.ref
compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "compose" }
compose-animation = { group = "androidx.compose.animation", name = "animation-graphics", version.ref = "compose" }
compose-animation-graphics = { group = "androidx.compose.animation", name = "animation-graphics", version.ref = "compose" }
compose-reorderable = { group = "org.burnoutcrew.composereorderable", name = "reorderable", version = "0.9.6" }
compose-reorderable = { module = "sh.calvin.reorderable:reorderable", version = "2.3.1" }

viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle" }
Expand Down

0 comments on commit cd6be33

Please sign in to comment.