add loading indicator and err/timeout toast to Album and Playlist pages (todo: other pages)

This commit is contained in:
Drew Weymouth
2025-02-14 17:15:03 -03:00
parent e10d167350
commit 3a3774f5b6
5 changed files with 50 additions and 4 deletions
+2
View File
@@ -17,6 +17,7 @@
"All": "All", "All": "All",
"All Tracks": "All Tracks", "All Tracks": "All Tracks",
"Alt. URL": "Alt. URL", "Alt. URL": "Alt. URL",
"An error occurred": "An error occurred",
"An error occurred adding tracks to the playlist": "An error occurred adding tracks to the playlist", "An error occurred adding tracks to the playlist": "An error occurred adding tracks to the playlist",
"An error occurred updating the playlist": "An error occurred updating the playlist", "An error occurred updating the playlist": "An error occurred updating the playlist",
"Are you sure you want to delete the server": "Are you sure you want to delete the server", "Are you sure you want to delete the server": "Are you sure you want to delete the server",
@@ -196,6 +197,7 @@
"Support the project": "Support the project", "Support the project": "Support the project",
"Switch Servers": "Switch Servers", "Switch Servers": "Switch Servers",
"Testing connection": "Testing connection", "Testing connection": "Testing connection",
"The request timed out": "The request timed out",
"Theme": "Theme", "Theme": "Theme",
"Time": "Time", "Time": "Time",
"Title": "Title", "Title": "Title",
+16 -2
View File
@@ -3,6 +3,7 @@ package browsing
import ( import (
"fmt" "fmt"
"log" "log"
"strings"
"github.com/dweymouth/supersonic/backend" "github.com/dweymouth/supersonic/backend"
"github.com/dweymouth/supersonic/backend/mediaprovider" "github.com/dweymouth/supersonic/backend/mediaprovider"
@@ -107,6 +108,7 @@ func newAlbumPage(
container.New(&layout.CustomPaddedLayout{LeftPadding: 15, RightPadding: 15, TopPadding: 15, BottomPadding: 10}, a.header), container.New(&layout.CustomPaddedLayout{LeftPadding: 15, RightPadding: 15, TopPadding: 15, BottomPadding: 10}, a.header),
nil, nil, nil, container.New(&layout.CustomPaddedLayout{LeftPadding: 15, RightPadding: 15, BottomPadding: 15}, a.tracklist)) nil, nil, nil, container.New(&layout.CustomPaddedLayout{LeftPadding: 15, RightPadding: 15, BottomPadding: 15}, a.tracklist))
a.tracklist.SetLoading(true)
go a.load() go a.load()
return a return a
} }
@@ -117,6 +119,7 @@ func (a *AlbumPage) CreateRenderer() fyne.WidgetRenderer {
func (a *AlbumPage) Save() SavedPage { func (a *AlbumPage) Save() SavedPage {
a.disposed = true a.disposed = true
a.tracklist.SetLoading(false)
s := a.albumPageState s := a.albumPageState
s.sort = a.tracklist.Sorting() s.sort = a.tracklist.Sorting()
a.header.page = nil a.header.page = nil
@@ -139,6 +142,7 @@ func (a *AlbumPage) OnSongChange(track mediaprovider.MediaItem, lastScrobbledIfA
} }
func (a *AlbumPage) Reload() { func (a *AlbumPage) Reload() {
a.tracklist.SetLoading(true)
go a.load() go a.load()
} }
@@ -162,13 +166,23 @@ func (a *AlbumPage) Scroll(scrollAmt float32) {
func (a *AlbumPage) load() { func (a *AlbumPage) load() {
album, err := a.mp.GetAlbum(a.albumID) album, err := a.mp.GetAlbum(a.albumID)
if err != nil { if err != nil {
log.Printf("Failed to get album: %s", err.Error()) msg := err.Error()
log.Printf("Failed to get album: %s", msg)
toastMsg := "An error occurred"
if strings.Contains(msg, "deadline exceeded") {
toastMsg = "The request timed out"
}
fyne.Do(func() {
a.tracklist.SetLoading(false)
a.contr.ToastProvider.ShowErrorToast(lang.L(toastMsg))
})
return return
} }
if a.disposed { if a.disposed {
return return
} }
fyne.Do(func() { fyne.Do(func() {
a.tracklist.SetLoading(false)
a.header.Update(album, a.im) a.header.Update(album, a.im)
a.tracklist.Options.ShowDiscNumber = len(album.Tracks) > 0 && album.Tracks[0].DiscNumber != album.Tracks[len(album.Tracks)-1].DiscNumber a.tracklist.Options.ShowDiscNumber = len(album.Tracks) > 0 && album.Tracks[0].DiscNumber != album.Tracks[len(album.Tracks)-1].DiscNumber
a.tracks = album.Tracks a.tracks = album.Tracks
@@ -376,7 +390,7 @@ func formatMiscLabelStr(a *mediaprovider.AlbumWithTracks) string {
} }
yearStr := util.FormatItemDate(a.Date) yearStr := util.FormatItemDate(a.Date)
if y := a.ReissueDate.Year; y != nil && *y > a.YearOrZero() { if y := a.ReissueDate.Year; y != nil && *y > a.YearOrZero() {
yearStr += fmt.Sprintf(" (%s %d)", lang.L("reissued"), util.FormatItemDate(a.ReissueDate)) yearStr += fmt.Sprintf(" (%s %s)", lang.L("reissued"), util.FormatItemDate(a.ReissueDate))
} }
return fmt.Sprintf("%s · %d %s · %s%s", yearStr, a.TrackCount, tracks, discs, util.SecondsToTimeString(float64(a.Duration))) return fmt.Sprintf("%s · %d %s · %s%s", yearStr, a.TrackCount, tracks, discs, util.SecondsToTimeString(float64(a.Duration)))
} }
+16 -1
View File
@@ -3,6 +3,7 @@ package browsing
import ( import (
"fmt" "fmt"
"log" "log"
"strings"
"github.com/dweymouth/supersonic/backend" "github.com/dweymouth/supersonic/backend"
"github.com/dweymouth/supersonic/backend/mediaprovider" "github.com/dweymouth/supersonic/backend/mediaprovider"
@@ -104,6 +105,8 @@ func newPlaylistPage(
a.container = container.NewBorder( a.container = container.NewBorder(
container.New(&layout.CustomPaddedLayout{LeftPadding: 15, RightPadding: 15, TopPadding: 15, BottomPadding: 10}, a.header), container.New(&layout.CustomPaddedLayout{LeftPadding: 15, RightPadding: 15, TopPadding: 15, BottomPadding: 10}, a.header),
nil, nil, nil, container.New(&layout.CustomPaddedLayout{LeftPadding: 15, RightPadding: 15, BottomPadding: 15}, a.tracklist)) nil, nil, nil, container.New(&layout.CustomPaddedLayout{LeftPadding: 15, RightPadding: 15, BottomPadding: 15}, a.tracklist))
a.tracklist.SetLoading(true)
go a.load() go a.load()
return a return a
} }
@@ -114,6 +117,7 @@ func (a *PlaylistPage) CreateRenderer() fyne.WidgetRenderer {
func (a *PlaylistPage) Save() SavedPage { func (a *PlaylistPage) Save() SavedPage {
a.disposed = true a.disposed = true
a.tracklist.SetLoading(false)
p := a.playlistPageState p := a.playlistPageState
p.trackSort = a.tracklist.Sorting() p.trackSort = a.tracklist.Sorting()
p.widgetPool.Release(util.WidgetTypePlaylistPageHeader, a.header) p.widgetPool.Release(util.WidgetTypePlaylistPageHeader, a.header)
@@ -136,6 +140,7 @@ func (a *PlaylistPage) OnSongChange(item mediaprovider.MediaItem, lastScrobbledI
} }
func (a *PlaylistPage) Reload() { func (a *PlaylistPage) Reload() {
a.tracklist.SetLoading(true)
go a.load() go a.load()
} }
@@ -159,7 +164,16 @@ func (a *PlaylistPage) Scroll(scrollAmt float32) {
func (a *PlaylistPage) load() { func (a *PlaylistPage) load() {
playlist, err := a.sm.Server.GetPlaylist(a.playlistID) playlist, err := a.sm.Server.GetPlaylist(a.playlistID)
if err != nil { if err != nil {
log.Printf("Failed to get playlist: %s", err.Error()) msg := err.Error()
log.Printf("Failed to get playlist: %s", msg)
toastMsg := "An error occurred"
if strings.Contains(msg, "deadline exceeded") {
toastMsg = "The request timed out"
}
fyne.Do(func() {
a.tracklist.SetLoading(false)
a.contr.ToastProvider.ShowErrorToast(lang.L(toastMsg))
})
return return
} }
if a.disposed { if a.disposed {
@@ -167,6 +181,7 @@ func (a *PlaylistPage) load() {
} }
renumberTracks(playlist.Tracks) renumberTracks(playlist.Tracks)
fyne.Do(func() { fyne.Do(func() {
a.tracklist.SetLoading(false)
a.tracks = playlist.Tracks a.tracks = playlist.Tracks
a.tracklist.SetTracks(playlist.Tracks) a.tracklist.SetTracks(playlist.Tracks)
a.tracklist.SetNowPlaying(a.nowPlayingID) a.tracklist.SetNowPlaying(a.nowPlayingID)
+13 -1
View File
@@ -102,6 +102,7 @@ type Tracklist struct {
shareMenuItem *fyne.MenuItem shareMenuItem *fyne.MenuItem
songRadioMenuItem *fyne.MenuItem songRadioMenuItem *fyne.MenuItem
infoMenuItem *fyne.MenuItem infoMenuItem *fyne.MenuItem
loadingDots *LoadingDots
container *fyne.Container container *fyne.Container
} }
@@ -199,17 +200,28 @@ func NewTracklist(tracks []*mediaprovider.Track, im *backend.ImageManager, useCo
t.OnReorderTracks(t.SelectedTrackIDs(), insertPos) t.OnReorderTracks(t.SelectedTrackIDs(), insertPos)
} }
} }
t.container = container.NewBorder(t.hdr, nil, nil, nil, t.list) t.loadingDots = NewLoadingDots()
t.container = container.NewBorder(t.hdr, nil, nil, nil,
container.NewStack(t.list, container.NewCenter(t.loadingDots)))
return t return t
} }
func (t *Tracklist) Reset() { func (t *Tracklist) Reset() {
t.SetLoading(false)
t.Clear() t.Clear()
t.Options = TracklistOptions{} t.Options = TracklistOptions{}
t.ctxMenu = nil t.ctxMenu = nil
t.SetSorting(TracklistSort{}) t.SetSorting(TracklistSort{})
} }
func (t *Tracklist) SetLoading(loading bool) {
if loading {
t.loadingDots.Start()
} else {
t.loadingDots.Stop()
}
}
func (t *Tracklist) Scroll(amount float32) { func (t *Tracklist) Scroll(amount float32) {
t.list.ScrollToOffset(t.list.GetScrollOffset() + amount) t.list.ScrollToOffset(t.list.GetScrollOffset() + amount)
} }
+3
View File
@@ -29,12 +29,14 @@ func NewTracklistLoader(tracklist *Tracklist, iter mediaprovider.TrackIterator)
} }
t.tracklist.OnTrackShown = t.onTrackShown t.tracklist.OnTrackShown = t.onTrackShown
t.fetching = true t.fetching = true
t.tracklist.SetLoading(true)
go t.loadMoreTracks(25) go t.loadMoreTracks(25)
return &t return &t
} }
// Cancels all asynchronous loads so that they will no longer modify the tracklist. // Cancels all asynchronous loads so that they will no longer modify the tracklist.
func (t *TracklistLoader) Dispose() { func (t *TracklistLoader) Dispose() {
t.tracklist.SetLoading(false)
t.disposed.Store(true) t.disposed.Store(true)
t.tracklist.OnTrackShown = nil t.tracklist.OnTrackShown = nil
} }
@@ -71,6 +73,7 @@ func (t *TracklistLoader) loadMoreTracks(num int) {
return return
} }
fyne.Do(func() { fyne.Do(func() {
t.tracklist.SetLoading(false)
t.tracklist.AppendTracks(t.trackBuffer) t.tracklist.AppendTracks(t.trackBuffer)
t.len += len(t.trackBuffer) t.len += len(t.trackBuffer)
}) })