#283: Prevent artist bio from overflowing header space
This commit is contained in:
@@ -3,7 +3,6 @@ package browsing
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/dweymouth/supersonic/backend"
|
"github.com/dweymouth/supersonic/backend"
|
||||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||||
@@ -280,7 +279,7 @@ type ArtistPageHeader struct {
|
|||||||
artistPage *ArtistPage
|
artistPage *ArtistPage
|
||||||
artistImage *widgets.ImagePlaceholder
|
artistImage *widgets.ImagePlaceholder
|
||||||
titleDisp *widget.RichText
|
titleDisp *widget.RichText
|
||||||
biographyDisp *widget.RichText
|
biographyDisp *widgets.MaxRowsLabel
|
||||||
similarArtists *fyne.Container
|
similarArtists *fyne.Container
|
||||||
favoriteBtn *widgets.FavoriteButton
|
favoriteBtn *widgets.FavoriteButton
|
||||||
playBtn *widget.Button
|
playBtn *widget.Button
|
||||||
@@ -294,7 +293,7 @@ func NewArtistPageHeader(page *ArtistPage) *ArtistPageHeader {
|
|||||||
a := &ArtistPageHeader{
|
a := &ArtistPageHeader{
|
||||||
artistPage: page,
|
artistPage: page,
|
||||||
titleDisp: widget.NewRichTextWithText(""),
|
titleDisp: widget.NewRichTextWithText(""),
|
||||||
biographyDisp: widget.NewRichTextWithText(artistBioNotAvailableStr),
|
biographyDisp: widgets.NewMaxRowsLabel(5, artistBioNotAvailableStr),
|
||||||
similarArtists: container.NewHBox(),
|
similarArtists: container.NewHBox(),
|
||||||
}
|
}
|
||||||
a.titleDisp.Segments[0].(*widget.TextSegment).Style = widget.RichTextStyle{
|
a.titleDisp.Segments[0].(*widget.TextSegment).Style = widget.RichTextStyle{
|
||||||
@@ -312,6 +311,7 @@ func NewArtistPageHeader(page *ArtistPage) *ArtistPageHeader {
|
|||||||
})
|
})
|
||||||
a.playRadioBtn = widget.NewButtonWithIcon(" Play Artist Radio", myTheme.ShuffleIcon, a.artistPage.playArtistRadio)
|
a.playRadioBtn = widget.NewButtonWithIcon(" Play Artist Radio", myTheme.ShuffleIcon, a.artistPage.playArtistRadio)
|
||||||
a.biographyDisp.Wrapping = fyne.TextWrapWord
|
a.biographyDisp.Wrapping = fyne.TextWrapWord
|
||||||
|
a.biographyDisp.Truncation = fyne.TextTruncateEllipsis
|
||||||
a.ExtendBaseWidget(a)
|
a.ExtendBaseWidget(a)
|
||||||
a.createContainer()
|
a.createContainer()
|
||||||
return a
|
return a
|
||||||
@@ -321,7 +321,7 @@ func (a *ArtistPageHeader) Clear() {
|
|||||||
a.artistID = ""
|
a.artistID = ""
|
||||||
a.favoriteBtn.IsFavorited = false
|
a.favoriteBtn.IsFavorited = false
|
||||||
a.titleDisp.Segments[0].(*widget.TextSegment).Text = ""
|
a.titleDisp.Segments[0].(*widget.TextSegment).Text = ""
|
||||||
a.biographyDisp.Segments[0].(*widget.TextSegment).Text = artistBioNotAvailableStr
|
a.biographyDisp.Text = artistBioNotAvailableStr
|
||||||
for _, obj := range a.similarArtists.Objects {
|
for _, obj := range a.similarArtists.Objects {
|
||||||
obj.Hide()
|
obj.Hide()
|
||||||
}
|
}
|
||||||
@@ -352,14 +352,8 @@ func (a *ArtistPageHeader) UpdateInfo(info *mediaprovider.ArtistInfo) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.Biography != "" {
|
if text := util.PlaintextFromHTMLString(info.Biography); text != "" {
|
||||||
segs := util.RichTextSegsFromHTMLString(info.Biography)
|
a.biographyDisp.SetText(text)
|
||||||
if len(segs) > 0 {
|
|
||||||
if ts, ok := segs[0].(*widget.TextSegment); ok && strings.TrimSpace(ts.Text) != "" {
|
|
||||||
a.biographyDisp.Segments = segs
|
|
||||||
a.biographyDisp.Refresh()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(a.similarArtists.Objects) == 0 {
|
if len(a.similarArtists.Objects) == 0 {
|
||||||
|
|||||||
+4
-5
@@ -82,10 +82,10 @@ func NewDebouncer(dur time.Duration, callOnDone func()) func() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func RichTextSegsFromHTMLString(s string) []widget.RichTextSegment {
|
func PlaintextFromHTMLString(s string) string {
|
||||||
tokr := html.NewTokenizer(strings.NewReader(s))
|
tokr := html.NewTokenizer(strings.NewReader(s))
|
||||||
var segs []widget.RichTextSegment
|
|
||||||
|
|
||||||
|
var text string
|
||||||
var isLink bool
|
var isLink bool
|
||||||
var done bool
|
var done bool
|
||||||
for !done {
|
for !done {
|
||||||
@@ -102,12 +102,11 @@ func RichTextSegsFromHTMLString(s string) []widget.RichTextSegment {
|
|||||||
t := tokr.Token()
|
t := tokr.Token()
|
||||||
// for now, skip displaying Navidrome's "Read more on Last.FM" link
|
// for now, skip displaying Navidrome's "Read more on Last.FM" link
|
||||||
if !isLink {
|
if !isLink {
|
||||||
segs = append(segs, &widget.TextSegment{Text: t.Data})
|
text = text + t.Data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return text
|
||||||
return segs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRatingSubmenu(onSetRating func(int)) *fyne.MenuItem {
|
func NewRatingSubmenu(onSetRating func(int)) *fyne.MenuItem {
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package widgets
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MaxRowsLabel struct {
|
||||||
|
widget.Label
|
||||||
|
|
||||||
|
maxHeight float32
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMaxRowsLabel(maxRows int, text string) *MaxRowsLabel {
|
||||||
|
if maxRows < 1 {
|
||||||
|
maxRows = 1
|
||||||
|
}
|
||||||
|
m := &MaxRowsLabel{
|
||||||
|
Label: widget.Label{
|
||||||
|
Text: text,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
m.ExtendBaseWidget(m)
|
||||||
|
|
||||||
|
maxHeightText := strings.Repeat("W\n", maxRows)
|
||||||
|
maxHeightText = maxHeightText[:len(maxHeightText)-1]
|
||||||
|
m.maxHeight = widget.NewLabel(maxHeightText).MinSize().Height
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MaxRowsLabel) MinSize() fyne.Size {
|
||||||
|
return fyne.NewSize(m.Label.MinSize().Width, m.maxHeight)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user