From 1d342bf4136d8fea31ef9e8532a2e26307f91f1e Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sun, 15 Dec 2024 15:52:21 -0800 Subject: [PATCH] ensure clicking anywhere outside tracklists can unselect all --- ui/browsing/albumpage.go | 8 +++++--- ui/browsing/artistpage.go | 12 ++++++------ ui/browsing/browsingpane.go | 7 +++++++ ui/browsing/favoritespage.go | 12 ++++++------ ui/browsing/nowplayingpage.go | 37 +++++++++++++++++------------------ ui/browsing/playlistpage.go | 8 +++++--- ui/browsing/trackspage.go | 16 +++++++++++++++ ui/controller/controller.go | 30 ++++++++++++++++++++-------- ui/mainwindow.go | 31 ++++++++++++++++++++++++++--- 9 files changed, 113 insertions(+), 48 deletions(-) diff --git a/ui/browsing/albumpage.go b/ui/browsing/albumpage.go index 6c14fdcd..c8cd55e9 100644 --- a/ui/browsing/albumpage.go +++ b/ui/browsing/albumpage.go @@ -143,14 +143,16 @@ func (a *AlbumPage) Reload() { go a.load() } -func (a *AlbumPage) Tapped(*fyne.PointEvent) { - a.tracklist.UnselectAll() -} +var _ CanSelectAll = (*AlbumPage)(nil) func (a *AlbumPage) SelectAll() { a.tracklist.SelectAll() } +func (a *AlbumPage) UnselectAll() { + a.tracklist.UnselectAll() +} + var _ Scrollable = (*AlbumPage)(nil) func (a *AlbumPage) Scroll(scrollAmt float32) { diff --git a/ui/browsing/artistpage.go b/ui/browsing/artistpage.go index 53971776..42390d59 100644 --- a/ui/browsing/artistpage.go +++ b/ui/browsing/artistpage.go @@ -110,12 +110,6 @@ func newArtistPage(artistID string, cfg *backend.ArtistPageConfig, pool *util.Wi return a } -func (a *ArtistPage) Tapped(*fyne.PointEvent) { - if a.tracklistCtr != nil { - a.tracklistCtr.Objects[0].(*widgets.Tracklist).UnselectAll() - } -} - var _ CanSelectAll = (*ArtistPage)(nil) func (a *ArtistPage) SelectAll() { @@ -124,6 +118,12 @@ func (a *ArtistPage) SelectAll() { } } +func (a *ArtistPage) UnselectAll() { + if a.tracklistCtr != nil { + a.tracklistCtr.Objects[0].(*widgets.Tracklist).UnselectAll() + } +} + func (a *ArtistPage) Route() controller.Route { return controller.ArtistRoute(a.artistID) } diff --git a/ui/browsing/browsingpane.go b/ui/browsing/browsingpane.go index 8207456d..4c4557a6 100644 --- a/ui/browsing/browsingpane.go +++ b/ui/browsing/browsingpane.go @@ -36,6 +36,7 @@ type Searchable interface { // Pages with selection should implement this interface to receive Ctrl+A events type CanSelectAll interface { SelectAll() + UnselectAll() } // Pages that have one main scrollable view should implement this interface @@ -199,6 +200,12 @@ func (b *BrowsingPane) SelectAll() { } } +func (b *BrowsingPane) UnselectAll() { + if s, ok := b.curPage.(CanSelectAll); ok { + s.UnselectAll() + } +} + func (b *BrowsingPane) ScrollUp() { b.scrollBy(-75) } diff --git a/ui/browsing/favoritespage.go b/ui/browsing/favoritespage.go index 50ed0ddf..f8f9b12a 100644 --- a/ui/browsing/favoritespage.go +++ b/ui/browsing/favoritespage.go @@ -174,12 +174,6 @@ func (a *FavoritesPage) Route() controller.Route { return controller.FavoritesRoute() } -func (a *FavoritesPage) Tapped(*fyne.PointEvent) { - if tr := a.tracklistOrNil(); tr != nil { - tr.UnselectAll() - } -} - func (a *FavoritesPage) Reload() { // reload favorite albums view if a.searchText != "" { @@ -287,6 +281,12 @@ func (a *FavoritesPage) SelectAll() { } } +func (a *FavoritesPage) UnselectAll() { + if a.toggleBtns.ActivatedButtonIndex() == 2 /*songs*/ && a.tracklistCtr != nil { + a.tracklistOrNil().UnselectAll() // can't be nil in this case + } +} + func (a *FavoritesPage) Refresh() { if a.albumGrid != nil { a.albumGrid.ShowSuffix = a.cfg.ShowAlbumYears diff --git a/ui/browsing/nowplayingpage.go b/ui/browsing/nowplayingpage.go index 484c8c8b..0c6eab7c 100644 --- a/ui/browsing/nowplayingpage.go +++ b/ui/browsing/nowplayingpage.go @@ -470,31 +470,30 @@ func (a *NowPlayingPage) OnPlayTimeUpdate(curTime, _ float64, seeked bool) { } } +func (a *NowPlayingPage) currentTracklistOrNil() *widgets.PlayQueueList { + if a.tabs != nil { + + switch a.tabs.SelectedIndex() { + case 0: /*queue*/ + return a.queueList + case 2: /*related*/ + return a.relatedList + } + } + return nil +} + var _ CanSelectAll = (*NowPlayingPage)(nil) func (a *NowPlayingPage) SelectAll() { - if a.tabs == nil { - return - } - switch a.tabs.SelectedIndex() { - case 0: /*queue*/ - a.queueList.SelectAll() - case 2: /*related*/ - a.relatedList.SelectAll() + if l := a.currentTracklistOrNil(); l != nil { + l.SelectAll() } } -var _ fyne.Tappable = (*NowPlayingPage)(nil) - -func (a *NowPlayingPage) Tapped(*fyne.PointEvent) { - if a.tabs == nil { - return - } - switch a.tabs.SelectedIndex() { - case 0: /*queue*/ - a.queueList.UnselectAll() - case 2: /*related*/ - a.relatedList.UnselectAll() +func (a *NowPlayingPage) UnselectAll() { + if l := a.currentTracklistOrNil(); l != nil { + l.UnselectAll() } } diff --git a/ui/browsing/playlistpage.go b/ui/browsing/playlistpage.go index c330961c..3da30c6f 100644 --- a/ui/browsing/playlistpage.go +++ b/ui/browsing/playlistpage.go @@ -139,14 +139,16 @@ func (a *PlaylistPage) Reload() { go a.load() } -func (a *PlaylistPage) Tapped(*fyne.PointEvent) { - a.tracklist.UnselectAll() -} +var _ CanSelectAll = (*PlaylistPage)(nil) func (a *PlaylistPage) SelectAll() { a.tracklist.SelectAll() } +func (a *PlaylistPage) UnselectAll() { + a.tracklist.UnselectAll() +} + var _ Scrollable = (*PlaylistPage)(nil) func (a *PlaylistPage) Scroll(scrollAmt float32) { diff --git a/ui/browsing/trackspage.go b/ui/browsing/trackspage.go index b6d75125..ccc38cac 100644 --- a/ui/browsing/trackspage.go +++ b/ui/browsing/trackspage.go @@ -89,6 +89,18 @@ func (t *TracksPage) Route() controller.Route { return controller.TracksRoute() } +var _ CanSelectAll = (*TracksPage)(nil) + +func (t *TracksPage) SelectAll() { + // deliberate no-op since we don't want to give the impression + // that you can select all tracks from the server, since only + // some of them are actually loaded into the model +} + +func (t *TracksPage) UnselectAll() { + t.currentTracklist().UnselectAll() +} + func (t *TracksPage) Reload() { t.tracklist.Clear() iter := t.mp.IterateTracks("") @@ -161,6 +173,10 @@ func (t *TracksPage) doSearch(query string) { t.Refresh() } +func (t *TracksPage) currentTracklist() *widgets.Tracklist { + return t.container.Objects[0].(*fyne.Container).Objects[0].(*widgets.Tracklist) +} + func (t *TracksPage) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(t.container) } diff --git a/ui/controller/controller.go b/ui/controller/controller.go index 811293f6..89096217 100644 --- a/ui/controller/controller.go +++ b/ui/controller/controller.go @@ -41,14 +41,15 @@ type CurPageFunc func() Route type Controller struct { visualizationData - AppVersion string - App *backend.App - MainWindow fyne.Window - NavHandler NavigationHandler - CurPageFunc CurPageFunc - ReloadFunc func() - RefreshPageFunc func() - SelectAllPageFunc func() + AppVersion string + App *backend.App + MainWindow fyne.Window + NavHandler NavigationHandler + CurPageFunc CurPageFunc + ReloadFunc func() + RefreshPageFunc func() + SelectAllPageFunc func() + UnselectAllPageFunc func() popUpQueueMutex sync.Mutex popUpQueue *widget.PopUp @@ -101,6 +102,19 @@ func (m *Controller) SelectAll() { } } +func (m *Controller) UnselectAll() { + m.popUpQueueMutex.Lock() + if m.popUpQueue != nil && m.popUpQueue.Visible() { + m.popUpQueueList.UnselectAll() + m.popUpQueueMutex.Unlock() + return + } + m.popUpQueueMutex.Unlock() + if m.SelectAllPageFunc != nil { + m.UnselectAllPageFunc() + } +} + func (m *Controller) NavigateTo(route Route) { m.NavHandler(route) } diff --git a/ui/mainwindow.go b/ui/mainwindow.go index ec7fd494..614f0a62 100644 --- a/ui/mainwindow.go +++ b/ui/mainwindow.go @@ -38,7 +38,7 @@ type MainWindow struct { theme *theme.MyTheme haveSystemTray bool alreadyConnected bool // tracks if we have already connected to a server before - container *fyne.Container + content *mainWindowContent // needs to bes shown/hidden when switching between servers based on whether they support radio radioBtn fyne.CanvasObject @@ -68,6 +68,7 @@ func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, m.Controller.CurPageFunc = m.BrowsingPane.CurrentPage m.Controller.RefreshPageFunc = m.BrowsingPane.RefreshPage m.Controller.SelectAllPageFunc = m.BrowsingPane.SelectAll + m.Controller.UnselectAllPageFunc = m.BrowsingPane.UnselectAll if runtime.GOOS == "darwin" { // Fyne will extract out an "About" menu item and @@ -136,8 +137,9 @@ func NewMainWindow(fyneApp fyne.App, appName, displayAppName, appVersion string, m.BrowsingPane.DisableNavigationButtons() m.addShortcuts() - m.container = container.NewBorder(nil, m.BottomPanel, nil, nil, m.BrowsingPane) - m.Window.SetContent(fynetooltip.AddWindowToolTipLayer(m.container, m.Window.Canvas())) + m.content = newMainWindowContent(container.NewBorder(nil, m.BottomPanel, nil, nil, m.BrowsingPane), + m.Controller.UnselectAll) + m.Window.SetContent(fynetooltip.AddWindowToolTipLayer(m.content, m.Window.Canvas())) m.setInitialSize() m.Window.SetCloseIntercept(func() { m.SaveWindowSize() @@ -433,3 +435,26 @@ func (m *MainWindow) SaveWindowSize() { &m.App.Config.Application.WindowWidth, &m.App.Config.Application.WindowHeight) } + +// widget just so we can catch a tap event that doesn't land anywhere else +// and call BrowsingPane.UnselectAll() +type mainWindowContent struct { + widget.BaseWidget + + content fyne.CanvasObject + onTapped func() +} + +func newMainWindowContent(content fyne.CanvasObject, onTapped func()) *mainWindowContent { + w := &mainWindowContent{content: content, onTapped: onTapped} + w.ExtendBaseWidget(w) + return w +} + +func (m *mainWindowContent) CreateRenderer() fyne.WidgetRenderer { + return widget.NewSimpleRenderer(m.content) +} + +func (m *mainWindowContent) Tapped(*fyne.PointEvent) { + m.onTapped() +}