From 17df4d780e5df9f4fd0284075562797e4b20726e Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Tue, 31 Oct 2023 18:11:23 -0700 Subject: [PATCH] more WIP --- backend/mediaprovider/subsonic/searchall.go | 12 +++++-- ui/browsing/browsingpane.go | 5 +-- ui/controller/controller.go | 26 ++++++++++++++ ui/dialogs/quicksearch.go | 40 +++++++++++++++++---- ui/mainwindow.go | 8 ++--- 5 files changed, 75 insertions(+), 16 deletions(-) diff --git a/backend/mediaprovider/subsonic/searchall.go b/backend/mediaprovider/subsonic/searchall.go index edcbc55..69534ea 100644 --- a/backend/mediaprovider/subsonic/searchall.go +++ b/backend/mediaprovider/subsonic/searchall.go @@ -91,6 +91,8 @@ func mergeResults( for _, al := range searchResult.Album { results = append(results, &mediaprovider.SearchResult{ Type: mediaprovider.ContentTypeAlbum, + ID: al.ID, + CoverID: al.CoverArt, Name: al.Name, ArtistName: getNameString(al.Artist, al.Artists), Size: al.SongCount, @@ -99,15 +101,19 @@ func mergeResults( for _, ar := range searchResult.Artist { results = append(results, &mediaprovider.SearchResult{ - Type: mediaprovider.ContentTypeArtist, - Name: ar.Name, - Size: ar.AlbumCount, + Type: mediaprovider.ContentTypeArtist, + ID: ar.ID, + CoverID: ar.CoverArt, + Name: ar.Name, + Size: ar.AlbumCount, }) } for _, tr := range searchResult.Song { results = append(results, &mediaprovider.SearchResult{ Type: mediaprovider.ContentTypeTrack, + ID: tr.ID, + CoverID: tr.CoverArt, Name: tr.Title, ArtistName: getNameString(tr.Artist, tr.Artists), Size: tr.Duration, diff --git a/ui/browsing/browsingpane.go b/ui/browsing/browsingpane.go index d551dec..21559fa 100644 --- a/ui/browsing/browsingpane.go +++ b/ui/browsing/browsingpane.go @@ -64,7 +64,7 @@ type BrowsingPane struct { container *fyne.Container } -func NewBrowsingPane(app *backend.App) *BrowsingPane { +func NewBrowsingPane(app *backend.App, controller *controller.Controller) *BrowsingPane { b := &BrowsingPane{app: app} b.ExtendBaseWidget(b) b.home = widget.NewButtonWithIcon("", theme.HomeIcon(), b.GoHome) @@ -81,13 +81,14 @@ func NewBrowsingPane(app *backend.App) *BrowsingPane { p.ShowAtPosition(fyne.NewPos(b.Size().Width-p.MinSize().Width+4, b.navBtnsContainer.MinSize().Height+theme.Padding())) }) + quickSearchBtn := widget.NewButtonWithIcon("", theme.SearchIcon(), controller.ShowQuickSearch) b.settingsMenu = fyne.NewMenu("") b.navBtnsContainer = container.NewHBox() b.container = container.NewBorder(container.New( &layouts.MaxPadLayout{PadLeft: -5, PadRight: -5}, container.New(layouts.NewLeftMiddleRightLayout(0), container.NewHBox(b.home, b.back, b.forward, b.reload), b.navBtnsContainer, - container.NewHBox(layout.NewSpacer(), b.settingsBtn))), + container.NewHBox(layout.NewSpacer(), quickSearchBtn, b.settingsBtn))), nil, nil, nil, b.pageContainer) b.updateHistoryButtons() return b diff --git a/ui/controller/controller.go b/ui/controller/controller.go index 541eb7a..3e2cc67 100644 --- a/ui/controller/controller.go +++ b/ui/controller/controller.go @@ -483,6 +483,32 @@ func (c *Controller) ShowSettingsDialog(themeUpdateCallbk func(), themeFiles map pop.Show() } +func (c *Controller) ShowQuickSearch() { + qs := dialogs.NewQuickSearch(c.App.ServerManager.Server, c.App.ImageManager) + pop := widget.NewModalPopUp(qs, c.MainWindow.Canvas()) + qs.OnDismiss = func() { + pop.Hide() + c.doModalClosed() + } + qs.OnNavigateTo = func(contentType mediaprovider.ContentType, id string) { + pop.Hide() + c.doModalClosed() + switch contentType { + case mediaprovider.ContentTypeAlbum: + c.NavigateTo(AlbumRoute(id)) + case mediaprovider.ContentTypeArtist: + c.NavigateTo(ArtistRoute(id)) + case mediaprovider.ContentTypeTrack: + // TODO + case mediaprovider.ContentTypePlaylist: + c.NavigateTo(PlaylistRoute(id)) + case mediaprovider.ContentTypeGenre: + c.NavigateTo(GenreRoute(id)) + } + } + pop.Show() +} + func (c *Controller) trySetPasswordAndConnectToServer(server *backend.ServerConfig, password string) error { if err := c.App.ServerManager.SetServerPassword(server, password); err != nil { log.Printf("error setting keyring credentials: %v", err) diff --git a/ui/dialogs/quicksearch.go b/ui/dialogs/quicksearch.go index d15034f..67399b0 100644 --- a/ui/dialogs/quicksearch.go +++ b/ui/dialogs/quicksearch.go @@ -2,6 +2,7 @@ package dialogs import ( "image" + "log" "sync" "fyne.io/fyne/v2" @@ -18,7 +19,10 @@ import ( type QuickSearch struct { widget.BaseWidget - mp *mediaprovider.MediaProvider + OnDismiss func() + OnNavigateTo func(mediaprovider.ContentType, string) + + mp mediaprovider.MediaProvider im *backend.ImageManager resultsMutex sync.RWMutex @@ -29,7 +33,7 @@ type QuickSearch struct { content *fyne.Container } -func NewQuickSearch(mp *mediaprovider.MediaProvider, im *backend.ImageManager) *QuickSearch { +func NewQuickSearch(mp mediaprovider.MediaProvider, im *backend.ImageManager) *QuickSearch { q := &QuickSearch{ mp: mp, im: im, @@ -57,25 +61,42 @@ func NewQuickSearch(mp *mediaprovider.MediaProvider, im *backend.ImageManager) * ) title := widget.NewRichText(&widget.TextSegment{Text: "Quick Search", Style: boldStyle}) title.Segments[0].(*widget.TextSegment).Style.Alignment = fyne.TextAlignCenter - q.content = container.NewVBox( - title, - container.NewBorder(searchEntry, nil, nil, nil, q.list), - ) + q.content = container.NewBorder( + container.NewVBox(title, searchEntry), nil, nil, nil, q.list) return q } func (q *QuickSearch) onSearched(query string) { + var results []*mediaprovider.SearchResult + if query != "" { + if res, err := q.mp.SearchAll(query, 20); err != nil { + log.Printf("Error searching: %s", err.Error()) + } else { + results = res + } + } + q.resultsMutex.Lock() + q.searchResults = results + q.resultsMutex.Unlock() + q.list.Refresh() } func (q *QuickSearch) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(q.content) } +func (q *QuickSearch) MinSize() fyne.Size { + return fyne.NewSize(500, 350) +} + type quickSearchResult struct { widget.BaseWidget // parent *QuickSearch + id string + contentType mediaprovider.ContentType + imageLoader backend.ThumbnailLoader image *widgets.ImagePlaceholder @@ -88,7 +109,7 @@ type quickSearchResult struct { func newQuickSearchResult(im *backend.ImageManager) *quickSearchResult { qs := &quickSearchResult{ - image: widgets.NewImagePlaceholder(myTheme.AlbumIcon, 64), + image: widgets.NewImagePlaceholder(myTheme.AlbumIcon, 50), title: widget.NewLabel(""), secondary: widget.NewRichText(), } @@ -107,6 +128,11 @@ func (q *quickSearchResult) Update(result *mediaprovider.SearchResult) { if result == nil { return } + if q.contentType == result.Type && q.id == result.ID { + return // nothing to do + } + q.id = result.ID + q.contentType = result.Type q.image.CenterIcon = placeholderIconForContentType(result.Type) q.imageLoader.Load(result.CoverID) q.title.SetText(result.Name) diff --git a/ui/mainwindow.go b/ui/mainwindow.go index 765cbd4..3a2842c 100644 --- a/ui/mainwindow.go +++ b/ui/mainwindow.go @@ -53,10 +53,9 @@ type MainWindow struct { func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, app *backend.App, size fyne.Size) MainWindow { m := MainWindow{ - App: app, - Window: fyneApp.NewWindow(displayAppName), - BrowsingPane: browsing.NewBrowsingPane(app), - theme: theme.NewMyTheme(&app.Config.Theme, configdir.LocalConfig(appName, "themes")), + App: app, + Window: fyneApp.NewWindow(displayAppName), + theme: theme.NewMyTheme(&app.Config.Theme, configdir.LocalConfig(appName, "themes")), } m.theme.NormalFont = app.Config.Application.FontNormalTTF @@ -71,6 +70,7 @@ func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, MainWindow: m.Window, App: app, } + m.BrowsingPane = browsing.NewBrowsingPane(app, m.Controller) m.Router = browsing.NewRouter(app, m.Controller, m.BrowsingPane) // inject controller dependencies m.Controller.NavHandler = m.Router.NavigateTo