enable drag and drop reordering

This commit is contained in:
Drew Weymouth
2024-06-22 17:10:26 -07:00
parent f5a4146e2b
commit 4545839e92
9 changed files with 79 additions and 160 deletions
+23 -83
View File
@@ -1,9 +1,6 @@
package sharedutil
import (
"math"
"slices"
"github.com/dweymouth/supersonic/backend/mediaprovider"
)
@@ -106,90 +103,33 @@ func TracksToIDs(tracks []*mediaprovider.Track) []string {
})
}
type TrackReorderOp int
const (
MoveToTop TrackReorderOp = iota
MoveToBottom
MoveUp
MoveDown
)
// Reorder items and return a new track slice.
// idxToMove must contain only valid indexes into tracks, and no repeats
func ReorderItems[T any](items []T, idxToMove []int, op TrackReorderOp) []T {
newItems := make([]T, len(items))
switch op {
case MoveToTop:
topIdx := 0
botIdx := len(idxToMove)
idxToMoveSet := ToSet(idxToMove)
for i, t := range items {
if _, ok := idxToMoveSet[i]; ok {
newItems[topIdx] = t
topIdx++
} else {
newItems[botIdx] = t
botIdx++
}
func ReorderItems[T any](items []T, idxToMove []int, insertIdx int) []T {
idxToMoveSet := ToSet(idxToMove)
newItems := make([]T, 0, len(items))
// collect items that will end up before the insertion set
i := 0
for ; i < len(items); i++ {
if insertIdx == i {
break
}
case MoveToBottom:
topIdx := 0
botIdx := len(items) - len(idxToMove)
idxToMoveSet := ToSet(idxToMove)
for i, t := range items {
if _, ok := idxToMoveSet[i]; ok {
newItems[botIdx] = t
botIdx++
} else {
newItems[topIdx] = t
topIdx++
}
}
case MoveUp:
first := firstIdxCanMoveUp(idxToMove)
copy(newItems, items)
for _, i := range idxToMove {
if i < first {
continue
}
newItems[i-1], newItems[i] = newItems[i], newItems[i-1]
}
case MoveDown:
last := lastIdxCanMoveDown(idxToMove, len(items))
copy(newItems, items)
for i := len(idxToMove) - 1; i >= 0; i-- {
idx := idxToMove[i]
if idx > last {
continue
}
newItems[idx+1], newItems[idx] = newItems[idx], newItems[idx+1]
if _, ok := idxToMoveSet[i]; !ok {
newItems = append(newItems, items[i])
}
}
for _, idx := range idxToMove {
newItems = append(newItems, items[idx])
}
for ; i < len(items); i++ {
if _, ok := idxToMoveSet[i]; !ok {
newItems = append(newItems, items[i])
}
}
return newItems
}
func firstIdxCanMoveUp(idxs []int) int {
prevIdx := -1
slices.Sort(idxs)
for _, idx := range idxs {
if idx > prevIdx+1 {
return idx
}
prevIdx = idx
}
return math.MaxInt
}
func lastIdxCanMoveDown(idxs []int, lenSlice int) int {
prevIdx := lenSlice
slices.Sort(idxs)
for i := len(idxs) - 1; i >= 0; i-- {
idx := idxs[i]
if idx < prevIdx-1 {
return idx
}
prevIdx = idx
}
return -1
}
+3 -32
View File
@@ -8,6 +8,7 @@ import (
)
func Test_ReorderItems(t *testing.T) {
tracks := []*mediaprovider.Track{
{ID: "a"}, // 0
{ID: "b"}, // 1
@@ -27,7 +28,7 @@ func Test_ReorderItems(t *testing.T) {
{ID: "b"},
{ID: "e"},
}
newTracks := ReorderItems(tracks, idxToMove, MoveToTop)
newTracks := ReorderItems(tracks, idxToMove, 0)
if !tracklistsEqual(t, newTracks, want) {
t.Error("ReorderTracks: MoveToTop order incorrect")
}
@@ -42,40 +43,10 @@ func Test_ReorderItems(t *testing.T) {
{ID: "c"},
{ID: "f"},
}
newTracks = ReorderItems(tracks, idxToMove, MoveToBottom)
newTracks = ReorderItems(tracks, idxToMove, len(tracks))
if !tracklistsEqual(t, newTracks, want) {
t.Error("ReorderTracks: MoveToBottom order incorrect")
}
// test MoveUp:
idxToMove = []int{0, 1, 3, 5}
want = []*mediaprovider.Track{
{ID: "a"},
{ID: "b"},
{ID: "d"},
{ID: "c"},
{ID: "f"},
{ID: "e"},
}
newTracks = ReorderItems(tracks, idxToMove, MoveUp)
if !tracklistsEqual(t, newTracks, want) {
t.Error("ReorderTracks: MoveUp order incorrect")
}
// test MoveDown:
idxToMove = []int{2, 4, 5}
want = []*mediaprovider.Track{
{ID: "a"},
{ID: "b"},
{ID: "d"},
{ID: "c"},
{ID: "e"},
{ID: "f"},
}
newTracks = ReorderItems(tracks, idxToMove, MoveDown)
if !tracklistsEqual(t, newTracks, want) {
t.Error("ReorderTracks: MoveDown order incorrect")
}
}
func tracklistsEqual(t *testing.T, a, b []*mediaprovider.Track) bool {