Skip to content

Save queue as playlist and improve queue edit mode#300

Open
cacuscacus wants to merge 6 commits into
sozercan:mainfrom
cacuscacus:feature/save-queue-as-playlist
Open

Save queue as playlist and improve queue edit mode#300
cacuscacus wants to merge 6 commits into
sozercan:mainfrom
cacuscacus:feature/save-queue-as-playlist

Conversation

@cacuscacus

Copy link
Copy Markdown
Contributor

Pull Request: Save Queue as Playlist & Queue Edit Improvements

Summary

Adds the ability to save the current playback queue as a new private playlist, plus several queue edit-mode fixes and UI polish: per-row removal for duplicate songs, a remove-duplicates action, icon-only footer controls with tooltips, and a layout fix for misaligned queue rows with long titles.

Type of Change

  • New feature (non-breaking change that adds functionality)
  • Bug fix (non-breaking change that fixes an issue)
  • UI/UX improvement

Features

Save Queue to Playlist

  • New Save to Playlist action in the queue edit panel footer (icon: text.badge.plus)
  • Opens an NSAlert sheet to name the playlist
  • Creates a private playlist via existing playlist/create API, seeding all queue videoIds in order
  • Updates library caches and notifies LibraryMutationBroadcaster (same pattern as song context menu “Create Playlist…”)
  • Accessibility ID: queueView.saveToPlaylistButton

Remove Duplicates

  • New header button in queue edit mode (icon: arrow.triangle.merge)
  • Tooltip: Remove Duplicates: delete repeated songs from the queue and keep the first occurrence of each.
  • Enabled only when queueHasDuplicateEntries is true; faded when inactive but still hoverable for the tooltip
  • Keeps the first occurrence of each videoId; realigns currentIndex if the playing entry was a later duplicate
  • Accessibility ID: queueView.removeDuplicatesButton

Queue Footer UI (Edit Mode)

  • Footer actions are icon-only with hover tooltips (Undo, Redo, Shuffle, Save to Playlist, Clear)
  • Layout: Undo + Redo grouped on the left; Shuffle, Save, and Clear distributed across remaining width
  • Clear remains red; disabled states use reduced opacity

Bug Fixes

Remove only the selected queue row (duplicates)

Problem: Deleting one instance of a duplicated song could remove every copy in the queue.

Fix:

  • Added removeFromQueue(at:) — removes by index, not videoId or shared entry ID
  • Side panel and popup queue UI now pass row index for context menu, swipe, and remove actions
  • removeFromQueue(entryIDs:) removes by index (highest first) for batch safety

Misaligned queue rows (long titles)

Problem: Rows with long titles (e.g. featured artist lists) could shift left, overlapping the index number and thumbnail.

Fix:

  • Replaced horizontal NSStackView cell layout with pinned Auto Layout (fixed leading index + thumbnail, fixed trailing duration/like/badge, truncating middle text)
  • Enabled table cell reuse via makeView(withIdentifier:)
  • Normalize row view frames after swipe-to-remove feedback and drag operations
  • clipsToBounds on cell to prevent visual bleed

API / Service Changes

Area Change
SongActionsHelper saveQueueAsPlaylist(songs:title:client:)
PlayerService+Queue queueHasDuplicateEntries, removeFromQueue(at:), removeDuplicateQueueEntries()
YTMusicClient No new endpoints — uses existing playlist/create

Files Changed

Sources/Kaset/Services/Player/PlayerService+Queue.swift
Sources/Kaset/Views/QueueSidePanelView.swift
Sources/Kaset/Views/QueueTableCellView.swift
Sources/Kaset/Views/QueueView.swift
Sources/Kaset/Views/SharedViews/SongActionsHelper.swift
Sources/Kaset/Utilities/AccessibilityIdentifiers.swift
Tests/KasetTests/PlayerServiceQueueTests.swift

Testing

Automated

swift test --filter PlayerServiceQueueTests

New/updated tests:

  • removeFromQueueAtIndexRemovesSingleDuplicate
  • removeDuplicateQueueEntriesKeepsFirstOccurrence
  • queueHasDuplicateEntries

Manual

  • Build queue with 5+ songs; Save to Playlist → name → verify playlist in Library
  • Add same song 2–3 times; remove one row → only that position removed
  • With duplicates present, click Remove Duplicates → only first occurrences kept
  • Hover footer/header icons → tooltips appear (including when disabled)
  • Scroll queue with long titles → thumbnails and index numbers stay aligned
  • Partial swipe-to-remove then cancel → rows stay aligned

Build

swift build
KASET_SIGNING=adhoc ./Scripts/build-app.sh debug

Install to /Applications (use ditto, not cp -r, because of Sparkle symlinks):

ditto .build/app/Kaset.app /Applications/Kaset.app

Checklist

  • Uses existing playlist/create API (no guessed endpoints)
  • No secrets/cookies in code or docs
  • Unit tests added for queue duplicate behavior
  • Accessibility identifiers for new buttons
  • swiftlint --strict && swiftformat . run before submit
  • Full swift test --skip KasetUITests run before submit

Branch

feature/save-queue-as-playlist

Suggested PR Title

Save queue as playlist and improve queue edit mode (dedupe, alignment, icon footer)

Prompt Request (for reviewers)

Add a "Save to Playlist" button in queue edit mode that saves the full queue via playlist/create. Fix queue removal so deleting one duplicate only removes that row. Add a header "Remove Duplicates" control. Make footer actions icon-only with tooltips and fix misaligned rows for long song titles in the AppKit queue table.

- Introduced a new button to save the current queue as a private playlist.
- Implemented dialog for playlist name input and success/error alerts.
- Updated AccessibilityIdentifiers to include the new button identifier.
- Enhanced SongActionsHelper with a method to create a playlist from the queue.
- Added functionality to check for duplicate entries in the queue.
- Implemented methods to remove entries from the queue by index and to remove later duplicates while keeping the first occurrence.
- Updated QueueSidePanelView to include a button for removing duplicate songs.
- Adjusted accessibility identifiers to accommodate the new button.
- Modified tests to validate the new queue management features, including removal of duplicates and checking for duplicate entries.
…lView

- Introduced a new reusable QueueFooterIconButton component to streamline button creation for queue actions.
- Updated QueueFooterActions to utilize QueueFooterIconButton for Undo, Redo, Shuffle, Save to Playlist, and Clear Queue functionalities.
- Enhanced accessibility and help text for each button to improve user experience.
…mproved UI responsiveness

- Added `normalizeVisibleRowFrames` method to `DraggableTableView` to reset row views after drag operations, ensuring consistent visual alignment.
- Updated `QueueListControllerRepresentable` to call `normalizeVisibleRowFrames` during data reload and drag session end.
- Refactored `QueueTableCellView` layout to improve view hierarchy and added static constants for layout dimensions, enhancing maintainability and readability.
- Improved handling of row view frames to prevent misalignment during interactions.
- Simplified the process of saving the current queue as a private playlist by moving the logic from SongActionsHelper to PlayerService.
- Updated QueueFooterActions to streamline the save playlist action, removing unnecessary parameters.
- Enhanced the queue duplicate check by using a more concise syntax.
- Removed the outdated saveQueueAsPlaylist method from SongActionsHelper to improve code clarity and maintainability.
- Added a private method `waitForSuggestionFetch` to streamline the waiting process for search suggestion queries during tests.
- Updated the `editingAfterSubmittedSuggestionReenablesAutocomplete` test to utilize the new method, improving readability and reliability of the test execution.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant