WIP - multi hyperlink

This commit is contained in:
Drew Weymouth
2023-10-22 11:10:36 -07:00
parent 6f08032f22
commit c3143dbbbe
5 changed files with 109 additions and 94 deletions
-73
View File
@@ -1,73 +0,0 @@
package widgets
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/widget"
)
type DisableableHyperlink struct {
widget.BaseWidget
h *widget.Hyperlink
l *widget.Label
OnTapped func()
NoTruncate bool
Disabled bool
lastDisabled bool
container *fyne.Container
}
func NewDisableableHyperlink() *DisableableHyperlink {
c := &DisableableHyperlink{
h: widget.NewHyperlink("", nil),
l: widget.NewLabel(""),
container: container.NewMax(),
}
c.h.OnTapped = func() {
if c.OnTapped != nil {
c.OnTapped()
}
}
c.ExtendBaseWidget(c)
c.updateContainer(c.Disabled)
return c
}
func (c *DisableableHyperlink) SetText(text string) {
lastWrapping := c.l.Wrapping
c.l.Wrapping = fyne.TextWrapOff
c.l.SetText(text)
c.h.SetText(text)
c.l.Wrapping = lastWrapping
c.Refresh()
}
func (c *DisableableHyperlink) Refresh() {
if c.NoTruncate {
c.h.Wrapping = fyne.TextWrapOff
c.l.Wrapping = fyne.TextWrapOff
} else {
c.h.Wrapping = fyne.TextTruncate
c.l.Wrapping = fyne.TextTruncate
}
if c.lastDisabled != c.Disabled {
c.updateContainer(c.Disabled)
c.lastDisabled = c.Disabled
}
c.container.Refresh()
}
func (c *DisableableHyperlink) CreateRenderer() fyne.WidgetRenderer {
return widget.NewSimpleRenderer(c.container)
}
func (c *DisableableHyperlink) updateContainer(linkDisabled bool) {
c.container.RemoveAll()
if linkDisabled {
c.container.Add(c.l)
} else {
c.container.Add(c.h)
}
}
+5 -5
View File
@@ -135,7 +135,7 @@ type GridViewItem struct {
itemID string
secondaryID string
primaryText *widget.Hyperlink
secondaryText *DisableableHyperlink
secondaryText *MultiHyperlink
container *fyne.Container
// updated by GridView
@@ -151,7 +151,7 @@ type GridViewItem struct {
func NewGridViewItem(placeholderResource fyne.Resource) *GridViewItem {
g := &GridViewItem{
primaryText: widget.NewHyperlink("", nil),
secondaryText: NewDisableableHyperlink(),
secondaryText: NewMultiHyperlink(),
Cover: newCoverImage(placeholderResource),
}
g.primaryText.TextStyle.Bold = true
@@ -174,7 +174,7 @@ func NewGridViewItem(placeholderResource fyne.Resource) *GridViewItem {
}
g.Cover.OnShowPage = showItemFn
g.primaryText.OnTapped = showItemFn
g.secondaryText.OnTapped = func() {
g.secondaryText.OnTapped = func(_ string) { // TODO
if g.OnShowSecondaryPage != nil {
g.OnShowSecondaryPage()
}
@@ -199,8 +199,8 @@ func (g *GridViewItem) Update(model GridViewItemModel) {
g.itemID = model.ID
g.secondaryID = model.SecondaryID
g.primaryText.SetText(model.Name)
g.secondaryText.Disabled = model.SecondaryID == ""
g.secondaryText.SetText(model.Secondary)
g.secondaryText.Segments = []MultiHyperlinkSegment{{Text: model.Secondary, LinkID: model.SecondaryID}}
g.secondaryText.Refresh()
g.Cover.ResetPlayButton()
}
+96
View File
@@ -0,0 +1,96 @@
package widgets
import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/widget"
)
type MultiHyperlink struct {
widget.BaseWidget
Segments []MultiHyperlinkSegment
OnTapped func(string)
provider *widget.RichText
}
type MultiHyperlinkSegment struct {
Text string
LinkID string
}
func NewMultiHyperlink() *MultiHyperlink {
c := &MultiHyperlink{
provider: widget.NewRichText(),
}
c.ExtendBaseWidget(c)
c.provider.Wrapping = fyne.TextTruncate
return c
}
func (c *MultiHyperlink) syncSegments() {
l := len(c.provider.Segments)
for i, seg := range c.Segments {
appendingSegments := 2*i >= l // true if we need to extend the RichText provider with new segments
var rtSeg widget.RichTextSegment
if !appendingSegments {
rtSeg = c.provider.Segments[2*i]
} else if i > 0 {
// append new separator segment
c.provider.Segments = append(c.provider.Segments, c.newSeparatorSegment())
}
if seg.LinkID == "" {
rtSeg = c.updateOrReplaceTextSegment(rtSeg, seg.Text)
} else {
rtSeg = c.updateOrReplaceHyperlinkSegment(rtSeg, seg.Text, seg.LinkID)
}
if appendingSegments {
c.provider.Segments = append(c.provider.Segments, rtSeg)
} else {
c.provider.Segments[2*i] = rtSeg
}
}
// discard extra segments if shortening the multihyperlink
for i := 2 * len(c.Segments); i < l; i++ {
c.provider.Segments[i] = nil
}
c.provider.Segments = c.provider.Segments[:2*len(c.Segments)-1]
}
func (c *MultiHyperlink) newSeparatorSegment() widget.RichTextSegment {
return &widget.TextSegment{Text: ", ", Style: widget.RichTextStyle{Inline: true}}
}
func (c *MultiHyperlink) updateOrReplaceTextSegment(seg widget.RichTextSegment, text string) widget.RichTextSegment {
if seg != nil {
if ts, ok := seg.(*widget.TextSegment); ok {
ts.Text = text
return seg
}
}
return &widget.TextSegment{Text: text, Style: widget.RichTextStyle{Inline: true}}
}
func (c *MultiHyperlink) updateOrReplaceHyperlinkSegment(seg widget.RichTextSegment, text, linkID string) widget.RichTextSegment {
if seg != nil {
if ts, ok := seg.(*widget.HyperlinkSegment); ok {
ts.Text = text
// TODO: OnTapped
return seg
}
}
return &widget.HyperlinkSegment{Text: text} // TODO: OnTapped
}
func (c *MultiHyperlink) onSegmentTapped(linkID string) {
// TODO
}
func (c *MultiHyperlink) Refresh() {
c.syncSegments()
c.BaseWidget.Refresh()
}
func (c *MultiHyperlink) CreateRenderer() fyne.WidgetRenderer {
return widget.NewSimpleRenderer(c.provider)
}
+4 -5
View File
@@ -18,7 +18,7 @@ type NowPlayingCard struct {
widget.BaseWidget
trackName *widget.Hyperlink
artistName *DisableableHyperlink
artistName *MultiHyperlink
albumName *widget.Hyperlink
cover *TappableImage
menu *widget.PopUpMenu
@@ -34,7 +34,7 @@ type NowPlayingCard struct {
func NewNowPlayingCard() *NowPlayingCard {
n := &NowPlayingCard{
trackName: widget.NewHyperlink("", nil),
artistName: NewDisableableHyperlink(),
artistName: NewMultiHyperlink(),
albumName: widget.NewHyperlink("", nil),
}
n.ExtendBaseWidget(n)
@@ -88,9 +88,8 @@ func (n *NowPlayingCard) CreateRenderer() fyne.WidgetRenderer {
func (n *NowPlayingCard) Update(track, artist string, artistNavigable bool, album string, cover image.Image) {
n.trackName.SetText(track)
n.trackName.Hidden = track == ""
n.artistName.SetText(artist)
n.artistName.Segments = []MultiHyperlinkSegment{{Text: artist}}
n.artistName.Hidden = artist == ""
n.artistName.Disabled = !artistNavigable
n.albumName.SetText(album)
n.albumName.Hidden = album == ""
n.cover.Image.Image = cover
@@ -98,7 +97,7 @@ func (n *NowPlayingCard) Update(track, artist string, artistNavigable bool, albu
}
func (n *NowPlayingCard) OnArtistNameTapped(f func()) {
n.artistName.OnTapped = f
//n.artistName.OnTapped = f
}
func (n *NowPlayingCard) OnAlbumNameTapped(f func()) {
+4 -11
View File
@@ -676,7 +676,7 @@ type TrackRow struct {
num *widget.RichText
name *widget.RichText
artist *DisableableHyperlink
artist *MultiHyperlink
album *widget.Hyperlink
dur *widget.RichText
year *widget.RichText
@@ -697,8 +697,8 @@ func NewTrackRow(tracklist *Tracklist, playingIcon fyne.CanvasObject) *TrackRow
t.ExtendBaseWidget(t)
t.num = newTrailingAlignRichText()
t.name = newTruncatingRichText()
t.artist = NewDisableableHyperlink()
t.artist.OnTapped = func() { tracklist.onArtistTapped(t.artistID) }
t.artist = NewMultiHyperlink()
//t.artist.OnTapped = func() { tracklist.onArtistTapped(t.artistID) } // TODO
t.album = widget.NewHyperlink("", nil)
t.album.Wrapping = fyne.TextTruncate
t.album.OnTapped = func() { tracklist.onAlbumTapped(t.albumID) }
@@ -748,8 +748,7 @@ func (t *TrackRow) Update(tm *trackModel, rowNum int) {
t.albumID = tr.AlbumID
t.name.Segments[0].(*widget.TextSegment).Text = tr.Name
t.artist.SetText(tr.ArtistNames[0])
t.artist.Disabled = tr.ArtistIDs[0] == ""
t.artist.Segments = []MultiHyperlinkSegment{{Text: tr.ArtistNames[0], LinkID: tr.ArtistIDs[0]}}
t.album.SetText(tr.Album)
t.dur.Segments[0].(*widget.TextSegment).Text = util.SecondsToTimeString(float64(tr.Duration))
t.year.Segments[0].(*widget.TextSegment).Text = strconv.Itoa(tr.Year)
@@ -789,12 +788,6 @@ func (t *TrackRow) Update(tm *trackModel, rowNum int) {
if isPlaying := t.tracklist.nowPlayingID == tr.ID; isPlaying != t.isPlaying {
t.isPlaying = isPlaying
t.name.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = isPlaying
t.dur.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = isPlaying
t.year.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = isPlaying
t.plays.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = isPlaying
t.bitrate.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = isPlaying
t.size.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = isPlaying
t.path.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = isPlaying
if isPlaying {
t.Content.(*fyne.Container).Objects[0] = container.NewCenter(t.playingIcon)