refactor tracklist to use MediaItem, even if it only contains tracks

This commit is contained in:
Drew Weymouth
2024-06-01 10:15:18 -07:00
parent c6c1341f8f
commit 82d4546096
8 changed files with 170 additions and 93 deletions
+4 -4
View File
@@ -248,7 +248,7 @@ func (p *playbackEngine) StopAndClearPlayQueue() {
} }
func (p *playbackEngine) GetPlayQueue() []mediaprovider.MediaItem { func (p *playbackEngine) GetPlayQueue() []mediaprovider.MediaItem {
return p.deepCopyTrackSlice(p.playQueue) return p.deepCopyMediaItemSlice(p.playQueue)
} }
// Any time the user changes the favorite status of a track elsewhere in the app, // Any time the user changes the favorite status of a track elsewhere in the app,
@@ -274,8 +274,8 @@ func (p *playbackEngine) OnTrackRatingChanged(id string, rating int) {
// Replaces the play queue with the given set of tracks. // Replaces the play queue with the given set of tracks.
// Does not stop playback if the currently playing track is in the new queue, // Does not stop playback if the currently playing track is in the new queue,
// but updates the now playing index to point to the first instance of the track in the new queue. // but updates the now playing index to point to the first instance of the track in the new queue.
func (p *playbackEngine) UpdatePlayQueue(tracks []*mediaprovider.Track) error { func (p *playbackEngine) UpdatePlayQueue(items []mediaprovider.MediaItem) error {
newQueue := p.copyTrackSliceToMediaItemSlice(tracks) newQueue := p.deepCopyMediaItemSlice(items)
newNowPlayingIdx := -1 newNowPlayingIdx := -1
if p.nowPlayingIdx >= 0 { if p.nowPlayingIdx >= 0 {
nowPlayingID := p.playQueue[p.nowPlayingIdx].Metadata().ID nowPlayingID := p.playQueue[p.nowPlayingIdx].Metadata().ID
@@ -548,7 +548,7 @@ func (p *playbackEngine) sendNowPlayingScrobble() {
// creates a deep copy of the track info so that we can maintain our own state // creates a deep copy of the track info so that we can maintain our own state
// (play count increases, favorite, and rating) without messing up other views' track models // (play count increases, favorite, and rating) without messing up other views' track models
func (p *playbackEngine) deepCopyTrackSlice(tracks []mediaprovider.MediaItem) []mediaprovider.MediaItem { func (p *playbackEngine) deepCopyMediaItemSlice(tracks []mediaprovider.MediaItem) []mediaprovider.MediaItem {
newTracks := make([]mediaprovider.MediaItem, len(tracks)) newTracks := make([]mediaprovider.MediaItem, len(tracks))
for i, tr := range tracks { for i, tr := range tracks {
newTracks[i] = tr.Copy() newTracks[i] = tr.Copy()
+2 -2
View File
@@ -126,8 +126,8 @@ func (p *PlaybackManager) LoadTracks(tracks []*mediaprovider.Track, insertQueueM
// Replaces the play queue with the given set of tracks. // Replaces the play queue with the given set of tracks.
// Does not stop playback if the currently playing track is in the new queue, // Does not stop playback if the currently playing track is in the new queue,
// but updates the now playing index to point to the first instance of the track in the new queue. // but updates the now playing index to point to the first instance of the track in the new queue.
func (p *PlaybackManager) UpdatePlayQueue(tracks []*mediaprovider.Track) error { func (p *PlaybackManager) UpdatePlayQueue(items []mediaprovider.MediaItem) error {
return p.engine.UpdatePlayQueue(tracks) return p.engine.UpdatePlayQueue(items)
} }
func (p *PlaybackManager) PlayAlbum(albumID string, firstTrack int, shuffle bool) error { func (p *PlaybackManager) PlayAlbum(albumID string, firstTrack int, shuffle bool) error {
+57
View File
@@ -112,6 +112,9 @@ const (
MoveDown MoveDown
) )
// TODO: it's a shame the below function is just duplicated for a slice of mediaprovider.MediaItem
// Find out if there's a better way with refactoring.
// Reorder tracks and return a new track slice. // Reorder tracks and return a new track slice.
// idxToMove must contain only valid indexes into tracks, and no repeats // idxToMove must contain only valid indexes into tracks, and no repeats
func ReorderTracks(tracks []*mediaprovider.Track, idxToMove []int, op TrackReorderOp) []*mediaprovider.Track { func ReorderTracks(tracks []*mediaprovider.Track, idxToMove []int, op TrackReorderOp) []*mediaprovider.Track {
@@ -166,6 +169,60 @@ func ReorderTracks(tracks []*mediaprovider.Track, idxToMove []int, op TrackReord
return newTracks return newTracks
} }
// Reorder media items and return a new item slice.
// idxToMove must contain only valid indexes into items, and no repeats
func ReorderMediaItems(items []mediaprovider.MediaItem, idxToMove []int, op TrackReorderOp) []mediaprovider.MediaItem {
newTracks := make([]mediaprovider.MediaItem, len(items))
switch op {
case MoveToTop:
topIdx := 0
botIdx := len(idxToMove)
idxToMoveSet := ToSet(idxToMove)
for i, t := range items {
if _, ok := idxToMoveSet[i]; ok {
newTracks[topIdx] = t
topIdx++
} else {
newTracks[botIdx] = t
botIdx++
}
}
case MoveToBottom:
topIdx := 0
botIdx := len(items) - len(idxToMove)
idxToMoveSet := ToSet(idxToMove)
for i, t := range items {
if _, ok := idxToMoveSet[i]; ok {
newTracks[botIdx] = t
botIdx++
} else {
newTracks[topIdx] = t
topIdx++
}
}
case MoveUp:
first := firstIdxCanMoveUp(idxToMove)
copy(newTracks, items)
for _, i := range idxToMove {
if i < first {
continue
}
newTracks[i-1], newTracks[i] = newTracks[i], newTracks[i-1]
}
case MoveDown:
last := lastIdxCanMoveDown(idxToMove, len(items))
copy(newTracks, items)
for i := len(idxToMove) - 1; i >= 0; i-- {
idx := idxToMove[i]
if idx > last {
continue
}
newTracks[idx+1], newTracks[idx] = newTracks[idx], newTracks[idx+1]
}
}
return newTracks
}
func firstIdxCanMoveUp(idxs []int) int { func firstIdxCanMoveUp(idxs []int) int {
prevIdx := -1 prevIdx := -1
slices.Sort(idxs) slices.Sort(idxs)
+7 -8
View File
@@ -43,7 +43,7 @@ type NowPlayingPage struct {
curRelatedID string // id of track currrently used to populate related list curRelatedID string // id of track currrently used to populate related list
totalTime float64 totalTime float64
lastPlayPos float64 lastPlayPos float64
queue []*mediaprovider.Track queue []mediaprovider.MediaItem
related []*mediaprovider.Track related []*mediaprovider.Track
lyricLock sync.Mutex lyricLock sync.Mutex
@@ -122,7 +122,7 @@ func NewNowPlayingPage(
a.queueList = widgets.NewPlayQueueList(a.im) a.queueList = widgets.NewPlayQueueList(a.im)
a.relatedList = widgets.NewPlayQueueList(a.im) a.relatedList = widgets.NewPlayQueueList(a.im)
a.queueList.OnReorderTracks = a.doSetNewTrackOrder a.queueList.OnReorderItems = a.doSetNewTrackOrder
a.queueList.OnDownload = contr.ShowDownloadDialog a.queueList.OnDownload = contr.ShowDownloadDialog
a.queueList.OnShare = func(tracks []*mediaprovider.Track) { a.queueList.OnShare = func(tracks []*mediaprovider.Track) {
if len(tracks) > 0 { if len(tracks) > 0 {
@@ -401,12 +401,11 @@ func (a *NowPlayingPage) Reload() {
a.relatedList.DisableRating = !a.canRate a.relatedList.DisableRating = !a.canRate
a.relatedList.DisableSharing = !a.canShare a.relatedList.DisableSharing = !a.canShare
// TODO a.queue = a.pm.GetPlayQueue()
//a.queue = a.pm.GetPlayQueue() a.queueList.SetItems(a.queue)
a.queueList.SetTracks(a.queue)
a.totalTime = 0.0 a.totalTime = 0.0
for _, tr := range a.queue { for _, tr := range a.queue {
a.totalTime += float64(tr.Duration) a.totalTime += float64(tr.Metadata().Duration)
} }
a.formatStatusLine() a.formatStatusLine()
} }
@@ -459,11 +458,11 @@ func (a *NowPlayingPage) doSetNewTrackOrder(trackIDs []string, op sharedutil.Tra
trackIDSet := sharedutil.ToSet(trackIDs) trackIDSet := sharedutil.ToSet(trackIDs)
idxs := make([]int, 0, len(trackIDs)) idxs := make([]int, 0, len(trackIDs))
for i, tr := range a.queue { for i, tr := range a.queue {
if _, ok := trackIDSet[tr.ID]; ok { if _, ok := trackIDSet[tr.Metadata().ID]; ok {
idxs = append(idxs, i) idxs = append(idxs, i)
} }
} }
newTracks := sharedutil.ReorderTracks(a.queue, idxs, op) newTracks := sharedutil.ReorderMediaItems(a.queue, idxs, op)
a.pm.UpdatePlayQueue(newTracks) a.pm.UpdatePlayQueue(newTracks)
} }
+32 -26
View File
@@ -8,76 +8,82 @@ import (
) )
type TrackListModel struct { type TrackListModel struct {
Track *mediaprovider.Track Item mediaprovider.MediaItem
Selected bool Selected bool
} }
// Returns the item as a *mediaprovider.Track, or panics if not a Track
// Use for tracklists that can only contain tracks (ie not PlayQueueList)
func (t TrackListModel) Track() *mediaprovider.Track {
return t.Item.(*mediaprovider.Track)
}
func ToTrackListModels(trs []*mediaprovider.Track) []*TrackListModel { func ToTrackListModels(trs []*mediaprovider.Track) []*TrackListModel {
return sharedutil.MapSlice(trs, func(tr *mediaprovider.Track) *TrackListModel { return sharedutil.MapSlice(trs, func(tr *mediaprovider.Track) *TrackListModel {
return &TrackListModel{Track: tr, Selected: false} return &TrackListModel{Item: tr, Selected: false}
}) })
} }
func SelectedTracks(tracks []*TrackListModel) []*mediaprovider.Track { func SelectedTracks(items []*TrackListModel) []*mediaprovider.Track {
return sharedutil.FilterMapSlice(tracks, func(tm *TrackListModel) (*mediaprovider.Track, bool) { return sharedutil.FilterMapSlice(items, func(tm *TrackListModel) (*mediaprovider.Track, bool) {
return tm.Track, tm.Selected return tm.Track(), tm.Selected
}) })
} }
func SelectedTrackIDs(tracks []*TrackListModel) []string { func SelectedItemIDs(items []*TrackListModel) []string {
return sharedutil.FilterMapSlice(tracks, func(tm *TrackListModel) (string, bool) { return sharedutil.FilterMapSlice(items, func(tm *TrackListModel) (string, bool) {
return tm.Track.ID, tm.Selected return tm.Item.Metadata().ID, tm.Selected
}) })
} }
func SelectTrack(tracks []*TrackListModel, idx int) { func SelectItem(items []*TrackListModel, idx int) {
if tracks[idx].Selected { if items[idx].Selected {
return return
} }
UnselectAllTracks(tracks) UnselectAllItems(items)
tracks[idx].Selected = true items[idx].Selected = true
} }
func SelectAllTracks(tracks []*TrackListModel) { func SelectAllItems(items []*TrackListModel) {
for _, tm := range tracks { for _, tm := range items {
tm.Selected = true tm.Selected = true
} }
} }
func UnselectAllTracks(tracks []*TrackListModel) { func UnselectAllItems(items []*TrackListModel) {
for _, tm := range tracks { for _, tm := range items {
tm.Selected = false tm.Selected = false
} }
} }
func SelectTrackRange(tracks []*TrackListModel, idx int) { func SelectItemRange(items []*TrackListModel, idx int) {
if tracks[idx].Selected { if items[idx].Selected {
return return
} }
lastSelected := -1 lastSelected := -1
for i := len(tracks) - 1; i >= 0; i-- { for i := len(items) - 1; i >= 0; i-- {
if tracks[i].Selected { if items[i].Selected {
lastSelected = i lastSelected = i
break break
} }
} }
if lastSelected < 0 { if lastSelected < 0 {
tracks[idx].Selected = true items[idx].Selected = true
return return
} }
from := min(idx, lastSelected) from := min(idx, lastSelected)
to := max(idx, lastSelected) to := max(idx, lastSelected)
for i := from; i <= to; i++ { for i := from; i <= to; i++ {
tracks[i].Selected = true items[i].Selected = true
} }
} }
func FindTrackByID(tracks []*TrackListModel, id string) (*mediaprovider.Track, int) { func FindTrackByID(items []*TrackListModel, id string) (*mediaprovider.Track, int) {
idx := slices.IndexFunc(tracks, func(tr *TrackListModel) bool { idx := slices.IndexFunc(items, func(tr *TrackListModel) bool {
return tr.Track.ID == id return tr.Item.Metadata().ID == id
}) })
if idx >= 0 { if idx >= 0 {
return tracks[idx].Track, idx return items[idx].Track(), idx
} }
return nil, -1 return nil, -1
} }
+42 -27
View File
@@ -23,6 +23,11 @@ import (
const playQueueListThumbnailSize = 52 const playQueueListThumbnailSize = 52
type PlayQueueListModel struct {
Item mediaprovider.MediaItem
Selected bool
}
type PlayQueueList struct { type PlayQueueList struct {
widget.BaseWidget widget.BaseWidget
@@ -33,12 +38,12 @@ type PlayQueueList struct {
OnAddToPlaylist func(trackIDs []string) OnAddToPlaylist func(trackIDs []string)
OnSetFavorite func(trackIDs []string, fav bool) OnSetFavorite func(trackIDs []string, fav bool)
OnSetRating func(trackIDs []string, rating int) OnSetRating func(trackIDs []string, rating int)
OnRemoveFromQueue func(trackIDs []string) OnRemoveFromQueue func(itemIDs []string)
OnDownload func(tracks []*mediaprovider.Track, downloadName string) OnDownload func(tracks []*mediaprovider.Track, downloadName string)
OnShare func(tracks []*mediaprovider.Track) OnShare func(tracks []*mediaprovider.Track)
OnShowArtistPage func(artistID string) OnShowArtistPage func(artistID string)
OnPlayTrackAt func(idx int) OnPlayTrackAt func(idx int)
OnReorderTracks func(trackIDs []string, op sharedutil.TrackReorderOp) OnReorderItems func(itemIDs []string, op sharedutil.TrackReorderOp)
list *FocusList list *FocusList
menu *widget.PopUpMenu menu *widget.PopUpMenu
@@ -49,7 +54,7 @@ type PlayQueueList struct {
colLayout *layouts.ColumnsLayout colLayout *layouts.ColumnsLayout
tracksMutex sync.RWMutex tracksMutex sync.RWMutex
tracks []*util.TrackListModel items []*util.TrackListModel
} }
func NewPlayQueueList(im *backend.ImageManager) *PlayQueueList { func NewPlayQueueList(im *backend.ImageManager) *PlayQueueList {
@@ -78,16 +83,16 @@ func NewPlayQueueList(im *backend.ImageManager) *PlayQueueList {
// we could have removed tracks from the list in between // we could have removed tracks from the list in between
// Fyne calling the length callback and this update callback // Fyne calling the length callback and this update callback
// so the itemID may be out of bounds. if so, do nothing. // so the itemID may be out of bounds. if so, do nothing.
if itemID >= len(p.tracks) { if itemID >= len(p.items) {
p.tracksMutex.RUnlock() p.tracksMutex.RUnlock()
return return
} }
model := p.tracks[itemID] model := p.items[itemID]
p.tracksMutex.RUnlock() p.tracksMutex.RUnlock()
tr := item.(*PlayQueueListRow) tr := item.(*PlayQueueListRow)
p.list.SetItemForID(itemID, tr) p.list.SetItemForID(itemID, tr)
if tr.trackID != model.Track.ID || tr.ListItemID != itemID { if tr.trackID != model.Item.Metadata().ID || tr.ListItemID != itemID {
tr.ListItemID = itemID tr.ListItemID = itemID
} }
tr.Update(model, itemID+1) tr.Update(model, itemID+1)
@@ -100,7 +105,17 @@ func NewPlayQueueList(im *backend.ImageManager) *PlayQueueList {
func (p *PlayQueueList) SetTracks(trs []*mediaprovider.Track) { func (p *PlayQueueList) SetTracks(trs []*mediaprovider.Track) {
p.tracksMutex.Lock() p.tracksMutex.Lock()
p.list.ClearItemForIDMap() p.list.ClearItemForIDMap()
p.tracks = util.ToTrackListModels(trs) p.items = util.ToTrackListModels(trs)
p.tracksMutex.Unlock()
p.Refresh()
}
func (p *PlayQueueList) SetItems(items []mediaprovider.MediaItem) {
p.tracksMutex.Lock()
p.list.ClearItemForIDMap()
p.items = sharedutil.MapSlice(items, func(item mediaprovider.MediaItem) *util.TrackListModel {
return &util.TrackListModel{Item: item}
})
p.tracksMutex.Unlock() p.tracksMutex.Unlock()
p.Refresh() p.Refresh()
} }
@@ -109,8 +124,8 @@ func (p *PlayQueueList) SetTracks(trs []*mediaprovider.Track) {
func (p *PlayQueueList) SetNowPlaying(trackID string) { func (p *PlayQueueList) SetNowPlaying(trackID string) {
prevNowPlaying := p.nowPlayingID prevNowPlaying := p.nowPlayingID
p.tracksMutex.RLock() p.tracksMutex.RLock()
trPrev, idxPrev := util.FindTrackByID(p.tracks, prevNowPlaying) trPrev, idxPrev := util.FindTrackByID(p.items, prevNowPlaying)
tr, idx := util.FindTrackByID(p.tracks, trackID) tr, idx := util.FindTrackByID(p.items, trackID)
p.tracksMutex.RUnlock() p.tracksMutex.RUnlock()
p.nowPlayingID = trackID p.nowPlayingID = trackID
if trPrev != nil { if trPrev != nil {
@@ -123,14 +138,14 @@ func (p *PlayQueueList) SetNowPlaying(trackID string) {
func (p *PlayQueueList) SelectAll() { func (p *PlayQueueList) SelectAll() {
p.tracksMutex.RLock() p.tracksMutex.RLock()
util.SelectAllTracks(p.tracks) util.SelectAllItems(p.items)
p.tracksMutex.RUnlock() p.tracksMutex.RUnlock()
p.list.Refresh() p.list.Refresh()
} }
func (p *PlayQueueList) UnselectAll() { func (p *PlayQueueList) UnselectAll() {
p.tracksMutex.RLock() p.tracksMutex.RLock()
util.UnselectAllTracks(p.tracks) util.UnselectAllItems(p.items)
p.tracksMutex.RUnlock() p.tracksMutex.RUnlock()
p.Refresh() p.Refresh()
} }
@@ -138,7 +153,7 @@ func (p *PlayQueueList) UnselectAll() {
func (p *PlayQueueList) lenTracks() int { func (p *PlayQueueList) lenTracks() int {
p.tracksMutex.RLock() p.tracksMutex.RLock()
defer p.tracksMutex.RUnlock() defer p.tracksMutex.RUnlock()
return len(p.tracks) return len(p.items)
} }
func (t *PlayQueueList) onArtistTapped(artistID string) { func (t *PlayQueueList) onArtistTapped(artistID string) {
@@ -172,19 +187,19 @@ func (p *PlayQueueList) onSelectTrack(idx int) {
func (p *PlayQueueList) selectTrack(idx int) { func (p *PlayQueueList) selectTrack(idx int) {
p.tracksMutex.RLock() p.tracksMutex.RLock()
defer p.tracksMutex.RUnlock() defer p.tracksMutex.RUnlock()
util.SelectTrack(p.tracks, idx) util.SelectItem(p.items, idx)
} }
func (p *PlayQueueList) selectAddOrRemove(idx int) { func (p *PlayQueueList) selectAddOrRemove(idx int) {
p.tracksMutex.RLock() p.tracksMutex.RLock()
defer p.tracksMutex.RUnlock() defer p.tracksMutex.RUnlock()
p.tracks[idx].Selected = !p.tracks[idx].Selected p.items[idx].Selected = !p.items[idx].Selected
} }
func (p *PlayQueueList) selectRange(idx int) { func (p *PlayQueueList) selectRange(idx int) {
p.tracksMutex.RLock() p.tracksMutex.RLock()
defer p.tracksMutex.RUnlock() defer p.tracksMutex.RUnlock()
util.SelectTrackRange(p.tracks, idx) util.SelectItemRange(p.items, idx)
} }
func (p *PlayQueueList) onShowContextMenu(e *fyne.PointEvent, trackIdx int) { func (p *PlayQueueList) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
@@ -233,8 +248,8 @@ func (p *PlayQueueList) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
}) })
remove.Icon = theme.ContentRemoveIcon() remove.Icon = theme.ContentRemoveIcon()
reorder := util.NewReorderTracksSubmenu(func(tro sharedutil.TrackReorderOp) { reorder := util.NewReorderTracksSubmenu(func(tro sharedutil.TrackReorderOp) {
if p.OnReorderTracks != nil { if p.OnReorderItems != nil {
p.OnReorderTracks(p.selectedTrackIDs(), tro) p.OnReorderItems(p.selectedTrackIDs(), tro)
} }
}) })
@@ -262,13 +277,13 @@ func (p *PlayQueueList) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
func (t *PlayQueueList) selectedTracks() []*mediaprovider.Track { func (t *PlayQueueList) selectedTracks() []*mediaprovider.Track {
t.tracksMutex.RLock() t.tracksMutex.RLock()
defer t.tracksMutex.RUnlock() defer t.tracksMutex.RUnlock()
return util.SelectedTracks(t.tracks) return util.SelectedTracks(t.items)
} }
func (t *PlayQueueList) selectedTrackIDs() []string { func (t *PlayQueueList) selectedTrackIDs() []string {
t.tracksMutex.RLock() t.tracksMutex.RLock()
defer t.tracksMutex.RUnlock() defer t.tracksMutex.RUnlock()
return util.SelectedTrackIDs(t.tracks) return util.SelectedItemIDs(t.items)
} }
func (p *PlayQueueList) CreateRenderer() fyne.WidgetRenderer { func (p *PlayQueueList) CreateRenderer() fyne.WidgetRenderer {
@@ -355,19 +370,19 @@ func (p *PlayQueueListRow) Update(tm *util.TrackListModel, rowNum int) {
// Update info that can change if this row is bound to // Update info that can change if this row is bound to
// a new track (*mediaprovider.Track) // a new track (*mediaprovider.Track)
tr := tm.Track meta := tm.Item.Metadata()
if tr.ID != p.trackID { if meta.ID != p.trackID {
p.imageLoader.Load(tm.Track.CoverArtID) p.imageLoader.Load(meta.CoverArtID)
p.EnsureUnfocused() p.EnsureUnfocused()
p.trackID = tr.ID p.trackID = meta.ID
p.title.Text = tr.Title p.title.Text = meta.Name
p.artist.BuildSegments(tr.ArtistNames, tr.ArtistIDs) p.artist.BuildSegments(meta.Artists, meta.ArtistIDs)
p.time.Text = util.SecondsToTimeString(float64(tr.Duration)) p.time.Text = util.SecondsToTimeString(float64(meta.Duration))
changed = true changed = true
} }
// Render whether track is playing or not // Render whether track is playing or not
if isPlaying := p.playQueueList.nowPlayingID == tr.ID; isPlaying != p.isPlaying { if isPlaying := p.playQueueList.nowPlayingID == meta.ID; isPlaying != p.isPlaying {
p.isPlaying = isPlaying p.isPlaying = isPlaying
p.title.TextStyle.Bold = isPlaying p.title.TextStyle.Bold = isPlaying
+21 -21
View File
@@ -171,7 +171,7 @@ func NewTracklist(tracks []*mediaprovider.Track, im *backend.ImageManager, useCo
tr := item.(TracklistRow) tr := item.(TracklistRow)
t.list.SetItemForID(itemID, tr) t.list.SetItemForID(itemID, tr)
if tr.TrackID() != model.Track.ID || tr.ItemID() != itemID { if tr.TrackID() != model.Item.Metadata().ID || tr.ItemID() != itemID {
tr.SetItemID(itemID) tr.SetItemID(itemID)
} }
i := -1 // signal that we want to display the actual track num. i := -1 // signal that we want to display the actual track num.
@@ -206,7 +206,7 @@ func (t *Tracklist) TrackAt(idx int) *mediaprovider.Track {
log.Println("error: Tracklist.TrackAt: index out of range") log.Println("error: Tracklist.TrackAt: index out of range")
return nil return nil
} }
return t.tracks[idx].Track return t.tracks[idx].Track()
} }
func (t *Tracklist) SetVisibleColumns(cols []string) { func (t *Tracklist) SetVisibleColumns(cols []string) {
@@ -324,7 +324,7 @@ func (t *Tracklist) GetTracks() []*mediaprovider.Track {
t.tracksMutex.RLock() t.tracksMutex.RLock()
defer t.tracksMutex.RUnlock() defer t.tracksMutex.RUnlock()
return sharedutil.MapSlice(t.tracks, func(tm *util.TrackListModel) *mediaprovider.Track { return sharedutil.MapSlice(t.tracks, func(tm *util.TrackListModel) *mediaprovider.Track {
return tm.Track return tm.Track()
}) })
} }
@@ -338,7 +338,7 @@ func (t *Tracklist) AppendTracks(trs []*mediaprovider.Track) {
func (t *Tracklist) SelectAll() { func (t *Tracklist) SelectAll() {
t.tracksMutex.RLock() t.tracksMutex.RLock()
util.SelectAllTracks(t.tracks) util.SelectAllItems(t.tracks)
t.tracksMutex.RUnlock() t.tracksMutex.RUnlock()
t.list.Refresh() t.list.Refresh()
} }
@@ -350,7 +350,7 @@ func (t *Tracklist) UnselectAll() {
func (t *Tracklist) unselectAll() { func (t *Tracklist) unselectAll() {
t.tracksMutex.RLock() t.tracksMutex.RLock()
util.UnselectAllTracks(t.tracks) util.UnselectAllItems(t.tracks)
t.tracksMutex.RUnlock() t.tracksMutex.RUnlock()
} }
@@ -358,7 +358,7 @@ func (t *Tracklist) SelectAndScrollToTrack(trackID string) {
t.tracksMutex.RLock() t.tracksMutex.RLock()
idx := -1 idx := -1
for i, tr := range t.tracks { for i, tr := range t.tracks {
if tr.Track.ID == trackID { if tr.Item.Metadata().ID == trackID {
idx = i idx = i
tr.Selected = true tr.Selected = true
} else { } else {
@@ -422,30 +422,30 @@ func (t *Tracklist) doSortTracks() {
t.tracks = t.tracksOrigOrder t.tracks = t.tracksOrigOrder
} }
case ColumnTitle: case ColumnTitle:
t.stringSort(func(tr *util.TrackListModel) string { return tr.Track.Title }) t.stringSort(func(tr *util.TrackListModel) string { return tr.Track().Title })
case ColumnArtist: case ColumnArtist:
t.stringSort(func(tr *util.TrackListModel) string { return strings.Join(tr.Track.ArtistNames, ", ") }) t.stringSort(func(tr *util.TrackListModel) string { return strings.Join(tr.Track().ArtistNames, ", ") })
case ColumnAlbum: case ColumnAlbum:
t.stringSort(func(tr *util.TrackListModel) string { return tr.Track.Album }) t.stringSort(func(tr *util.TrackListModel) string { return tr.Track().Album })
case ColumnPath: case ColumnPath:
t.stringSort(func(tr *util.TrackListModel) string { return tr.Track.FilePath }) t.stringSort(func(tr *util.TrackListModel) string { return tr.Track().FilePath })
case ColumnRating: case ColumnRating:
t.intSort(func(tr *util.TrackListModel) int64 { return int64(tr.Track.Rating) }) t.intSort(func(tr *util.TrackListModel) int64 { return int64(tr.Track().Rating) })
case ColumnTime: case ColumnTime:
t.intSort(func(tr *util.TrackListModel) int64 { return int64(tr.Track.Duration) }) t.intSort(func(tr *util.TrackListModel) int64 { return int64(tr.Track().Duration) })
case ColumnYear: case ColumnYear:
t.intSort(func(tr *util.TrackListModel) int64 { return int64(tr.Track.Year) }) t.intSort(func(tr *util.TrackListModel) int64 { return int64(tr.Track().Year) })
case ColumnSize: case ColumnSize:
t.intSort(func(tr *util.TrackListModel) int64 { return tr.Track.Size }) t.intSort(func(tr *util.TrackListModel) int64 { return tr.Track().Size })
case ColumnPlays: case ColumnPlays:
t.intSort(func(tr *util.TrackListModel) int64 { return int64(tr.Track.PlayCount) }) t.intSort(func(tr *util.TrackListModel) int64 { return int64(tr.Track().PlayCount) })
case ColumnComment: case ColumnComment:
t.stringSort(func(tr *util.TrackListModel) string { return tr.Track.Comment }) t.stringSort(func(tr *util.TrackListModel) string { return tr.Track().Comment })
case ColumnBitrate: case ColumnBitrate:
t.intSort(func(tr *util.TrackListModel) int64 { return int64(tr.Track.BitRate) }) t.intSort(func(tr *util.TrackListModel) int64 { return int64(tr.Track().BitRate) })
case ColumnFavorite: case ColumnFavorite:
t.intSort(func(tr *util.TrackListModel) int64 { t.intSort(func(tr *util.TrackListModel) int64 {
if tr.Track.Favorite { if tr.Track().Favorite {
return 1 return 1
} }
return 0 return 0
@@ -492,13 +492,13 @@ func (t *Tracklist) selectAddOrRemove(idx int) {
func (t *Tracklist) selectTrack(idx int) { func (t *Tracklist) selectTrack(idx int) {
t.tracksMutex.RLock() t.tracksMutex.RLock()
defer t.tracksMutex.RUnlock() defer t.tracksMutex.RUnlock()
util.SelectTrack(t.tracks, idx) util.SelectItem(t.tracks, idx)
} }
func (t *Tracklist) selectRange(idx int) { func (t *Tracklist) selectRange(idx int) {
t.tracksMutex.RLock() t.tracksMutex.RLock()
defer t.tracksMutex.RUnlock() defer t.tracksMutex.RUnlock()
util.SelectTrackRange(t.tracks, idx) util.SelectItemRange(t.tracks, idx)
} }
func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) { func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
@@ -663,7 +663,7 @@ func (t *Tracklist) selectedTracks() []*mediaprovider.Track {
func (t *Tracklist) SelectedTrackIDs() []string { func (t *Tracklist) SelectedTrackIDs() []string {
t.tracksMutex.RLock() t.tracksMutex.RLock()
defer t.tracksMutex.RUnlock() defer t.tracksMutex.RUnlock()
return util.SelectedTrackIDs(t.tracks) return util.SelectedItemIDs(t.tracks)
} }
func (t *Tracklist) lenTracks() int { func (t *Tracklist) lenTracks() int {
+5 -5
View File
@@ -175,8 +175,8 @@ func NewExpandedTracklistRow(tracklist *Tracklist, im *backend.ImageManager, pla
} }
func (t *ExpandedTracklistRow) Update(tm *util.TrackListModel, rowNum int) { func (t *ExpandedTracklistRow) Update(tm *util.TrackListModel, rowNum int) {
if t.trackID != tm.Track.ID { if t.trackID != tm.Track().ID {
t.imageLoader.Load(tm.Track.CoverArtID) t.imageLoader.Load(tm.Track().CoverArtID)
} }
t.tracklistRowBase.Update(tm, rowNum) t.tracklistRowBase.Update(tm, rowNum)
} }
@@ -256,10 +256,10 @@ func (t *tracklistRowBase) Update(tm *util.TrackListModel, rowNum int) {
// Update info that can change if this row is bound to // Update info that can change if this row is bound to
// a new track (*mediaprovider.Track) // a new track (*mediaprovider.Track)
tr := tm.Track tr := tm.Track()
if tr.ID != t.trackID { if id := tr.ID; id != t.trackID {
t.EnsureUnfocused() t.EnsureUnfocused()
t.trackID = tr.ID t.trackID = id
t.name.Segments[0].(*widget.TextSegment).Text = tr.Title t.name.Segments[0].(*widget.TextSegment).Text = tr.Title
t.artist.BuildSegments(tr.ArtistNames, tr.ArtistIDs) t.artist.BuildSegments(tr.ArtistNames, tr.ArtistIDs)