diff --git a/ui/browsing/artistpage.go b/ui/browsing/artistpage.go index a64dc70..4f67e57 100644 --- a/ui/browsing/artistpage.go +++ b/ui/browsing/artistpage.go @@ -148,6 +148,15 @@ func (a *ArtistPage) OnSongChange(track, lastScrobbledIfAny *mediaprovider.Track } } +var _ Scrollable = (*ArtistPage)(nil) + +func (g *ArtistPage) Scroll(scrollAmt float32) { + if g.activeView == 0 && g.albumGrid != nil { + g.albumGrid.ScrollToOffset(g.albumGrid.GetScrollOffset() + scrollAmt) + g.albumGrid.Refresh() + } +} + func (a *ArtistPage) playArtistRadio() { go a.pm.PlaySimilarSongs(a.artistID) } diff --git a/ui/browsing/artistspage.go b/ui/browsing/artistspage.go index 62c9a1b..ad10493 100644 --- a/ui/browsing/artistspage.go +++ b/ui/browsing/artistspage.go @@ -164,6 +164,13 @@ func createArtistsGridViewModel(artists []*mediaprovider.Artist) []widgets.GridV }) } +var _ Scrollable = (*ArtistsPage)(nil) + +func (a *ArtistsPage) Scroll(scrollAmt float32) { + a.grid.ScrollToOffset(a.grid.GetScrollOffset() + scrollAmt) + a.grid.Refresh() +} + func (a *ArtistsPage) CreateRenderer() fyne.WidgetRenderer { return widget.NewSimpleRenderer(a.container) } diff --git a/ui/browsing/browsingpane.go b/ui/browsing/browsingpane.go index 01c7d27..fc275b6 100644 --- a/ui/browsing/browsingpane.go +++ b/ui/browsing/browsingpane.go @@ -30,10 +30,17 @@ type Searchable interface { SearchWidget() fyne.Focusable } +// Pages with selection should implement this interface to receive Ctrl+A events type CanSelectAll interface { SelectAll() } +// Pages that have one main scrollable view should implement this interface +// to receive callbacks from window-level keyboard scrolling (up/down) +type Scrollable interface { + Scroll(amount float32) +} + type CanShowNowPlaying interface { OnSongChange(song, lastScrobbledIfAny *mediaprovider.Track) } @@ -169,6 +176,18 @@ func (b *BrowsingPane) SelectAll() { } } +func (b *BrowsingPane) ScrollUp() { + if s, ok := b.curPage.(Scrollable); ok { + s.Scroll(-75) + } +} + +func (b *BrowsingPane) ScrollDown() { + if s, ok := b.curPage.(Scrollable); ok { + s.Scroll(75) + } +} + func (b *BrowsingPane) doSetPage(p Page) bool { if b.curPage != nil && b.curPage.Route() == p.Route() { return false diff --git a/ui/browsing/favoritespage.go b/ui/browsing/favoritespage.go index 8866218..6ef4d26 100644 --- a/ui/browsing/favoritespage.go +++ b/ui/browsing/favoritespage.go @@ -37,7 +37,7 @@ type FavoritesPage struct { nowPlayingID string pendingViewSwitch bool - grid *widgets.GridView + albumGrid *widgets.GridView gridState *widgets.GridViewState searchGridState *widgets.GridViewState artistGrid *widgets.GridView @@ -63,13 +63,13 @@ func NewFavoritesPage(cfg *backend.FavoritesPageConfig, pool *util.WidgetPool, c a.createHeader(0) iter := widgets.NewGridViewAlbumIterator(mp.IterateAlbums("", a.filter)) if g := pool.Obtain(util.WidgetTypeGridView); g != nil { - a.grid = g.(*widgets.GridView) - a.grid.Placeholder = myTheme.AlbumIcon - a.grid.Reset(iter) + a.albumGrid = g.(*widgets.GridView) + a.albumGrid.Placeholder = myTheme.AlbumIcon + a.albumGrid.Reset(iter) } else { - a.grid = widgets.NewGridView(iter, a.im, myTheme.AlbumIcon) + a.albumGrid = widgets.NewGridView(iter, a.im, myTheme.AlbumIcon) } - a.contr.ConnectAlbumGridActions(a.grid) + a.contr.ConnectAlbumGridActions(a.albumGrid) if cfg.InitialView == "Artists" { a.toggleBtns.SetActivatedButton(1) a.onShowFavoriteArtists() @@ -77,7 +77,7 @@ func NewFavoritesPage(cfg *backend.FavoritesPageConfig, pool *util.WidgetPool, c a.toggleBtns.SetActivatedButton(2) a.onShowFavoriteSongs() } else { // Albums view - a.createContainer(a.grid) + a.createContainer(a.albumGrid) } return a } @@ -128,11 +128,11 @@ func restoreFavoritesPage(saved *savedFavoritesPage) *FavoritesPage { state = saved.searchGridState } if g := a.pool.Obtain(util.WidgetTypeGridView); g != nil { - a.grid = g.(*widgets.GridView) - a.grid.Placeholder = myTheme.AlbumIcon - a.grid.ResetFromState(state) + a.albumGrid = g.(*widgets.GridView) + a.albumGrid.Placeholder = myTheme.AlbumIcon + a.albumGrid.ResetFromState(state) } else { - a.grid = widgets.NewGridViewFromState(state) + a.albumGrid = widgets.NewGridViewFromState(state) } a.toggleBtns.SetActivatedButton(saved.activeToggleBtn) @@ -141,12 +141,28 @@ func restoreFavoritesPage(saved *savedFavoritesPage) *FavoritesPage { } else if saved.activeToggleBtn == 2 { a.onShowFavoriteSongs() } else { - a.createContainer(a.grid) + a.createContainer(a.albumGrid) } return a } +var _ Scrollable = (*FavoritesPage)(nil) + +func (a *FavoritesPage) Scroll(amount float32) { + var grid *widgets.GridView + switch a.toggleBtns.ActivatedButtonIndex() { + case 0: // albums + grid = a.albumGrid + case 1: // artists + grid = a.artistGrid + default: + return + } + grid.ScrollToOffset(grid.GetScrollOffset() + amount) + grid.Refresh() +} + func (a *FavoritesPage) Route() controller.Route { return controller.FavoritesRoute() } @@ -163,7 +179,7 @@ func (a *FavoritesPage) Reload() { a.doSearchAlbums(a.searchText) } else { iter := a.mp.IterateAlbums("", a.filter) - a.grid.Reset(widgets.NewGridViewAlbumIterator(iter)) + a.albumGrid.Reset(widgets.NewGridViewAlbumIterator(iter)) } if a.tracklistCtr != nil || a.artistGrid != nil { go func() { @@ -213,12 +229,12 @@ func (a *FavoritesPage) Save() SavedPage { activeToggleBtn: a.toggleBtns.ActivatedButtonIndex(), } if a.searchText != "" { - sf.searchGridState = a.grid.SaveToState() + sf.searchGridState = a.albumGrid.SaveToState() } else { - sf.gridState = a.grid.SaveToState() + sf.gridState = a.albumGrid.SaveToState() } - a.grid.Clear() - a.pool.Release(util.WidgetTypeGridView, a.grid) + a.albumGrid.Clear() + a.pool.Release(util.WidgetTypeGridView, a.albumGrid) if a.artistGrid != nil { a.artistGrid.Clear() a.pool.Release(util.WidgetTypeGridView, a.artistGrid) @@ -240,7 +256,7 @@ func (a *FavoritesPage) SearchWidget() fyne.Focusable { func (a *FavoritesPage) OnSearched(query string) { if query == "" { - a.grid.ResetFromState(a.gridState) + a.albumGrid.ResetFromState(a.gridState) a.searchGridState = nil } else { a.doSearchAlbums(query) @@ -269,17 +285,17 @@ func (a *FavoritesPage) SelectAll() { func (a *FavoritesPage) doSearchAlbums(query string) { if a.searchText == "" { - a.gridState = a.grid.SaveToState() + a.gridState = a.albumGrid.SaveToState() } iter := widgets.NewGridViewAlbumIterator(a.mp.SearchAlbums(query, a.filter)) - a.grid.Reset(iter) + a.albumGrid.Reset(iter) } func (a *FavoritesPage) onShowFavoriteAlbums() { a.cfg.InitialView = "Albums" // save setting a.searcher.Entry.Show() a.filterBtn.Show() - a.container.Objects[0] = a.grid + a.container.Objects[0] = a.albumGrid a.Refresh() } diff --git a/ui/browsing/gridviewpage.go b/ui/browsing/gridviewpage.go index 03a6c2b..2fcfccc 100644 --- a/ui/browsing/gridviewpage.go +++ b/ui/browsing/gridviewpage.go @@ -191,6 +191,13 @@ func (g *GridViewPage) SearchWidget() fyne.Focusable { return g.searcher } +var _ Scrollable = (*GridViewPage)(nil) + +func (g *GridViewPage) Scroll(scrollAmt float32) { + g.grid.ScrollToOffset(g.grid.GetScrollOffset() + scrollAmt) + g.grid.Refresh() +} + func (g *GridViewPage) OnSearched(query string) { if query == "" { if g.sortOrder != nil { diff --git a/ui/browsing/playlistspage.go b/ui/browsing/playlistspage.go index 199d19c..22e9000 100644 --- a/ui/browsing/playlistspage.go +++ b/ui/browsing/playlistspage.go @@ -82,6 +82,15 @@ func newPlaylistsPage(contr *controller.Controller, pool *util.WidgetPool, cfg * return a } +var _ Scrollable = (*PlaylistsPage)(nil) + +func (p *PlaylistsPage) Scroll(scrollAmt float32) { + if p.viewToggle.ActivatedButtonIndex() == 1 && p.gridView != nil { + p.gridView.ScrollToOffset(p.gridView.GetScrollOffset() + scrollAmt) + p.gridView.Refresh() + } +} + func (a *PlaylistsPage) load(searchOnLoad bool) { playlists, err := a.mp.GetPlaylists() if err != nil { diff --git a/ui/mainwindow.go b/ui/mainwindow.go index ce17413..8ee90a4 100644 --- a/ui/mainwindow.go +++ b/ui/mainwindow.go @@ -323,6 +323,10 @@ func (m *MainWindow) addShortcuts() { m.Canvas().SetOnTypedKey(func(e *fyne.KeyEvent) { switch e.Name { + case fyne.KeyUp: + m.BrowsingPane.ScrollUp() + case fyne.KeyDown: + m.BrowsingPane.ScrollDown() case fyne.KeyEscape: m.Controller.CloseEscapablePopUp() case fyne.KeySpace: