refactor tracklist to use MediaItem, even if it only contains tracks
This commit is contained in:
@@ -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()
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user