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
|
itemID string
|
||||||
secondaryID string
|
secondaryID string
|
||||||
primaryText *widget.Hyperlink
|
primaryText *widget.Hyperlink
|
||||||
secondaryText *DisableableHyperlink
|
secondaryText *MultiHyperlink
|
||||||
container *fyne.Container
|
container *fyne.Container
|
||||||
|
|
||||||
// updated by GridView
|
// updated by GridView
|
||||||
@@ -151,7 +151,7 @@ type GridViewItem struct {
|
|||||||
func NewGridViewItem(placeholderResource fyne.Resource) *GridViewItem {
|
func NewGridViewItem(placeholderResource fyne.Resource) *GridViewItem {
|
||||||
g := &GridViewItem{
|
g := &GridViewItem{
|
||||||
primaryText: widget.NewHyperlink("", nil),
|
primaryText: widget.NewHyperlink("", nil),
|
||||||
secondaryText: NewDisableableHyperlink(),
|
secondaryText: NewMultiHyperlink(),
|
||||||
Cover: newCoverImage(placeholderResource),
|
Cover: newCoverImage(placeholderResource),
|
||||||
}
|
}
|
||||||
g.primaryText.TextStyle.Bold = true
|
g.primaryText.TextStyle.Bold = true
|
||||||
@@ -174,7 +174,7 @@ func NewGridViewItem(placeholderResource fyne.Resource) *GridViewItem {
|
|||||||
}
|
}
|
||||||
g.Cover.OnShowPage = showItemFn
|
g.Cover.OnShowPage = showItemFn
|
||||||
g.primaryText.OnTapped = showItemFn
|
g.primaryText.OnTapped = showItemFn
|
||||||
g.secondaryText.OnTapped = func() {
|
g.secondaryText.OnTapped = func(_ string) { // TODO
|
||||||
if g.OnShowSecondaryPage != nil {
|
if g.OnShowSecondaryPage != nil {
|
||||||
g.OnShowSecondaryPage()
|
g.OnShowSecondaryPage()
|
||||||
}
|
}
|
||||||
@@ -199,8 +199,8 @@ func (g *GridViewItem) Update(model GridViewItemModel) {
|
|||||||
g.itemID = model.ID
|
g.itemID = model.ID
|
||||||
g.secondaryID = model.SecondaryID
|
g.secondaryID = model.SecondaryID
|
||||||
g.primaryText.SetText(model.Name)
|
g.primaryText.SetText(model.Name)
|
||||||
g.secondaryText.Disabled = model.SecondaryID == ""
|
g.secondaryText.Segments = []MultiHyperlinkSegment{{Text: model.Secondary, LinkID: model.SecondaryID}}
|
||||||
g.secondaryText.SetText(model.Secondary)
|
g.secondaryText.Refresh()
|
||||||
g.Cover.ResetPlayButton()
|
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
|
widget.BaseWidget
|
||||||
|
|
||||||
trackName *widget.Hyperlink
|
trackName *widget.Hyperlink
|
||||||
artistName *DisableableHyperlink
|
artistName *MultiHyperlink
|
||||||
albumName *widget.Hyperlink
|
albumName *widget.Hyperlink
|
||||||
cover *TappableImage
|
cover *TappableImage
|
||||||
menu *widget.PopUpMenu
|
menu *widget.PopUpMenu
|
||||||
@@ -34,7 +34,7 @@ type NowPlayingCard struct {
|
|||||||
func NewNowPlayingCard() *NowPlayingCard {
|
func NewNowPlayingCard() *NowPlayingCard {
|
||||||
n := &NowPlayingCard{
|
n := &NowPlayingCard{
|
||||||
trackName: widget.NewHyperlink("", nil),
|
trackName: widget.NewHyperlink("", nil),
|
||||||
artistName: NewDisableableHyperlink(),
|
artistName: NewMultiHyperlink(),
|
||||||
albumName: widget.NewHyperlink("", nil),
|
albumName: widget.NewHyperlink("", nil),
|
||||||
}
|
}
|
||||||
n.ExtendBaseWidget(n)
|
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) {
|
func (n *NowPlayingCard) Update(track, artist string, artistNavigable bool, album string, cover image.Image) {
|
||||||
n.trackName.SetText(track)
|
n.trackName.SetText(track)
|
||||||
n.trackName.Hidden = track == ""
|
n.trackName.Hidden = track == ""
|
||||||
n.artistName.SetText(artist)
|
n.artistName.Segments = []MultiHyperlinkSegment{{Text: artist}}
|
||||||
n.artistName.Hidden = artist == ""
|
n.artistName.Hidden = artist == ""
|
||||||
n.artistName.Disabled = !artistNavigable
|
|
||||||
n.albumName.SetText(album)
|
n.albumName.SetText(album)
|
||||||
n.albumName.Hidden = album == ""
|
n.albumName.Hidden = album == ""
|
||||||
n.cover.Image.Image = cover
|
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()) {
|
func (n *NowPlayingCard) OnArtistNameTapped(f func()) {
|
||||||
n.artistName.OnTapped = f
|
//n.artistName.OnTapped = f
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NowPlayingCard) OnAlbumNameTapped(f func()) {
|
func (n *NowPlayingCard) OnAlbumNameTapped(f func()) {
|
||||||
|
|||||||
+4
-11
@@ -676,7 +676,7 @@ type TrackRow struct {
|
|||||||
|
|
||||||
num *widget.RichText
|
num *widget.RichText
|
||||||
name *widget.RichText
|
name *widget.RichText
|
||||||
artist *DisableableHyperlink
|
artist *MultiHyperlink
|
||||||
album *widget.Hyperlink
|
album *widget.Hyperlink
|
||||||
dur *widget.RichText
|
dur *widget.RichText
|
||||||
year *widget.RichText
|
year *widget.RichText
|
||||||
@@ -697,8 +697,8 @@ func NewTrackRow(tracklist *Tracklist, playingIcon fyne.CanvasObject) *TrackRow
|
|||||||
t.ExtendBaseWidget(t)
|
t.ExtendBaseWidget(t)
|
||||||
t.num = newTrailingAlignRichText()
|
t.num = newTrailingAlignRichText()
|
||||||
t.name = newTruncatingRichText()
|
t.name = newTruncatingRichText()
|
||||||
t.artist = NewDisableableHyperlink()
|
t.artist = NewMultiHyperlink()
|
||||||
t.artist.OnTapped = func() { tracklist.onArtistTapped(t.artistID) }
|
//t.artist.OnTapped = func() { tracklist.onArtistTapped(t.artistID) } // TODO
|
||||||
t.album = widget.NewHyperlink("", nil)
|
t.album = widget.NewHyperlink("", nil)
|
||||||
t.album.Wrapping = fyne.TextTruncate
|
t.album.Wrapping = fyne.TextTruncate
|
||||||
t.album.OnTapped = func() { tracklist.onAlbumTapped(t.albumID) }
|
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.albumID = tr.AlbumID
|
||||||
|
|
||||||
t.name.Segments[0].(*widget.TextSegment).Text = tr.Name
|
t.name.Segments[0].(*widget.TextSegment).Text = tr.Name
|
||||||
t.artist.SetText(tr.ArtistNames[0])
|
t.artist.Segments = []MultiHyperlinkSegment{{Text: tr.ArtistNames[0], LinkID: tr.ArtistIDs[0]}}
|
||||||
t.artist.Disabled = tr.ArtistIDs[0] == ""
|
|
||||||
t.album.SetText(tr.Album)
|
t.album.SetText(tr.Album)
|
||||||
t.dur.Segments[0].(*widget.TextSegment).Text = util.SecondsToTimeString(float64(tr.Duration))
|
t.dur.Segments[0].(*widget.TextSegment).Text = util.SecondsToTimeString(float64(tr.Duration))
|
||||||
t.year.Segments[0].(*widget.TextSegment).Text = strconv.Itoa(tr.Year)
|
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 {
|
if isPlaying := t.tracklist.nowPlayingID == tr.ID; isPlaying != t.isPlaying {
|
||||||
t.isPlaying = isPlaying
|
t.isPlaying = isPlaying
|
||||||
t.name.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = 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 {
|
if isPlaying {
|
||||||
t.Content.(*fyne.Container).Objects[0] = container.NewCenter(t.playingIcon)
|
t.Content.(*fyne.Container).Objects[0] = container.NewCenter(t.playingIcon)
|
||||||
|
|||||||
Reference in New Issue
Block a user