diff --git a/ui/albumpage.go b/ui/albumpage.go index 4c65ded..a01cb23 100644 --- a/ui/albumpage.go +++ b/ui/albumpage.go @@ -11,7 +11,6 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" "github.com/dweymouth/go-subsonic" @@ -20,13 +19,14 @@ import ( type AlbumPage struct { widget.BaseWidget - albumID string - im *backend.ImageManager - lm *backend.LibraryManager - nav func(Route) - header *AlbumPageHeader - tracklist *widgets.Tracklist - container *fyne.Container + albumID string + im *backend.ImageManager + lm *backend.LibraryManager + nav func(Route) + header *AlbumPageHeader + tracklist *widgets.Tracklist + nowPlayingID string + container *fyne.Container OnPlayAlbum func(string, int) } @@ -35,9 +35,11 @@ func NewAlbumPage(albumID string, lm *backend.LibraryManager, im *backend.ImageM a := &AlbumPage{albumID: albumID, lm: lm, im: im, nav: nav} a.ExtendBaseWidget(a) a.header = NewAlbumPageHeader(a) + a.tracklist = widgets.NewTracklist(nil) + a.tracklist.OnPlayTrackAt = a.onPlayTrackAt a.container = container.NewBorder( container.New(&layouts.MaxPadLayout{PadLeft: 15, PadRight: 15, PadTop: 15, PadBottom: 10}, a.header), - nil, nil, nil, layout.NewSpacer()) + nil, nil, nil, container.New(&layouts.MaxPadLayout{PadLeft: 15, PadRight: 15, PadBottom: 15}, a.tracklist)) a.loadAsync() return a } @@ -54,6 +56,15 @@ func (a *AlbumPage) Route() Route { return AlbumRoute(a.albumID) } +func (a *AlbumPage) OnSongChange(song *subsonic.Child) { + if song == nil { + a.nowPlayingID = "" + } else { + a.nowPlayingID = song.ID + } + a.tracklist.SetNowPlaying(a.nowPlayingID) +} + func (a *AlbumPage) onPlayTrackAt(tracknum int) { if a.OnPlayAlbum != nil { a.OnPlayAlbum(a.albumID, tracknum) @@ -68,10 +79,8 @@ func (a *AlbumPage) loadAsync() { return } a.header.Update(album, a.im) - tl := widgets.NewTracklist(album.Song) - tl.OnPlayTrackAt = a.onPlayTrackAt - a.container.Objects[0] = container.New(&layouts.MaxPadLayout{PadLeft: 15, PadRight: 15, PadBottom: 15}, tl) - a.container.Refresh() + a.tracklist.Tracks = album.Song + a.tracklist.SetNowPlaying(a.nowPlayingID) }() } diff --git a/ui/browsingpane.go b/ui/browsingpane.go index 09fe727..d97a109 100644 --- a/ui/browsingpane.go +++ b/ui/browsingpane.go @@ -13,6 +13,7 @@ import ( "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" + "github.com/dweymouth/go-subsonic" ) type Page interface { @@ -29,6 +30,10 @@ type CanPlayAlbum interface { SetPlayAlbumCallback(func(albumID string, startingTrack int)) } +type CanShowNowPlaying interface { + OnSongChange(song *subsonic.Child) +} + type BrowsingPane struct { widget.BaseWidget @@ -57,6 +62,7 @@ func NewBrowsingPane(app *backend.App) *BrowsingPane { b.searchBar.OnTextChanged = b.onSearchTextChanged b.back = widget.NewButtonWithIcon("", theme.NavigateBackIcon(), b.GoBack) b.forward = widget.NewButtonWithIcon("", theme.NavigateNextIcon(), b.GoForward) + b.app.PlaybackManager.OnSongChange(b.onSongChange) b.pageContainer = container.NewMax( canvas.NewRectangle(color.RGBA{R: 24, G: 24, B: 24, A: 255}), layout.NewSpacer()) @@ -82,6 +88,9 @@ func (b *BrowsingPane) doSetPage(p Page) bool { _ = b.app.PlaybackManager.PlayAlbum(albumID, firstTrack) }) } + if np, ok := p.(CanShowNowPlaying); ok { + np.OnSongChange(b.app.PlaybackManager.NowPlaying()) + } _, s := p.(Searchable) b.searchBar.Hidden = !s b.pageContainer.Objects[1] = p @@ -89,6 +98,15 @@ func (b *BrowsingPane) doSetPage(p Page) bool { return true } +func (b *BrowsingPane) onSongChange(song *subsonic.Child) { + if b.curPage == nil { + return + } + if p, ok := b.curPage.(CanShowNowPlaying); ok { + p.OnSongChange(song) + } +} + func (b *BrowsingPane) addPageToHistory(p Page) { b.history = b.history[:b.historyIdx] b.history = append(b.history, p) diff --git a/ui/widgets/tracklist.go b/ui/widgets/tracklist.go index e59d90d..fba2eff 100644 --- a/ui/widgets/tracklist.go +++ b/ui/widgets/tracklist.go @@ -14,8 +14,9 @@ import ( type TrackRow struct { widget.BaseWidget - trackID string - prevTrackID string + trackID string + prevTrackID string + prevIsPlaying bool num *widget.RichText name *widget.RichText @@ -39,22 +40,28 @@ func NewTrackRow() *TrackRow { t.artist.Wrapping = fyne.TextTruncate t.dur = widget.NewRichTextWithText("") - t.container = container.New(layouts.NewColumnsLayout([]float32{30, -1, -1, 55}), + t.container = container.New(layouts.NewColumnsLayout([]float32{35, -1, -1, 55}), t.num, t.name, t.artist, t.dur) return t } -func (t *TrackRow) Update(tr *subsonic.Child) { - if tr.ID == t.prevTrackID { +func (t *TrackRow) Update(tr *subsonic.Child, isPlaying bool) { + if tr.ID == t.prevTrackID && isPlaying == t.prevIsPlaying { return } t.prevTrackID = t.trackID + t.prevIsPlaying = isPlaying t.trackID = tr.ID t.num.Segments[0].(*widget.TextSegment).Text = strconv.Itoa(tr.Track) t.name.Segments[0].(*widget.TextSegment).Text = tr.Title t.artist.Segments[0].(*widget.TextSegment).Text = tr.Artist t.dur.Segments[0].(*widget.TextSegment).Text = util.SecondsToTimeString(float64(tr.Duration)) + t.num.Segments[0].(*widget.TextSegment).Style.TextStyle = fyne.TextStyle{Bold: isPlaying} + t.name.Segments[0].(*widget.TextSegment).Style.TextStyle = fyne.TextStyle{Bold: isPlaying, Italic: isPlaying} + t.artist.Segments[0].(*widget.TextSegment).Style.TextStyle = fyne.TextStyle{Bold: isPlaying, Italic: isPlaying} + t.dur.Segments[0].(*widget.TextSegment).Style.TextStyle = fyne.TextStyle{Bold: isPlaying} + t.Refresh() } @@ -71,26 +78,38 @@ func (t *TrackRow) DoubleTapped(*fyne.PointEvent) { type Tracklist struct { widget.BaseWidget - tracks []*subsonic.Child - list *widget.List - + Tracks []*subsonic.Child OnPlayTrackAt func(int) + + nowPlayingIdx int + list *widget.List } func NewTracklist(tracks []*subsonic.Child) *Tracklist { - t := &Tracklist{tracks: tracks} + t := &Tracklist{Tracks: tracks, nowPlayingIdx: -1} t.ExtendBaseWidget(t) t.list = widget.NewList( - func() int { return len(t.tracks) }, + func() int { return len(t.Tracks) }, func() fyne.CanvasObject { return NewTrackRow() }, func(itemID widget.ListItemID, item fyne.CanvasObject) { tr := item.(*TrackRow) tr.OnDoubleTapped = func() { t.onPlayTrackAt(itemID) } - tr.Update(t.tracks[itemID]) + tr.Update(t.Tracks[itemID], itemID == t.nowPlayingIdx) }) return t } +func (t *Tracklist) SetNowPlaying(trackID string) { + t.nowPlayingIdx = -1 + for i, tr := range t.Tracks { + if tr.ID == trackID { + t.nowPlayingIdx = i + break + } + } + t.list.Refresh() +} + func (t *Tracklist) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(t.list) }