From aa58a5080406545d9a38fe2ccf73dfe2101f5561 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sun, 3 Mar 2024 11:00:16 -0800 Subject: [PATCH] add status line to fullscreen page --- ui/browsing/fullscreenpage.go | 123 ++++++++++++++++++++++++++++++---- 1 file changed, 109 insertions(+), 14 deletions(-) diff --git a/ui/browsing/fullscreenpage.go b/ui/browsing/fullscreenpage.go index 65b6ccf..d0b53b6 100644 --- a/ui/browsing/fullscreenpage.go +++ b/ui/browsing/fullscreenpage.go @@ -2,20 +2,26 @@ package browsing import ( "context" + "fmt" "image" "log" + "strings" "github.com/dweymouth/supersonic/backend" "github.com/dweymouth/supersonic/backend/mediaprovider" + "github.com/dweymouth/supersonic/backend/player" + "github.com/dweymouth/supersonic/backend/player/mpv" "github.com/dweymouth/supersonic/sharedutil" "github.com/dweymouth/supersonic/ui/controller" "github.com/dweymouth/supersonic/ui/layouts" + myTheme "github.com/dweymouth/supersonic/ui/theme" "github.com/dweymouth/supersonic/ui/util" "github.com/dweymouth/supersonic/ui/widgets" "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" ) @@ -28,6 +34,8 @@ type FullscreenPage struct { queueList *widgets.PlayQueueList imageLoadCancel context.CancelFunc card *widgets.LargeNowPlayingCard + statusLabel *widget.Label + totalTime float64 nowPlayingID string albumID string container *fyne.Container @@ -53,6 +61,10 @@ func NewFullscreenPage( }} a.ExtendBaseWidget(a) + pm.OnPaused(a.formatStatusLine) + pm.OnPlaying(a.formatStatusLine) + pm.OnStopped(a.formatStatusLine) + a.card = widgets.NewLargeNowPlayingCard() a.card.DisableRating = !canRate a.card.OnAlbumNameTapped = func() { @@ -75,26 +87,37 @@ func NewFullscreenPage( a.queueList.OnShowArtistPage = func(artistID string) { a.contr.NavigateTo(controller.ArtistRoute(artistID)) } - paddedLayout := &layouts.PercentPadLayout{ - LeftRightObjectPercent: .8, - TopBottomObjectPercent: .8, - } - a.container = container.NewGridWithColumns(2, - container.New(paddedLayout, a.card), - container.New(paddedLayout, - util.AddHeaderBackground( - container.NewAppTabs( - container.NewTabItem("Play Queue", - container.NewBorder(layout.NewSpacer(), nil, nil, nil, a.queueList)), - container.NewTabItem("Lyrics", layout.NewSpacer()), - ))), - ) + a.statusLabel = widget.NewLabel("Stopped") a.Reload() return a } func (a *FullscreenPage) CreateRenderer() fyne.WidgetRenderer { + if a.container == nil { + paddedLayout := &layouts.PercentPadLayout{ + LeftRightObjectPercent: .8, + TopBottomObjectPercent: .8, + } + mainContent := container.NewGridWithColumns(2, + container.New(paddedLayout, a.card), + container.New(paddedLayout, + util.AddHeaderBackground( + container.NewAppTabs( + container.NewTabItem("Play Queue", + container.NewBorder(layout.NewSpacer(), nil, nil, nil, a.queueList)), + container.NewTabItem("Lyrics", layout.NewSpacer()), + )))) + a.container = container.NewStack( + mainContent, + container.NewVBox( + layout.NewSpacer(), + container.NewBorder(nil, nil, util.NewHSpace(1), util.NewHSpace(1), + myTheme.NewThemedRectangle(theme.ColorNameInputBorder)), + a.statusLabel, + ), + ) + } return widget.NewSimpleRenderer(a.container) } @@ -142,6 +165,11 @@ func (a *FullscreenPage) OnPlayQueueChange() { func (a *FullscreenPage) Reload() { a.queue = a.pm.GetPlayQueue() a.queueList.SetTracks(a.queue) + a.totalTime = 0.0 + for _, tr := range a.queue { + a.totalTime += float64(tr.Duration) + } + a.formatStatusLine() } func (s *fullscreenPageState) Restore() Page { @@ -151,3 +179,70 @@ func (s *fullscreenPageState) Restore() Page { } return NewFullscreenPage(s.contr, s.pool, s.im, s.pm, s.canRate) } + +var _ CanShowPlayTime = (*FullscreenPage)(nil) + +func (a *FullscreenPage) OnPlayTimeUpdate(_, _ float64) { + a.formatStatusLine() +} + +func (a *FullscreenPage) formatStatusLine() { + curPlayer := a.pm.CurrentPlayer() + playerStats := curPlayer.GetStatus() + lastStatus := a.statusLabel.Text + state := "Stopped" + switch playerStats.State { + case player.Paused: + state = "Paused" + case player.Playing: + state = "Playing" + } + + dur := 0.0 + if np := a.pm.NowPlaying(); np != nil { + dur = float64(np.Duration) + } + statusSuffix := "" + trackNum := 0 + if state != "Stopped" { + trackNum = a.pm.NowPlayingIndex() + 1 + statusSuffix = fmt.Sprintf(" %s/%s", + util.SecondsToTimeString(playerStats.TimePos), + util.SecondsToTimeString(dur)) + } + status := fmt.Sprintf("%s (%d/%d)%s", state, trackNum, + len(a.queue), statusSuffix) + + mediaInfo := "" + if state != "Stopped" { + mediaInfo = a.formatMediaInfoStr(curPlayer) + } + if mediaInfo != "" { + mediaInfo = " ยท " + mediaInfo + } + + a.statusLabel.Text = fmt.Sprintf("%s%s | Total time: %s", status, mediaInfo, util.SecondsToTimeString(a.totalTime)) + if lastStatus != a.statusLabel.Text { + a.statusLabel.Refresh() + } +} + +func (a *FullscreenPage) formatMediaInfoStr(player player.BasePlayer) string { + mpv, ok := player.(*mpv.Player) + if !ok { + return "" + } + audioInfo, err := mpv.GetMediaInfo() + if err != nil { + log.Printf("error getting playback status: %s", err.Error()) + return "" + } + codec := audioInfo.Codec + if len(codec) <= 4 && !strings.EqualFold(codec, "opus") { + codec = strings.ToUpper(codec) // FLAC, MP3, AAC, etc + } + + // Note: bit depth intentionally omitted since MPV reports the decoded bit depth + // i.e. 24 bit files get reported as 32 bit. Also b/c bit depth isn't meaningful for lossy. + return fmt.Sprintf("%s %g kHz, %d kbps", codec, float64(audioInfo.Samplerate)/1000, audioInfo.Bitrate/1000) +}