diff --git a/go.mod b/go.mod index 58a0656..9c0e5a9 100644 --- a/go.mod +++ b/go.mod @@ -44,4 +44,4 @@ require ( honnef.co/go/js/dom v0.0.0-20210725211120-f030747120f2 // indirect ) -replace fyne.io/fyne/v2 v2.2.4 => github.com/dweymouth/fyne/v2 v2.2.5-0.20221220015227-bd9b07f93ac4 +replace fyne.io/fyne/v2 v2.2.4 => github.com/dweymouth/fyne/v2 v2.2.5-0.20221227225053-ae75dfbeb567 diff --git a/go.sum b/go.sum index 712f494..f846f2b 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7h github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dweymouth/fyne/v2 v2.2.5-0.20221220015227-bd9b07f93ac4 h1:Q/+eS7II+u1xjnWHXMgQ9G1pssn/Yi6BoxY6iJCVsfU= -github.com/dweymouth/fyne/v2 v2.2.5-0.20221220015227-bd9b07f93ac4/go.mod h1:MBoGuHzLLSXdQOWFAwWhIhYTEMp33zqtGCReSWhaQTA= +github.com/dweymouth/fyne/v2 v2.2.5-0.20221227225053-ae75dfbeb567 h1:JEBJ5YN74ryKQNW1TgH0GjHkVpgmHMb1oYuz8ZShjY8= +github.com/dweymouth/fyne/v2 v2.2.5-0.20221227225053-ae75dfbeb567/go.mod h1:MBoGuHzLLSXdQOWFAwWhIhYTEMp33zqtGCReSWhaQTA= github.com/dweymouth/go-subsonic v0.0.0-20221214005741-bd8048fa1863 h1:bOWMpFJ9zY839T1EngQ5nxVCiMlatPtpGkg/yHK6szg= github.com/dweymouth/go-subsonic v0.0.0-20221214005741-bd8048fa1863/go.mod h1:fUez6NFiEJiQTZizZ1BThZr5GJXAbigzGYjEPNm4tdI= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= diff --git a/ui/albumgrid.go b/ui/albumgrid.go index e557e8d..caf2f73 100644 --- a/ui/albumgrid.go +++ b/ui/albumgrid.go @@ -2,7 +2,6 @@ package ui import ( "context" - "fmt" "image" "supersonic/backend" "supersonic/ui/widgets" @@ -85,7 +84,6 @@ func (ag *AlbumGrid) doUpdateAlbumCard(albumIdx int, ac *widgets.AlbumCard) { return default: if err == nil { - fmt.Println("setting image") ac.Cover.SetImage(i) ag.Refresh() } @@ -115,6 +113,7 @@ func (a *AlbumGrid) fetchMoreAlbums(count int) { if i == count { a.fetching = false } + a.Refresh() }) } diff --git a/ui/albumspage.go b/ui/albumspage.go index f798a66..8777529 100644 --- a/ui/albumspage.go +++ b/ui/albumspage.go @@ -1,7 +1,6 @@ package ui import ( - "log" "supersonic/backend" "fyne.io/fyne/v2" @@ -29,11 +28,7 @@ func NewAlbumsPage(title string, lm *backend.LibraryManager, im *backend.ImageMa } a.ExtendBaseWidget(a) a.grid = NewAlbumGrid(lm.RecentlyAddedIter(), im.GetAlbumThumbnail) - a.grid.OnPlayAlbum = func(id string) { - if a.OnPlayAlbum != nil { - a.OnPlayAlbum(id) - } - } + a.grid.OnPlayAlbum = a.onPlayAlbum a.gridContainer = container.NewMax(a.grid) return a } @@ -45,12 +40,18 @@ func (a *AlbumsPage) OnSearched(query string) { a.Refresh() return } - log.Printf("searched %s", query) a.searchGrid = NewAlbumGrid(a.lm.SearchIter(query), a.im.GetAlbumThumbnail) + a.searchGrid.OnPlayAlbum = a.onPlayAlbum a.gridContainer.Objects[0] = a.searchGrid a.Refresh() } +func (a *AlbumsPage) onPlayAlbum(albumID string) { + if a.OnPlayAlbum != nil { + a.OnPlayAlbum(albumID) + } +} + func (a *AlbumsPage) CreateRenderer() fyne.WidgetRenderer { a.ExtendBaseWidget(a) return widget.NewSimpleRenderer(a.gridContainer) diff --git a/ui/browsingpane.go b/ui/browsingpane.go index 8645d6e..feba344 100644 --- a/ui/browsingpane.go +++ b/ui/browsingpane.go @@ -6,6 +6,8 @@ import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" ) @@ -21,8 +23,7 @@ type BrowsingPane struct { widget.BaseWidget searchBar *searchField - searchTimer time.Timer - pendingSearch bool + searchTimer *time.Timer cancelPendingSearch context.CancelFunc curPage Page @@ -36,7 +37,49 @@ type blankPage struct { type searchField struct { widget.Entry - height float32 + height float32 + OnTextChanged func(string) +} + +var _ fyne.Tappable = (*clearTextButton)(nil) + +type clearTextButton struct { + widget.Icon + + OnTapped func() +} + +type hspace struct { + widget.BaseWidget + + Width float32 +} + +func newHSpace(w float32) *hspace { + h := &hspace{Width: w} + h.ExtendBaseWidget(h) + return h +} + +func (h *hspace) MinSize() fyne.Size { + return fyne.NewSize(h.Width, 0) +} + +func (h *hspace) CreateRenderer() fyne.WidgetRenderer { + return widget.NewSimpleRenderer(layout.NewSpacer()) +} + +func NewClearTextButton() *clearTextButton { + c := &clearTextButton{} + c.ExtendBaseWidget(c) + c.Resource = theme.SearchIcon() + return c +} + +func (c *clearTextButton) Tapped(*fyne.PointEvent) { + if c.OnTapped != nil { + c.OnTapped() + } } func NewSearchField() *searchField { @@ -45,6 +88,22 @@ func NewSearchField() *searchField { // this is a bit hacky sf.height = widget.NewEntry().MinSize().Height sf.PlaceHolder = "Search" + c := NewClearTextButton() + c.OnTapped = func() { + sf.SetText("") + } + sf.ActionItem = c + sf.OnChanged = func(s string) { + if s == "" { + c.Resource = theme.SearchIcon() + } else { + c.Resource = theme.ContentClearIcon() + } + c.Refresh() + if sf.OnTextChanged != nil { + sf.OnTextChanged(s) + } + } return sf } @@ -56,11 +115,12 @@ func NewBrowsingPane() *BrowsingPane { b := &BrowsingPane{} b.ExtendBaseWidget(b) b.searchBar = NewSearchField() - b.searchBar.OnChanged = b.onSearchTextChanged + b.searchBar.OnTextChanged = b.onSearchTextChanged b.curPage = &blankPage{} - b.searchTimer = *time.NewTimer(0) b.pageContaner = container.NewMax(b.curPage) - b.container = container.NewBorder(container.NewHBox(b.searchBar), nil, nil, nil, b.pageContaner) + b.container = container.NewBorder( + container.NewHBox(newHSpace(15), b.searchBar), + nil, nil, nil, b.pageContaner) return b } @@ -75,30 +135,46 @@ func (b *BrowsingPane) SetPage(p Page) { } func (b *BrowsingPane) onSearchTextChanged(text string) { - b.searchTimer.Reset(300 * time.Millisecond) - if s, ok := b.curPage.(Searchable); ok { - s.OnSearched(text) + if text == "" { + if b.cancelPendingSearch != nil { + b.cancelPendingSearch() + } + b.sendSearch("") } - if !b.pendingSearch { - /* - ctx, cancel := context.WithCancel(context.Background()) - b.cancelPendingSearch = cancel - b.pendingSearch = true - go func(ctx context.Context) { - select { - case <-ctx.Done(): - b.pendingSearch = false - case <-b.searchTimer.C: - if s, ok := b.curPage.(Searchable); ok { - s.OnSearched(b.searchBar.Text) - } - b.pendingSearch = false - } - }(ctx) - */ + if b.searchTimer == nil { + ctx, cancel := context.WithCancel(context.Background()) + b.cancelPendingSearch = cancel + b.searchTimer = time.NewTimer(200 * time.Millisecond) + go func(ctx context.Context, trigger <-chan time.Time) { + select { + case <-ctx.Done(): + b.searchTimer = nil + case <-trigger: + b.sendSearch(b.searchBar.Text) + b.searchTimer = nil + } + }(ctx, b.searchTimer.C) + } else { + b.resetSearchTimer(200 * time.Millisecond) + } +} + +func (b *BrowsingPane) sendSearch(query string) { + if s, ok := b.curPage.(Searchable); ok { + s.OnSearched(query) } } func (b *BrowsingPane) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(b.container) } + +func (b *BrowsingPane) resetSearchTimer(d time.Duration) { + if b.searchTimer == nil { + return + } + if !b.searchTimer.Stop() { + <-b.searchTimer.C + } + b.searchTimer.Reset(d) +}