Merge branch 'main' into new-add-to-playlist

This commit is contained in:
Drew Weymouth
2024-05-23 08:06:59 -07:00
committed by GitHub
11 changed files with 142 additions and 63 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ func NewBottomPanel(pm *backend.PlaybackManager, contr *controller.Controller) *
bp.ExtendBaseWidget(bp)
pm.OnSongChange(bp.onSongChange)
pm.OnPlayTimeUpdate(func(cur, total float64) {
pm.OnPlayTimeUpdate(func(cur, total float64, _ bool) {
if !pm.IsSeeking() {
bp.Controls.UpdatePlayTime(cur, total)
}
+3 -3
View File
@@ -46,7 +46,7 @@ type CanShowNowPlaying interface {
}
type CanShowPlayTime interface {
OnPlayTimeUpdate(curTime, totalTime float64)
OnPlayTimeUpdate(curTime, totalTime float64, seeked bool)
}
type CanShowPlayQueue interface {
@@ -222,12 +222,12 @@ func (b *BrowsingPane) onSongChange(song, lastScrobbledIfAny *mediaprovider.Trac
}
}
func (b *BrowsingPane) onPlayTimeUpdate(cur, total float64) {
func (b *BrowsingPane) onPlayTimeUpdate(cur, total float64, seeked bool) {
if b.curPage == nil {
return
}
if p, ok := b.curPage.(CanShowPlayTime); ok {
p.OnPlayTimeUpdate(cur, total)
p.OnPlayTimeUpdate(cur, total, seeked)
}
}
+6 -1
View File
@@ -241,8 +241,13 @@ func (s *nowPlayingPageState) Restore() Page {
var _ CanShowPlayTime = (*NowPlayingPage)(nil)
func (a *NowPlayingPage) OnPlayTimeUpdate(_, _ float64) {
func (a *NowPlayingPage) OnPlayTimeUpdate(curTime, _ float64, seeked bool) {
a.formatStatusLine()
if seeked {
a.lyricsViewer.OnSeeked(curTime)
} else {
a.lyricsViewer.UpdatePlayPos(curTime)
}
}
var _ CanSelectAll = (*NowPlayingPage)(nil)
+74 -31
View File
@@ -4,66 +4,109 @@ import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
fynelyrics "github.com/dweymouth/fyne-lyrics"
"github.com/dweymouth/supersonic/backend/mediaprovider"
)
type LyricsViewer struct {
widget.BaseWidget
noLyricsLabel widget.Label
unsyncedViewer *widget.RichText
noLyricsLabel widget.Label
viewer *fynelyrics.LyricsViewer
lyrics *mediaprovider.Lyrics
nextLyricLine int
lastPlayPos float64
container *container.Scroll
currentView lyricView
// keeps track if UpdatePlayPos has been called yet
// for the current lyrics
firstUpdate bool
container *fyne.Container
isEmpty bool
}
type lyricView int
const (
lyricViewEmpty lyricView = iota
lyricViewUnsynced
lyricViewSynced
)
func NewLyricsViewer() *LyricsViewer {
l := &LyricsViewer{noLyricsLabel: widget.Label{
Text: "Lyrics not available",
}}
}, isEmpty: true}
l.ExtendBaseWidget(l)
l.container = container.NewVScroll(&l.noLyricsLabel)
l.container = container.NewStack(&l.noLyricsLabel)
return l
}
func (l *LyricsViewer) SetLyrics(lyrics *mediaprovider.Lyrics) {
l.lyrics = lyrics
l.nextLyricLine = 0
l.firstUpdate = true
if lyrics == nil || len(lyrics.Lines) == 0 {
if l.currentView != lyricViewEmpty {
l.container.Content = &l.noLyricsLabel
l.currentView = lyricViewEmpty
if !l.isEmpty {
l.container.Objects[0] = &l.noLyricsLabel
l.isEmpty = true
l.Refresh()
}
return
}
if l.unsyncedViewer == nil {
l.unsyncedViewer = widget.NewRichText()
l.unsyncedViewer.Wrapping = fyne.TextWrapWord
if l.viewer == nil {
l.viewer = fynelyrics.NewLyricsViewer()
l.viewer.ActiveLyricPosition = fynelyrics.ActiveLyricPositionTopThird
}
l.unsyncedViewer.Segments = nil
for _, line := range lyrics.Lines {
ts := &widget.TextSegment{Text: line.Text}
ts.Style.Alignment = fyne.TextAlignCenter
ts.Style.SizeName = widget.RichTextStyleSubHeading.SizeName
ts.Style.Inline = false
l.unsyncedViewer.Segments = append(l.unsyncedViewer.Segments, ts)
lines := make([]string, len(lyrics.Lines))
for i, line := range lyrics.Lines {
lines[i] = line.Text
}
l.unsyncedViewer.Refresh()
if l.currentView != lyricViewUnsynced {
l.container.Content = l.unsyncedViewer
l.currentView = lyricViewUnsynced
l.viewer.SetLyrics(lines, lyrics.Synced)
if l.isEmpty {
l.container.Objects[0] = l.viewer
l.isEmpty = false
l.Refresh()
}
}
func (l *LyricsViewer) UpdatePlayPos(timeSecs float64) {
if l.lyrics == nil || !l.lyrics.Synced {
return
}
if l.firstUpdate || timeSecs < l.lastPlayPos {
l.OnSeeked(timeSecs)
l.firstUpdate = false
return
}
l.lastPlayPos = timeSecs
// advance if needed
if l.lyrics.Lines[l.nextLyricLine].Start <= timeSecs {
l.viewer.NextLine()
if l.nextLyricLine < len(l.lyrics.Lines)-1 {
l.nextLyricLine++
}
}
}
func (l *LyricsViewer) OnSeeked(timeSecs float64) {
l.lastPlayPos = timeSecs
if l.lyrics == nil || !l.lyrics.Synced {
return
}
// find first line that starts after timeSecs
nextLine := -1
for i, l := range l.lyrics.Lines {
if l.Start > timeSecs {
nextLine = i
break
}
}
if nextLine == -1 {
// last lyric
nextLine = len(l.lyrics.Lines)
l.nextLyricLine = nextLine - 1
} else {
l.nextLyricLine = nextLine
}
l.viewer.SetCurrentLine(nextLine /*one-indexed*/)
}
func (l *LyricsViewer) CreateRenderer() fyne.WidgetRenderer {
return widget.NewSimpleRenderer(l.container)
}