WIP - multi hyperlink
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user