diff --git a/Sources/TVAnarchy/GoonCollectionView.swift b/Sources/TVAnarchy/GoonCollectionView.swift index bae1efb..f538a71 100644 --- a/Sources/TVAnarchy/GoonCollectionView.swift +++ b/Sources/TVAnarchy/GoonCollectionView.swift @@ -98,6 +98,20 @@ struct GoonCollectionView: View { .background(.quaternary.opacity(0.4), in: RoundedRectangle(cornerRadius: 8)) HStack(spacing: 10) { + Button { selectAllShown() } label: { + Label("All", systemImage: "checkmark.circle") + } + .controlSize(.small) + .disabled(shown.isEmpty || shown.allSatisfy { playlist.isQueued(path: $0.path) }) + .help(filter.isEmpty ? "Select every clip" : "Select every clip matching the filter") + + Button { selectNoneShown() } label: { + Label("None", systemImage: "circle") + } + .controlSize(.small) + .disabled(shown.allSatisfy { !playlist.isQueued(path: $0.path) }) + .help(filter.isEmpty ? "Deselect every clip" : "Deselect every clip matching the filter") + Button { queueAllFresh() } label: { Label("Queue all fresh", systemImage: "plus.rectangle.on.rectangle") } @@ -270,6 +284,21 @@ struct GoonCollectionView: View { } } + /// Queue every currently-shown clip (respects the active filter, so "All" while + /// filtered selects just the matches). + private func selectAllShown() { + for c in shown where !playlist.isQueued(path: c.path) { + playlist.addToQueue(id: c.path, title: c.title, path: c.path) + } + } + + /// Deselect every currently-shown clip (respects the active filter). + private func selectNoneShown() { + for c in shown where playlist.isQueued(path: c.path) { + playlist.removeFromQueue(path: c.path) + } + } + private func clearQueued() { for c in queued { playlist.removeFromQueue(path: c.path) } }