refactor a bit and have tracklist respond to set sorting calls
This commit is contained in:
+28
-13
@@ -15,14 +15,19 @@ import (
|
|||||||
"fyne.io/fyne/v2/widget"
|
"fyne.io/fyne/v2/widget"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ColumnSort int
|
type SortType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SortNone ColumnSort = iota
|
SortNone SortType = iota
|
||||||
SortAscending
|
SortAscending
|
||||||
SortDescending
|
SortDescending
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ListHeaderSort struct {
|
||||||
|
ColNumber int
|
||||||
|
Type SortType
|
||||||
|
}
|
||||||
|
|
||||||
type ListColumn struct {
|
type ListColumn struct {
|
||||||
Text string
|
Text string
|
||||||
AlignTrailing bool
|
AlignTrailing bool
|
||||||
@@ -34,10 +39,11 @@ type ListHeader struct {
|
|||||||
|
|
||||||
DisableSorting bool
|
DisableSorting bool
|
||||||
|
|
||||||
OnColumnSortChanged func(int, ColumnSort)
|
OnColumnSortChanged func(ListHeaderSort)
|
||||||
OnColumnVisibilityChanged func(int, bool)
|
OnColumnVisibilityChanged func(int, bool)
|
||||||
OnColumnVisibilityMenuShown func(*widget.PopUp)
|
OnColumnVisibilityMenuShown func(*widget.PopUp)
|
||||||
|
|
||||||
|
sort ListHeaderSort
|
||||||
columns []ListColumn
|
columns []ListColumn
|
||||||
columnVisible []bool
|
columnVisible []bool
|
||||||
columnsLayout *layouts.ColumnsLayout
|
columnsLayout *layouts.ColumnsLayout
|
||||||
@@ -80,8 +86,8 @@ func (l *ListHeader) SetColumnVisible(colNum int, visible bool) {
|
|||||||
func (l *ListHeader) buildColumns() {
|
func (l *ListHeader) buildColumns() {
|
||||||
for i, c := range l.columns {
|
for i, c := range l.columns {
|
||||||
hdr := newColHeader(c, &l.DisableSorting)
|
hdr := newColHeader(c, &l.DisableSorting)
|
||||||
hdr.OnSortChanged = func(i int) func(ColumnSort) {
|
hdr.OnSortChanged = func(i int) func(SortType) {
|
||||||
return func(sort ColumnSort) { l.onSortChanged(i, sort) }
|
return func(sort SortType) { l.SetSorting(ListHeaderSort{ColNumber: i, Type: sort}) }
|
||||||
}(i)
|
}(i)
|
||||||
hdr.OnTappedSecondary = l.TappedSecondary
|
hdr.OnTappedSecondary = l.TappedSecondary
|
||||||
l.columnsContainer.Add(
|
l.columnsContainer.Add(
|
||||||
@@ -95,17 +101,26 @@ func (l *ListHeader) buildColumns() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *ListHeader) onSortChanged(colNum int, sort ColumnSort) {
|
// Sets the sorting for the ListHeader. Will invoke
|
||||||
|
// OnColumnSortChanged if set.
|
||||||
|
func (l *ListHeader) SetSorting(sort ListHeaderSort) {
|
||||||
|
if l.sort == sort {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
l.sort = sort
|
||||||
for i, c := range l.columnsContainer.Objects {
|
for i, c := range l.columnsContainer.Objects {
|
||||||
if i != colNum {
|
// TODO
|
||||||
c.(*fyne.Container).Objects[1].(*colHeader).Sort = SortNone
|
//c.(*colHeader).Sort = sortNone
|
||||||
// TODO
|
hdr := c.(*fyne.Container).Objects[1].(*colHeader)
|
||||||
//c.(*colHeader).Sort = sortNone
|
if i == sort.ColNumber {
|
||||||
|
hdr.Sort = sort.Type
|
||||||
|
} else {
|
||||||
|
hdr.Sort = SortNone
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l.Refresh()
|
l.Refresh()
|
||||||
if l.OnColumnSortChanged != nil {
|
if l.OnColumnSortChanged != nil {
|
||||||
l.OnColumnSortChanged(colNum, sort)
|
l.OnColumnSortChanged(sort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,8 +171,8 @@ func (l *ListHeader) createOnChangedCallbk(colNum int) func(bool) {
|
|||||||
type colHeader struct {
|
type colHeader struct {
|
||||||
widget.BaseWidget
|
widget.BaseWidget
|
||||||
|
|
||||||
Sort ColumnSort
|
Sort SortType
|
||||||
OnSortChanged func(ColumnSort)
|
OnSortChanged func(SortType)
|
||||||
OnTappedSecondary func(*fyne.PointEvent)
|
OnTappedSecondary func(*fyne.PointEvent)
|
||||||
|
|
||||||
sortDisabled *bool
|
sortDisabled *bool
|
||||||
|
|||||||
+84
-76
@@ -43,7 +43,7 @@ var columns = []string{
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TracklistSort struct {
|
type TracklistSort struct {
|
||||||
SortOrder ColumnSort
|
SortOrder SortType
|
||||||
ColumnName string
|
ColumnName string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,9 +108,7 @@ func NewTracklist(tracks []*mediaprovider.Track) *Tracklist {
|
|||||||
// #, Title, Artist, Album, Time, Year, Favorite, Rating, Plays, Bitrate, Size, Path
|
// #, Title, Artist, Album, Time, Year, Favorite, Rating, Plays, Bitrate, Size, Path
|
||||||
t.colLayout = layouts.NewColumnsLayout([]float32{40, -1, -1, -1, 60, 60, 55, 100, 65, 75, 75, -1})
|
t.colLayout = layouts.NewColumnsLayout([]float32{40, -1, -1, -1, 60, 60, 55, 100, 65, 75, 75, -1})
|
||||||
t.buildHeader()
|
t.buildHeader()
|
||||||
t.hdr.OnColumnSortChanged = func(idx int, sort ColumnSort) {
|
t.hdr.OnColumnSortChanged = t.onSorted
|
||||||
t.SetSorting(TracklistSort{ColumnName: colName(idx), SortOrder: sort})
|
|
||||||
}
|
|
||||||
t.hdr.OnColumnVisibilityChanged = t.setColumnVisible
|
t.hdr.OnColumnVisibilityChanged = t.setColumnVisible
|
||||||
t.hdr.OnColumnVisibilityMenuShown = func(pop *widget.PopUp) {
|
t.hdr.OnColumnVisibilityMenuShown = func(pop *widget.PopUp) {
|
||||||
if t.OnColumnVisibilityMenuShown != nil {
|
if t.OnColumnVisibilityMenuShown != nil {
|
||||||
@@ -210,81 +208,16 @@ func (t *Tracklist) setColumnVisible(colNum int, vis bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracklist) stringSort(fieldFn func(*mediaprovider.Track) string, sortOrder ColumnSort) {
|
|
||||||
new := make([]*mediaprovider.Track, len(t.tracksOrigOrder))
|
|
||||||
copy(new, t.tracksOrigOrder)
|
|
||||||
sort.SliceStable(new, func(i, j int) bool {
|
|
||||||
cmp := strings.Compare(fieldFn(new[i]), fieldFn(new[j]))
|
|
||||||
if sortOrder == SortDescending {
|
|
||||||
return cmp > 0
|
|
||||||
}
|
|
||||||
return cmp < 0
|
|
||||||
})
|
|
||||||
t.tracks = new
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tracklist) intSort(fieldFn func(*mediaprovider.Track) int64, sortOrder ColumnSort) {
|
|
||||||
new := make([]*mediaprovider.Track, len(t.tracksOrigOrder))
|
|
||||||
copy(new, t.tracksOrigOrder)
|
|
||||||
sort.SliceStable(new, func(i, j int) bool {
|
|
||||||
if sortOrder == SortDescending {
|
|
||||||
return fieldFn(new[i]) > fieldFn(new[j])
|
|
||||||
}
|
|
||||||
return fieldFn(new[i]) < fieldFn(new[j])
|
|
||||||
})
|
|
||||||
t.tracks = new
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tracklist) Sorting() TracklistSort {
|
func (t *Tracklist) Sorting() TracklistSort {
|
||||||
return t.sorting
|
return t.sorting
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracklist) SetSorting(sorting TracklistSort) {
|
func (t *Tracklist) SetSorting(sorting TracklistSort) {
|
||||||
t.sorting = sorting
|
if sorting.ColumnName == "" {
|
||||||
t.tracksMutex.Lock()
|
|
||||||
if sorting.SortOrder == SortNone {
|
|
||||||
t.tracks = t.tracksOrigOrder
|
|
||||||
t.tracksMutex.Unlock()
|
|
||||||
t.Refresh()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch sorting.ColumnName {
|
// actual sorting will be handled in callback from header
|
||||||
case ColumnNum:
|
t.hdr.SetSorting(ListHeaderSort{ColNumber: ColNumber(sorting.ColumnName), Type: sorting.SortOrder})
|
||||||
if sorting.SortOrder == SortDescending {
|
|
||||||
t.tracks = sharedutil.Reversed(t.tracksOrigOrder)
|
|
||||||
} else {
|
|
||||||
t.tracks = t.tracksOrigOrder
|
|
||||||
}
|
|
||||||
case ColumnTitle:
|
|
||||||
t.stringSort(func(tr *mediaprovider.Track) string { return tr.Name }, sorting.SortOrder)
|
|
||||||
case ColumnArtist:
|
|
||||||
t.stringSort(func(tr *mediaprovider.Track) string { return tr.ArtistNames[0] }, sorting.SortOrder)
|
|
||||||
case ColumnAlbum:
|
|
||||||
t.stringSort(func(tr *mediaprovider.Track) string { return tr.Album }, sorting.SortOrder)
|
|
||||||
case ColumnPath:
|
|
||||||
t.stringSort(func(tr *mediaprovider.Track) string { return tr.FilePath }, sorting.SortOrder)
|
|
||||||
case ColumnRating:
|
|
||||||
t.intSort(func(tr *mediaprovider.Track) int64 { return int64(tr.Rating) }, sorting.SortOrder)
|
|
||||||
case ColumnTime:
|
|
||||||
t.intSort(func(tr *mediaprovider.Track) int64 { return int64(tr.Duration) }, sorting.SortOrder)
|
|
||||||
case ColumnYear:
|
|
||||||
t.intSort(func(tr *mediaprovider.Track) int64 { return int64(tr.Year) }, sorting.SortOrder)
|
|
||||||
case ColumnSize:
|
|
||||||
t.intSort(func(tr *mediaprovider.Track) int64 { return tr.Size }, sorting.SortOrder)
|
|
||||||
case ColumnPlays:
|
|
||||||
t.intSort(func(tr *mediaprovider.Track) int64 { return int64(tr.PlayCount) }, sorting.SortOrder)
|
|
||||||
case ColumnBitrate:
|
|
||||||
t.intSort(func(tr *mediaprovider.Track) int64 { return int64(tr.BitRate) }, sorting.SortOrder)
|
|
||||||
case ColumnFavorite:
|
|
||||||
t.intSort(func(tr *mediaprovider.Track) int64 {
|
|
||||||
if tr.Favorite {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}, sorting.SortOrder)
|
|
||||||
}
|
|
||||||
t.tracksMutex.Unlock()
|
|
||||||
t.Refresh()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracklist) SetNowPlaying(trackID string) {
|
func (t *Tracklist) SetNowPlaying(trackID string) {
|
||||||
@@ -302,7 +235,7 @@ func (t *Tracklist) IncrementPlayCount(trackID string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all tracks from the tracklist. Thread-safe.
|
// Remove all tracks from the tracklist. Does not issue Refresh call. Thread-safe.
|
||||||
func (t *Tracklist) Clear() {
|
func (t *Tracklist) Clear() {
|
||||||
t.selectionMgr.UnselectAll()
|
t.selectionMgr.UnselectAll()
|
||||||
t.tracksMutex.Lock()
|
t.tracksMutex.Lock()
|
||||||
@@ -310,12 +243,12 @@ func (t *Tracklist) Clear() {
|
|||||||
t.tracks = nil
|
t.tracks = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the tracks in the tracklist. Thread-safe.
|
// Sets the tracks in the tracklist. Does not issue Refresh call. Thread-safe.
|
||||||
func (t *Tracklist) SetTracks(trs []*mediaprovider.Track) {
|
func (t *Tracklist) SetTracks(trs []*mediaprovider.Track) {
|
||||||
t.tracksMutex.Lock()
|
t.tracksMutex.Lock()
|
||||||
defer t.tracksMutex.Unlock()
|
defer t.tracksMutex.Unlock()
|
||||||
t.tracks = trs
|
|
||||||
t.tracksOrigOrder = trs
|
t.tracksOrigOrder = trs
|
||||||
|
t.doSortTracks()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the tracks in the tracklist in the current display order.
|
// Returns the tracks in the tracklist in the current display order.
|
||||||
@@ -325,7 +258,7 @@ func (t *Tracklist) GetTracks() []*mediaprovider.Track {
|
|||||||
return t.tracks
|
return t.tracks
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append more tracks to the tracklist. Thread-safe.
|
// Append more tracks to the tracklist. Does not issue Refresh call. Thread-safe.
|
||||||
func (t *Tracklist) AppendTracks(trs []*mediaprovider.Track) {
|
func (t *Tracklist) AppendTracks(trs []*mediaprovider.Track) {
|
||||||
t.tracksMutex.Lock()
|
t.tracksMutex.Lock()
|
||||||
defer t.tracksMutex.Unlock()
|
defer t.tracksMutex.Unlock()
|
||||||
@@ -367,6 +300,81 @@ func (t *Tracklist) Refresh() {
|
|||||||
t.BaseWidget.Refresh()
|
t.BaseWidget.Refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Tracklist) stringSort(fieldFn func(*mediaprovider.Track) string) {
|
||||||
|
new := make([]*mediaprovider.Track, len(t.tracksOrigOrder))
|
||||||
|
copy(new, t.tracksOrigOrder)
|
||||||
|
sort.SliceStable(new, func(i, j int) bool {
|
||||||
|
cmp := strings.Compare(fieldFn(new[i]), fieldFn(new[j]))
|
||||||
|
if t.sorting.SortOrder == SortDescending {
|
||||||
|
return cmp > 0
|
||||||
|
}
|
||||||
|
return cmp < 0
|
||||||
|
})
|
||||||
|
t.tracks = new
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tracklist) intSort(fieldFn func(*mediaprovider.Track) int64) {
|
||||||
|
new := make([]*mediaprovider.Track, len(t.tracksOrigOrder))
|
||||||
|
copy(new, t.tracksOrigOrder)
|
||||||
|
sort.SliceStable(new, func(i, j int) bool {
|
||||||
|
if t.sorting.SortOrder == SortDescending {
|
||||||
|
return fieldFn(new[i]) > fieldFn(new[j])
|
||||||
|
}
|
||||||
|
return fieldFn(new[i]) < fieldFn(new[j])
|
||||||
|
})
|
||||||
|
t.tracks = new
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tracklist) doSortTracks() {
|
||||||
|
if t.sorting.SortOrder == SortNone {
|
||||||
|
t.tracks = t.tracksOrigOrder
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch t.sorting.ColumnName {
|
||||||
|
case ColumnNum:
|
||||||
|
if t.sorting.SortOrder == SortDescending {
|
||||||
|
t.tracks = sharedutil.Reversed(t.tracksOrigOrder)
|
||||||
|
} else {
|
||||||
|
t.tracks = t.tracksOrigOrder
|
||||||
|
}
|
||||||
|
case ColumnTitle:
|
||||||
|
t.stringSort(func(tr *mediaprovider.Track) string { return tr.Name })
|
||||||
|
case ColumnArtist:
|
||||||
|
t.stringSort(func(tr *mediaprovider.Track) string { return tr.ArtistNames[0] })
|
||||||
|
case ColumnAlbum:
|
||||||
|
t.stringSort(func(tr *mediaprovider.Track) string { return tr.Album })
|
||||||
|
case ColumnPath:
|
||||||
|
t.stringSort(func(tr *mediaprovider.Track) string { return tr.FilePath })
|
||||||
|
case ColumnRating:
|
||||||
|
t.intSort(func(tr *mediaprovider.Track) int64 { return int64(tr.Rating) })
|
||||||
|
case ColumnTime:
|
||||||
|
t.intSort(func(tr *mediaprovider.Track) int64 { return int64(tr.Duration) })
|
||||||
|
case ColumnYear:
|
||||||
|
t.intSort(func(tr *mediaprovider.Track) int64 { return int64(tr.Year) })
|
||||||
|
case ColumnSize:
|
||||||
|
t.intSort(func(tr *mediaprovider.Track) int64 { return tr.Size })
|
||||||
|
case ColumnPlays:
|
||||||
|
t.intSort(func(tr *mediaprovider.Track) int64 { return int64(tr.PlayCount) })
|
||||||
|
case ColumnBitrate:
|
||||||
|
t.intSort(func(tr *mediaprovider.Track) int64 { return int64(tr.BitRate) })
|
||||||
|
case ColumnFavorite:
|
||||||
|
t.intSort(func(tr *mediaprovider.Track) int64 {
|
||||||
|
if tr.Favorite {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tracklist) onSorted(sort ListHeaderSort) {
|
||||||
|
t.sorting = TracklistSort{ColumnName: colName(sort.ColNumber), SortOrder: sort.Type}
|
||||||
|
t.tracksMutex.Lock()
|
||||||
|
t.doSortTracks()
|
||||||
|
t.tracksMutex.Unlock()
|
||||||
|
t.Refresh()
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Tracklist) onPlayTrackAt(idx int) {
|
func (t *Tracklist) onPlayTrackAt(idx int) {
|
||||||
if t.OnPlayTrackAt != nil {
|
if t.OnPlayTrackAt != nil {
|
||||||
t.OnPlayTrackAt(idx)
|
t.OnPlayTrackAt(idx)
|
||||||
|
|||||||
Reference in New Issue
Block a user