Merge pull request #424 from dweymouth/feature/track-info-dialog

Add track info dialog
This commit is contained in:
Drew Weymouth
2024-07-18 17:45:39 -07:00
committed by GitHub
9 changed files with 249 additions and 10 deletions
+33
View File
@@ -146,6 +146,7 @@ func (m *Controller) connectTracklistActionsWithReplayGainMode(tracklist *widget
tracklist.OnShare = func(trackID string) {
go m.ShowShareDialog(trackID)
}
tracklist.OnShowTrackInfo = m.ShowTrackInfoDialog
tracklist.OnPlaySongRadio = func(track *mediaprovider.Track) {
go func() {
tracks, err := m.GetSongRadioTracks(track)
@@ -858,6 +859,38 @@ func (c *Controller) ShowAlbumInfoDialog(albumID, albumName string, albumCover i
}()
}
func (c *Controller) ShowTrackInfoDialog(track *mediaprovider.Track) {
info := dialogs.NewTrackInfoDialog(track)
pop := widget.NewModalPopUp(info, c.MainWindow.Canvas())
info.OnDismiss = func() {
pop.Hide()
c.doModalClosed()
}
info.OnNavigateToAlbum = func(albumID string) {
info.OnDismiss()
c.NavigateTo(AlbumRoute(albumID))
}
info.OnNavigateToArtist = func(artistID string) {
info.OnDismiss()
c.NavigateTo(ArtistRoute(artistID))
}
info.OnNavigateToGenre = func(genre string) {
info.OnDismiss()
c.NavigateTo(GenreRoute(genre))
}
info.OnCopyFilePath = func() {
c.MainWindow.Clipboard().SetContent(track.FilePath)
}
c.ClosePopUpOnEscape(pop)
winSize := c.MainWindow.Canvas().Size()
popMin := pop.MinSize()
width := fyne.Max(700, fyne.Max(popMin.Width, winSize.Width*0.6))
height := fyne.Max(500, fyne.Max(popMin.Height, winSize.Height*0.7))
pop.Resize(fyne.NewSize(width, height))
c.haveModal = true
pop.Show()
}
func (c *Controller) GetSongRadioTracks(sourceTrack *mediaprovider.Track) ([]*mediaprovider.Track, error) {
radioTracks, err := c.App.ServerManager.Server.GetSongRadio(sourceTrack.ID, 100)
if err != nil {
+160
View File
@@ -0,0 +1,160 @@
package dialogs
import (
"fmt"
"strconv"
"time"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
"github.com/dweymouth/supersonic/backend/mediaprovider"
"github.com/dweymouth/supersonic/ui/util"
"github.com/dweymouth/supersonic/ui/widgets"
)
type TrackInfoDialog struct {
widget.BaseWidget
OnDismiss func()
OnNavigateToArtist func(artistID string)
OnNavigateToAlbum func(albumID string)
OnNavigateToGenre func(genre string)
OnCopyFilePath func()
track *mediaprovider.Track
}
func NewTrackInfoDialog(track *mediaprovider.Track) *TrackInfoDialog {
t := &TrackInfoDialog{track: track}
t.ExtendBaseWidget(t)
return t
}
func (t *TrackInfoDialog) CreateRenderer() fyne.WidgetRenderer {
c := container.New(layout.NewFormLayout())
addFormRow(c, "Title", t.track.Title)
c.Add(newFormText("Artist", true))
artists := widgets.NewMultiHyperlink()
artists.BuildSegments(t.track.ArtistNames, t.track.ArtistIDs)
artists.OnTapped = func(id string) {
if t.OnNavigateToArtist != nil {
t.OnNavigateToArtist(id)
}
}
c.Add(artists)
c.Add(newFormText("Album", true))
album := widget.NewHyperlink(t.track.Album, nil)
album.OnTapped = func() {
if t.OnNavigateToAlbum != nil {
t.OnNavigateToAlbum(t.track.AlbumID)
}
}
c.Add(album)
if len(t.track.Genres) > 0 {
c.Add(newFormText("Genres", true))
genres := widgets.NewMultiHyperlink()
genres.BuildSegments(t.track.Genres, t.track.Genres)
genres.OnTapped = func(g string) {
if t.OnNavigateToGenre != nil {
t.OnNavigateToGenre(g)
}
}
c.Add(genres)
}
addFormRow(c, "Duration", util.SecondsToTimeString(float64(t.track.Duration)))
copyBtn := widgets.NewIconButton(theme.ContentCopyIcon(), func() {
if t.OnCopyFilePath != nil {
t.OnCopyFilePath()
}
})
copyBtn.IconSize = widgets.IconButtonSizeSmaller
btnCtr := container.New(layout.NewCustomPaddedLayout(8, 0, 10, 0),
container.NewVBox(copyBtn, layout.NewSpacer()))
c.Add(container.NewHBox(btnCtr, newFormText("File path", true)))
c.Add(newFormText(t.track.FilePath, false))
addFormRow(c, "Comment", t.track.Comment)
addFormRow(c, "Year", strconv.Itoa(t.track.Year))
addFormRow(c, "Track number", strconv.Itoa(t.track.TrackNumber))
addFormRow(c, "Disc number", strconv.Itoa(t.track.DiscNumber))
if t.track.BPM > 0 {
addFormRow(c, "BPM", strconv.Itoa(t.track.BPM))
}
addFormRow(c, "Content type", t.track.ContentType)
addFormRow(c, "Bit rate", fmt.Sprintf("%d kbps", t.track.BitRate))
addFormRow(c, "File size", util.BytesToSizeString(t.track.Size))
addFormRow(c, "Play count", strconv.Itoa(t.track.PlayCount))
if !t.track.LastPlayed.IsZero() {
addFormRow(c, "Last played", t.track.LastPlayed.Format(time.RFC1123))
}
if t.track.ReplayGain.TrackPeak > 0 {
addFormRow(c, "Track gain", fmt.Sprintf("%0.2f dB", t.track.ReplayGain.TrackGain))
addFormRow(c, "Track peak", fmt.Sprintf("%0.6f", t.track.ReplayGain.TrackPeak))
}
if t.track.ReplayGain.AlbumPeak > 0 {
addFormRow(c, "Album gain", fmt.Sprintf("%0.2f dB", t.track.ReplayGain.AlbumGain))
addFormRow(c, "Album peak", fmt.Sprintf("%0.6f", t.track.ReplayGain.AlbumPeak))
}
title := widget.NewRichTextWithText("Track Info")
title.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = true
dismissBtn := widget.NewButton("Close", func() {
if t.OnDismiss != nil {
t.OnDismiss()
}
})
return widget.NewSimpleRenderer(
container.NewBorder(
/*top*/ container.NewHBox(layout.NewSpacer(), title, layout.NewSpacer()),
/*bottom*/ container.NewVBox(
widget.NewSeparator(),
container.NewHBox(layout.NewSpacer(), dismissBtn),
),
/*left/right*/ nil, nil,
/*center*/ container.New(layout.NewCustomPaddedLayout(10, 10, 15, 15),
container.NewScroll(c)),
),
)
}
func addFormRow(c *fyne.Container, left, right string) {
if right == "" {
return
}
c.Add(newFormText(left, true))
c.Add(newFormText(right, false))
}
func newFormText(text string, leftCol bool) *widget.RichText {
alignment := fyne.TextAlignLeading
if leftCol {
alignment = fyne.TextAlignTrailing
}
rt := widget.NewRichText(
&widget.TextSegment{
Text: text,
Style: widget.RichTextStyle{
TextStyle: fyne.TextStyle{Bold: leftCol},
Alignment: alignment,
},
},
)
if !leftCol {
rt.Wrapping = fyne.TextWrapWord
}
return rt
}
+10 -1
View File
@@ -78,6 +78,7 @@ type Tracklist struct {
OnShare func(trackID string)
OnPlaySongRadio func(track *mediaprovider.Track)
OnReorderTracks func(trackIDs []string, insertPos int)
OnShowTrackInfo func(track *mediaprovider.Track)
OnShowArtistPage func(artistID string)
OnShowAlbumPage func(albumID string)
@@ -101,6 +102,7 @@ type Tracklist struct {
ratingSubmenu *fyne.MenuItem
shareMenuItem *fyne.MenuItem
songRadioMenuItem *fyne.MenuItem
infoMenuItem *fyne.MenuItem
container *fyne.Container
}
@@ -559,6 +561,12 @@ func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
t.onDownload(t.selectedTracks(), "Selected tracks")
})
download.Icon = theme.DownloadIcon()
t.infoMenuItem = fyne.NewMenuItem("Show info...", func() {
if t.OnShowTrackInfo != nil {
t.OnShowTrackInfo(t.selectedTracks()[0])
}
})
t.infoMenuItem.Icon = theme.InfoIcon()
favorite := fyne.NewMenuItem("Set favorite", func() {
t.onSetFavorites(t.selectedTracks(), true, true)
})
@@ -568,7 +576,7 @@ func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
})
unfavorite.Icon = myTheme.NotFavoriteIcon
t.ctxMenu.Items = append(t.ctxMenu.Items, fyne.NewMenuItemSeparator(),
playlist, download)
playlist, download, t.infoMenuItem)
t.shareMenuItem = fyne.NewMenuItem("Share...", func() {
t.onShare(t.selectedTracks())
})
@@ -587,6 +595,7 @@ func (t *Tracklist) onShowContextMenu(e *fyne.PointEvent, trackIdx int) {
}
t.ratingSubmenu.Disabled = t.Options.DisableRating
t.shareMenuItem.Disabled = t.Options.DisableSharing || len(t.selectedTracks()) != 1
t.infoMenuItem.Disabled = len(t.selectedTracks()) != 1
widget.ShowPopUpMenuAtPosition(t.ctxMenu, fyne.CurrentApp().Driver().CanvasForObject(t), e.AbsolutePosition)
}