diff --git a/ui/browsing/playlistspage.go b/ui/browsing/playlistspage.go index 95af201..4a2213e 100644 --- a/ui/browsing/playlistspage.go +++ b/ui/browsing/playlistspage.go @@ -99,8 +99,7 @@ func NewPlaylistList() *PlaylistList { a := &PlaylistList{ columnsLayout: layouts.NewColumnsLayout([]float32{-1, -1, 200, 125}), } - a.header = widgets.NewListHeader( - []widgets.ListColumn{{"Name", false}, {"Description", false}, {"Owner", false}, {"Track Count", true}}, a.columnsLayout) + a.buildHeader() a.list = widget.NewList( func() int { return len(a.Playlists) @@ -125,6 +124,15 @@ func NewPlaylistList() *PlaylistList { return a } +func (p *PlaylistList) buildHeader() { + p.header = widgets.NewListHeader([]widgets.ListColumn{ + {"Name", false, false}, + {"Description", false, false}, + {"Owner", false, false}, + {"Track Count", true, false}}, p.columnsLayout) + +} + func (p *PlaylistList) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(p.container) } diff --git a/ui/widgets/artistgenreplaylist.go b/ui/widgets/artistgenreplaylist.go index c827841..127c8fa 100644 --- a/ui/widgets/artistgenreplaylist.go +++ b/ui/widgets/artistgenreplaylist.go @@ -63,7 +63,8 @@ func NewArtistGenrePlaylist(items []ArtistGenrePlaylistItemModel) *ArtistGenrePl columnsLayout: layouts.NewColumnsLayout([]float32{-1, 125, 125}), } a.ExtendBaseWidget(a) - a.hdr = NewListHeader([]ListColumn{{"Name", false}, {"Album Count", true}, {"Track Count", true}}, a.columnsLayout) + a.hdr = NewListHeader([]ListColumn{ + {"Name", false, false}, {"Album Count", true, false}, {"Track Count", true, false}}, a.columnsLayout) a.list = widget.NewList( func() int { return len(a.Items) }, func() fyne.CanvasObject { diff --git a/ui/widgets/listheader.go b/ui/widgets/listheader.go index 18bcf0a..1223544 100644 --- a/ui/widgets/listheader.go +++ b/ui/widgets/listheader.go @@ -1,6 +1,7 @@ package widgets import ( + "log" "supersonic/ui/layouts" "fyne.io/fyne/v2" @@ -11,18 +12,23 @@ import ( ) type ListColumn struct { - Text string - AlignTrailing bool + Text string + AlignTrailing bool + CanToggleVisible bool } type ListHeader struct { widget.BaseWidget + OnColumnVisibilityChanged func(int, bool) + columns []ListColumn + columnVisible []bool columnsLayout *layouts.ColumnsLayout columnsContainer *fyne.Container container *fyne.Container + popUpMenu *fyne.Container } func NewListHeader(cols []ListColumn, layout *layouts.ColumnsLayout) *ListHeader { @@ -31,6 +37,10 @@ func NewListHeader(cols []ListColumn, layout *layouts.ColumnsLayout) *ListHeader columnsLayout: layout, columnsContainer: container.New(layout), } + l.columnVisible = make([]bool, len(cols)) + for i, _ := range l.columnVisible { + l.columnVisible[i] = true + } l.container = container.NewMax(canvas.NewRectangle(theme.BackgroundColor()), l.columnsContainer) l.ExtendBaseWidget(l) l.buildColumns() @@ -38,11 +48,16 @@ func NewListHeader(cols []ListColumn, layout *layouts.ColumnsLayout) *ListHeader } func (l *ListHeader) SetColumnVisible(colNum int, visible bool) { + if colNum >= len(l.columns) { + log.Println("error: ListHeader.SetColumnVisible: column index out of range") + return + } if visible { l.columnsContainer.Objects[colNum].Show() } else { l.columnsContainer.Objects[colNum].Hide() } + l.columnVisible[colNum] = visible } func (l *ListHeader) buildColumns() { @@ -61,3 +76,55 @@ func (l *ListHeader) buildColumns() { func (l *ListHeader) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(l.container) } + +func (l *ListHeader) TappedSecondary(e *fyne.PointEvent) { + l.setupPopUpMenu() + if len(l.popUpMenu.Objects) == 0 { + return + } + pop := widget.NewPopUp(l.popUpMenu, fyne.CurrentApp().Driver().CanvasForObject(l)) + pop.ShowAtPosition(e.AbsolutePosition) +} + +func (l *ListHeader) setupPopUpMenu() { + if l.popUpMenu == nil { + l.popUpMenu = container.New(&layouts.VboxCustomPadding{ExtraPad: -10}) + for i, c := range l.columns { + if c.CanToggleVisible { + l.popUpMenu.Add(widget.NewCheck(c.Text, l.createOnChangedCallbk(i))) + } + } + } + objIdx := 0 + for i, col := range l.columns { + if col.CanToggleVisible { + l.popUpMenu.Objects[objIdx].(*widget.Check).Checked = l.columnVisible[i] + objIdx++ + } + } +} + +func (l *ListHeader) createOnChangedCallbk(colNum int) func(bool) { + return func(val bool) { + l.columnVisible[colNum] = val + l.SetColumnVisible(colNum, val) + if l.OnColumnVisibilityChanged != nil { + l.OnColumnVisibilityChanged(colNum, val) + } + } +} + +type colVisibleToggle struct { + widget.Check +} + +func newColVisibleToggle(colNum int, colName string, visibilities []bool, onChanged func(bool)) *colVisibleToggle { + c := &colVisibleToggle{ + Check: widget.Check{ + Text: colName, + OnChanged: onChanged, + }, + } + c.ExtendBaseWidget(c) + return c +} diff --git a/ui/widgets/tracklist.go b/ui/widgets/tracklist.go index d586f48..c5082b1 100644 --- a/ui/widgets/tracklist.go +++ b/ui/widgets/tracklist.go @@ -1,6 +1,7 @@ package widgets import ( + "log" "runtime" "strconv" "supersonic/ui/layouts" @@ -59,9 +60,11 @@ func NewTracklist(tracks []*subsonic.Child) *Tracklist { t.ExtendBaseWidget(t) t.selectionMgr = util.NewListSelectionManager(func() int { return len(t.Tracks) }) t.colLayout = layouts.NewColumnsLayout([]float32{35, -1, -1, -1, 60, 65, 75}) - t.hdr = NewListHeader([]ListColumn{ - {"#", true}, {"Title", false}, {"Artist", false}, {"Album", false}, {"Time", true}, {"Plays", true}, {"Bitrate", true}}, - t.colLayout) + t.buildHeader() + t.hdr.OnColumnVisibilityChanged = func(col int, vis bool) { + // first 2 columns are builtin and always visible + t.SetColumnVisible(col-2, vis) + } playingIcon := container.NewCenter(container.NewHBox(NewHSpace(2), widget.NewIcon(theme.MediaPlayIcon()))) t.list = widget.NewList( func() int { return len(t.Tracks) }, @@ -86,6 +89,18 @@ func NewTracklist(tracks []*subsonic.Child) *Tracklist { return t } +func (t *Tracklist) buildHeader() { + t.hdr = NewListHeader([]ListColumn{ + {"#", true, false}, + {"Title", false, false}, + {"Artist", false, true}, + {"Album", false, true}, + {"Time", true, true}, + {"Plays", true, true}, + {"Bitrate", true, true}}, + t.colLayout) +} + func (t *Tracklist) SetVisibleColumns(cols []TracklistColumn) { for i := range t.visibleColumns { t.visibleColumns[i] = false @@ -95,6 +110,15 @@ func (t *Tracklist) SetVisibleColumns(cols []TracklistColumn) { } } +func (t *Tracklist) SetColumnVisible(colNum int, vis bool) { + if colNum >= len(t.visibleColumns) { + log.Printf("error: Tracklist.SetColumnVisible: column index %d out of range", colNum) + return + } + t.visibleColumns[colNum] = vis + t.Refresh() +} + func (t *Tracklist) SetNowPlaying(trackID string) { t.nowPlayingIdx = -1 for i, tr := range t.Tracks {