add 'Skip duplicates' option

This commit is contained in:
natilou
2024-05-18 16:03:21 -03:00
parent 1b53695589
commit d939c7f85f
3 changed files with 65 additions and 20 deletions
+24 -2
View File
@@ -12,6 +12,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"time" "time"
"slices"
"github.com/dweymouth/supersonic/backend" "github.com/dweymouth/supersonic/backend"
"github.com/dweymouth/supersonic/backend/mediaprovider" "github.com/dweymouth/supersonic/backend/mediaprovider"
@@ -338,7 +339,27 @@ func (m *Controller) DoAddTracksToPlaylistWorkflow(trackIDs []string) {
go m.App.ServerManager.Server.CreatePlaylist(query, trackIDs) go m.App.ServerManager.Server.CreatePlaylist(query, trackIDs)
} else { } else {
m.App.Config.Application.DefaultPlaylistID = id m.App.Config.Application.DefaultPlaylistID = id
go m.App.ServerManager.Server.AddPlaylistTracks(id, trackIDs) if sp.SkipDuplicates {
var filterTrackIDs []string
go func() {
if selectedPlaylist, err := m.App.ServerManager.Server.GetPlaylist(id); err != nil {
log.Printf("error getting playlist: %s", err.Error())
} else {
var trackIDsInPaylist []string
for _, track := range selectedPlaylist.Tracks{
trackIDsInPaylist = append(trackIDsInPaylist, track.ID)
}
filterTrackIDs = sharedutil.FilterSlice(trackIDs, func(trackID string) bool {
return !slices.Contains(trackIDsInPaylist, trackID)
})
}
m.App.ServerManager.Server.AddPlaylistTracks(id, filterTrackIDs)
}()
} else {
go m.App.ServerManager.Server.AddPlaylistTracks(id, trackIDs)
}
} }
}) })
@@ -346,8 +367,8 @@ func (m *Controller) DoAddTracksToPlaylistWorkflow(trackIDs []string) {
m.haveModal = true m.haveModal = true
min := sp.MinSize() min := sp.MinSize()
height := fyne.Max(min.Height, fyne.Min(min.Height*1.5, m.MainWindow.Canvas().Size().Height*0.7)) height := fyne.Max(min.Height, fyne.Min(min.Height*1.5, m.MainWindow.Canvas().Size().Height*0.7))
pop.Resize(fyne.NewSize(min.Width, height))
sp.SearchDialog.Show() sp.SearchDialog.Show()
pop.Resize(fyne.NewSize(min.Width, height))
pop.Show() pop.Show()
m.MainWindow.Canvas().Focus(sp.GetSearchEntry()) m.MainWindow.Canvas().Focus(sp.GetSearchEntry())
} }
@@ -627,6 +648,7 @@ func (c *Controller) ShowQuickSearch() {
c.haveModal = true c.haveModal = true
min := qs.MinSize() min := qs.MinSize()
height := fyne.Max(min.Height, fyne.Min(min.Height*1.5, c.MainWindow.Canvas().Size().Height*0.7)) height := fyne.Max(min.Height, fyne.Min(min.Height*1.5, c.MainWindow.Canvas().Size().Height*0.7))
qs.SearchDialog.Show()
pop.Resize(fyne.NewSize(min.Width, height)) pop.Resize(fyne.NewSize(min.Width, height))
pop.Show() pop.Show()
c.MainWindow.Canvas().Focus(qs.GetSearchEntry()) c.MainWindow.Canvas().Focus(qs.GetSearchEntry())
+33 -15
View File
@@ -33,22 +33,24 @@ type SearchDialog struct {
list *widget.List list *widget.List
selectedIndex int selectedIndex int
placeholderTitle string
content *fyne.Container content *fyne.Container
OnDismiss func() OnDismiss func()
OnNavigateTo func(mediaprovider.ContentType, string, string) OnNavigateTo func(mediaprovider.ContentType, string, string)
OnSearched func(string) []*mediaprovider.SearchResult OnSearched func(string) []*mediaprovider.SearchResult
OnUpdateSearchResults func(*searchResult, *mediaprovider.SearchResult) OnUpdateSearchResults func(*searchResult, *mediaprovider.SearchResult)
OnInit func() []*mediaprovider.SearchResult OnInit func() ([]*mediaprovider.SearchResult, *widget.Check)
} }
func NewSearchDialog(im util.ImageFetcher, placeholderTitle string, onSearched func(string) []*mediaprovider.SearchResult, onUpdateSearchResult func(*searchResult, *mediaprovider.SearchResult), onInit func() []*mediaprovider.SearchResult) *SearchDialog { func NewSearchDialog(im util.ImageFetcher, placeholderTitle string, onSearched func(string) []*mediaprovider.SearchResult, onUpdateSearchResult func(*searchResult, *mediaprovider.SearchResult), onInit func() ([]*mediaprovider.SearchResult, *widget.Check)) *SearchDialog {
sd := &SearchDialog{ sd := &SearchDialog{
imgSource: im, imgSource: im,
loadingDots: widgets.NewLoadingDots(), loadingDots: widgets.NewLoadingDots(),
OnSearched: onSearched, OnSearched: onSearched,
OnUpdateSearchResults: onUpdateSearchResult, OnUpdateSearchResults: onUpdateSearchResult,
OnInit: onInit, OnInit: onInit,
placeholderTitle: placeholderTitle,
} }
sd.ExtendBaseWidget(sd) sd.ExtendBaseWidget(sd)
@@ -80,17 +82,6 @@ func NewSearchDialog(im util.ImageFetcher, placeholderTitle string, onSearched f
sd.update(sr, result) sd.update(sr, result)
}, },
) )
dismissBtn := widget.NewButton("Close", sd.onDismiss)
title := widget.NewRichText(&widget.TextSegment{Text: placeholderTitle, Style: util.BoldRichTextStyle})
title.Segments[0].(*widget.TextSegment).Style.Alignment = fyne.TextAlignCenter
sd.content = container.NewStack(
container.NewBorder(
container.NewVBox(title, se),
container.NewVBox(widget.NewSeparator(), container.NewHBox(layout.NewSpacer(), dismissBtn)),
nil, nil, sd.list),
container.NewCenter(sd.loadingDots),
)
return sd return sd
} }
@@ -149,20 +140,47 @@ func (sd *SearchDialog) setResults(results []*mediaprovider.SearchResult) {
sd.list.Select(0) sd.list.Select(0)
} }
func (sd *SearchDialog) SetContent(checkBox *widget.Check) {
dismissBtn := widget.NewButton("Close", sd.onDismiss)
title := widget.NewRichText(&widget.TextSegment{Text:sd.placeholderTitle, Style: util.BoldRichTextStyle})
title.Segments[0].(*widget.TextSegment).Style.Alignment = fyne.TextAlignCenter
se := sd.SearchEntry.(fyne.CanvasObject)
if checkBox != nil {
sd.content = container.NewStack(
container.NewBorder(
container.NewVBox(title, se),
container.NewVBox(widget.NewSeparator(), container.NewHBox(checkBox, layout.NewSpacer(), dismissBtn)),
nil, nil, sd.list),
container.NewCenter(sd.loadingDots),
)
} else {
sd.content = container.NewStack(
container.NewBorder(
container.NewVBox(title, se),
container.NewVBox(widget.NewSeparator(), container.NewHBox(layout.NewSpacer(), dismissBtn)),
nil, nil, sd.list),
container.NewCenter(sd.loadingDots),
)
}
}
func (sd *SearchDialog) onInit() { func (sd *SearchDialog) onInit() {
if sd.OnInit == nil { if sd.OnInit == nil {
sd.SetContent(nil)
return return
} }
sd.loadingDots.Start() sd.loadingDots.Start()
var results []*mediaprovider.SearchResult var results []*mediaprovider.SearchResult
res := sd.OnInit() res, checkBox := sd.OnInit()
if len(res) == 0 { if len(res) == 0 {
log.Println("No results") log.Println("No results")
} else { } else {
results = res results = res
} }
sd.SetContent(checkBox)
sd.loadingDots.Stop() sd.loadingDots.Stop()
sd.setResults(results) sd.setResults(results)
} }
func (sd *SearchDialog) onSearched(query string) { func (sd *SearchDialog) onSearched(query string) {
+8 -3
View File
@@ -20,6 +20,7 @@ type SelectPlaylist struct {
mp mediaprovider.MediaProvider mp mediaprovider.MediaProvider
loggedInUser string loggedInUser string
allPlaylists []*mediaprovider.Playlist allPlaylists []*mediaprovider.Playlist
SkipDuplicates bool
} }
func NewSelectPlaylistDialog(mp mediaprovider.MediaProvider, im util.ImageFetcher, loggedInUser string) *SelectPlaylist { func NewSelectPlaylistDialog(mp mediaprovider.MediaProvider, im util.ImageFetcher, loggedInUser string) *SelectPlaylist {
@@ -27,6 +28,7 @@ func NewSelectPlaylistDialog(mp mediaprovider.MediaProvider, im util.ImageFetche
sp := &SelectPlaylist{ sp := &SelectPlaylist{
mp: mp, mp: mp,
loggedInUser: loggedInUser, loggedInUser: loggedInUser,
SkipDuplicates: false,
} }
sd := NewSearchDialog( sd := NewSearchDialog(
im, im,
@@ -39,13 +41,13 @@ func NewSelectPlaylistDialog(mp mediaprovider.MediaProvider, im util.ImageFetche
return sp return sp
} }
func (sp *SelectPlaylist) onInit() []*mediaprovider.SearchResult { func (sp *SelectPlaylist) onInit() ([]*mediaprovider.SearchResult, *widget.Check) {
var results []*mediaprovider.SearchResult var results []*mediaprovider.SearchResult
playlists, err := sp.mp.GetPlaylists() playlists, err := sp.mp.GetPlaylists()
if err != nil { if err != nil {
// TODO: surface this error to user // TODO: surface this error to user
log.Printf("error getting playlists: %s", err.Error()) log.Printf("error getting playlists: %s", err.Error())
return results return results, nil
} }
sp.allPlaylists = sharedutil.FilterSlice(playlists, func(playlist *mediaprovider.Playlist) bool { sp.allPlaylists = sharedutil.FilterSlice(playlists, func(playlist *mediaprovider.Playlist) bool {
return playlist.Owner == sp.loggedInUser return playlist.Owner == sp.loggedInUser
@@ -60,7 +62,10 @@ func (sp *SelectPlaylist) onInit() []*mediaprovider.SearchResult {
ArtistName: playlist.Name, ArtistName: playlist.Name,
}) })
} }
return results skipDuplicatesCheck := widget.NewCheck("Skip duplicates", func(checked bool) {
sp.SkipDuplicates = checked
})
return results, skipDuplicatesCheck
} }
func (sp *SelectPlaylist) onSearched(query string) []*mediaprovider.SearchResult { func (sp *SelectPlaylist) onSearched(query string) []*mediaprovider.SearchResult {