Summary
As MeedyaDL approaches the multi-service rollout (#100 EPIC → M8 BBC iPlayer → M9 Spotify → M10 YouTube), the queue / download / settings UX needs polish that scales beyond the current Apple-Music-only assumption. This issue captures a researched, codebase-verified design proposal inspired by OnTheSpot (a similar multi-service music downloader, PyQt6-based) — borrowing its cleanest patterns while deliberately rejecting its rougher edges.
Methodology: 11 specific polish recommendations + 6 net-new from a completeness pass were each verified against the current codebase (file paths, existing helpers, effort estimate) before landing in this issue. Each item below carries its concrete "files to change" pointer and effort tier.
Revision (2026-06-07): Following user feedback, original anti-pattern 1 ("cap visible queue columns at 4-5") was replaced with a more nuanced responsive-column-visibility rule that allows up to ~8 columns at wide widths but tier-hides them at narrower widths. New Phase 1 item 0 ("Responsive column system") captures the framework. Other recommendations (per-row platform icon, art thumb, status pill etc.) now land into that column system rather than as ad-hoc row additions.
What OnTheSpot does well (worth borrowing)
- Service column per row — small platform icon + name on every queue / search row, instantly identifying which service the item came from
- Album-art thumbnails — ~48×48 cover art on every row, making 100+ row queues visually scannable
- Many columns of useful data — codec / bitrate / format / type / progress, all available for quick scan when window is wide
- Unified Accounts table in Settings — one place that shows every connected service with auth status, account tier, last-validated timestamp
- Status text in a dedicated column — single source of truth, not buried inside a coloured icon
- Action buttons grouped at far right — consistent action vocabulary across rows (copy / retry / locate / open / delete)
What OnTheSpot does poorly (deliberately rejecting)
- Generic Qt aesthetic — flat stock buttons, no hover affordance, no micro-interactions
- Status badges as plain text rather than coloured pills
- Fixed column density at every window width — all 8 columns visible even when window is narrow, becoming unreadable
- Conflating service brand colour with download status (deuteranopia users can't tell "Spotify queued" from "Spotify failed")
- Settings as a single dense form with no progressive disclosure
Anti-patterns to avoid (load-bearing — preserve in future Claude sessions)
- Use responsive column visibility, never fixed density at all widths. The queue may surface up to ~8 columns at wide widths (album art, platform icon, Artist — Album — Track, status pill, progress, speed/ETA, codec/quality, file path, actions), but visibility must tier at Tailwind breakpoints so a sidebar-collapsed narrow window stays scannable. Tier 1 (essentials: art, identifier, status, actions) always visible; subsequent tiers reveal at
md / lg / xl / 2xl. Provide a hover-tooltip or click-to-expand affordance so users on narrow windows can still see hidden data on demand. Don't dump everything onto the row at every width.
- Don't make service brand colours the primary status signal. Status pills (recommendation 4) and brand colours (recommendation 7) must use different hue ranges — green / amber / red for state, brand colour for the service icon only.
- Don't auto-open service-specific Settings tabs on URL paste. Becomes hostile mid-flow on a 50-URL batch. Surface a preview card under the textarea (recommendation 9) instead.
- Don't gate basic queue functionality behind multi-select mode. Selection should augment per-row actions, never replace them.
Phase 1 — Strongly recommend, can land pre-M8 (Apple-Music-only era still benefits)
These don't depend on multi-service code landing first.
0. Responsive column visibility system (foundation — lands first)
Build the queue row as a CSS-Grid-based layout with up to ~8 columns whose visibility tiers at Tailwind breakpoints. Subsequent Phase 1 items (per-row platform icon, art thumb, status pill, codec, file path…) all slot into this system rather than each adding ad-hoc width.
Tier hierarchy (always-visible at the top, least-essential hides first):
| Tier |
Visibility from |
Columns |
| Tier 1 |
always (≥ 320px) |
Album art thumbnail · Artist — Album — Track · Status pill · Action buttons (hover-revealed) |
| Tier 2 |
md (≥ 768px) |
Platform / service icon |
| Tier 3 |
lg (≥ 1024px) |
Inline progress bar (during downloads) · Speed / ETA |
| Tier 4 |
xl (≥ 1280px) |
Codec / quality (ALAC, Atmos, 4K HDR) · Content type (Album / Single / Music Video / Playlist) |
| Tier 5 |
2xl (≥ 1536px) |
File path · Submitted-at timestamp · Estimated file size |
Tailwind's default breakpoints (md 768, lg 1024, xl 1280, 2xl 1536) align with typical Tauri-window-on-desktop widths (sidebar-collapsed narrow ~800px → big-monitor maximised ~2400px+). No custom screens config needed — confirmed tailwind.config.js uses defaults.
Click-to-expand affordance: even at narrow widths, the user can click/tap the row to reveal a secondary inline detail panel showing the hidden columns (codec, file path, timestamps, speed/ETA) for that one row. Reuses the existing fallback-warning expandable panel pattern in QueueItem.tsx.
Header row: in tabular mode, render a sticky column-header strip with the same responsive visibility — labels appear/disappear with their columns.
- Files:
- QueueItem.tsx (rewrite layout into
grid with grid-cols-[…] + per-cell hidden md:flex / hidden lg:flex / hidden xl:flex / hidden 2xl:flex classes)
- DownloadQueue.tsx (add sticky column header strip above the virtualised list)
- new
src/components/download/QueueRowExpansion.tsx (click-to-expand secondary panel)
- QueueListVirtualized.tsx (track expanded-row IDs; variable row height when expanded)
- Effort: one-PR medium
- Verdict: strongly recommend (this is the framework all other Phase 1 row work builds on; ship first)
- Cross-ref: anti-pattern 1 — must use this system, not ad-hoc width
1. Per-row platform icon in queue
The detectPlatform() helper + PlatformIcon SVG-cached component already exist in GlobalProgressBar.tsx (lines ~76-87, 99-188) but are scoped to that one file. Surface the same icon in the queue row's Tier 2 column (≥ md), left of the status pill.
- Files: extract
detectPlatform() + PlatformEntry into a new src/lib/platform-config.ts (avoid naming collision with the existing OS-detection usePlatform() hook); slim integration in QueueItem.tsx Tier 2 column
- Effort: one-PR small
- Verdict: strongly recommend (infrastructure proven, removes duplication)
2. Album-art thumbnails on queue rows (Tier 1)
AlbumMetadata already exposes artwork_square_url and artwork_tall_url (apple_music_api.rs lines 237-243), fetched at enqueue via try_fetch_metadata(). URLs are currently consumed only by the animated-artwork service — never exposed to the frontend.
- Files: add
artwork_url: Option<String> to QueueItemStatus in models/download.rs; pass it through in download_queue.rs; mirror in types/index.ts (lines 964-1031); render lazy-loaded <img> ~48×48 in QueueItem.tsx Tier 1 column
- Effort: one-PR small
- Verdict: strongly recommend (pure layering, no new backend capability)
3. Render "Artist — Album — Track" instead of raw URL (Tier 1)
album_name and artist_name already exist on QueueItemStatus (types/index.ts lines 979-982) — populated at enqueue per CLAUDE.md, used in progress-caption.ts formatter for the global progress bar — but QueueItem.tsx line 541 still shows the raw URL. Same metadata, different rendering policy.
- Files: QueueItem.tsx Tier 1 primary identifier column; optionally extract reusable formatter from progress-caption.ts
- Effort: one-PR small
- Verdict: strongly recommend (pure rendering switch, gracefully falls back to URL when metadata absent)
4. Status pills (icon + label inside a coloured rounded-full)
STATE_CONFIG mapping in QueueItem.tsx (lines 205-231) already has icon + colorClass + label — pill rendering already used in the same file for the "Retry without Wrapper" pattern (lines 708-716) and in YouTubeTab.tsx line 38. Trivial swap. Lives in the Tier 1 status column.
- Files: QueueItem.tsx (replace icon-only div with pill in Tier 1 status column); optionally extract
<StatusPill> into src/components/common/
- Effort: one-PR small
- Verdict: strongly recommend
5. Hover-reveal row actions
At 50+ rows, always-visible action icons clutter visual scan. group + group-hover:opacity-100 pattern already used in ActivityLog.tsx line ~330. Tab-focused buttons must remain visible for keyboard a11y — the existing aria-label / title annotations are already in place. Lives in the Tier 1 actions column.
- Files: QueueItem.tsx row container + action button container in Tier 1 actions column
- Effort: one-PR small
- Verdict: strongly recommend
6. Micro-animations (row insert + status transition + expand-row slide)
prefers-reduced-motion is fully wired in globals.css lines 331-340 (suppresses to 0.01ms). Existing transition-colors / transition-all duration-300 patterns already in QueueItem + ProgressBar. Safe to add a row-insert fade-slide, a status-transition icon swap, and a click-to-expand slide-down animation (paired with recommendation 0) without touching motion-sensitive users.
- Files: new
@keyframes in globals.css around line 260-270; conditional class on QueueItem row; track newly-inserted IDs in QueueListVirtualized.tsx
- Effort: one-PR medium
- Verdict: strongly recommend (perfect low-risk test case for polish animations)
7. WCAG-AA-verified service brand colour tokens
Per CLAUDE.md, MeedyaDL has 4 platform themes + a11y-high-contrast.css + a11y-colour-blind.css. No --service-* tokens exist today. Add tokens (5 services × 4 themes × 2 modes ≈ 40 declarations) with WCAG AA contrast verified against each background, plus CVD-safe variants in a11y-colour-blind.css.
8. Undo for destructive queue operations
Clear All / Abort All / multi-row Cancel are all immediate and irreversible — accidental clicks on a 200-row queue are real frustration. Snapshot affected items in memory; surface a 5-second toast: "Cleared 47 items · Undo". Undo re-enqueues in original order with mv_companion_override etc. preserved. Toast respects notification_auto_dismiss_seconds.
9. Per-service "what gets downloaded" preview card on Download page
Different services produce wildly different artifacts (Apple Music: lyrics + animated art + companion codecs; BBC iPlayer: video + subtitles; Spotify: Ogg + lyrics). Surface a small accent card under the URL textarea once detectService(url) resolves, listing what this service will download with the current settings + per-line links to the controlling settings.
- Files: DownloadForm.tsx; reuse
useSettingsField hook
- Effort: small
- Verdict: strongly recommend (sets correct user expectations across services)
Phase 2 — Strongly recommend, but tie to multi-service landing (M8+)
These need at least one non-Apple-Music service to be functional before they land cleanly.
10. Service filter chips above queue
service field already exists on QueueItemStatus (types/index.ts line 970). Status-filter chip pattern already implemented in DownloadQueue.tsx lines 1139-1160 with toggle buttons, counts, reset logic — direct copy-paste shape. Conditional rendering: show only when ≥4 distinct services present in queue to avoid clutter pre-M8.
- Files: DownloadQueue.tsx (filter row + state + memo extension); ensure backend populates
service field reliably on QueueItemStatus
- Effort: one-PR small
- Verdict: strongly recommend, gated on M8 landing
11. Friendly multi-service empty state on Queue + Download
Both DownloadForm.tsx lines 871-875 and QueueListVirtualized.tsx lines 109-122 have generic empty states today. MEDIA_SERVICE_LABELS constant exists in types/index.ts but is unused in the UI. Multi-service empty state shows enabled-service icons + "Paste a URL or drop a link".
- Files: DownloadForm.tsx, QueueListVirtualized.tsx; optional new
src/components/common/ServiceIconBadge.tsx
- Effort: one-PR medium
- Verdict: recommend, gated on multi-service landing
- Risk: shipping in v1.x with Apple-Music-only would show 5 service icons but only 1 works — user confusion. Either gate behind
enabled_services setting (see recommendation 14) or ship only after M8
12. Unified Settings > Accounts page
Backend PerServiceSettings stubs for AppleMusicSettings / SpotifySettings / YouTubeSettings already exist (settings.rs lines 565-590). Frontend has placeholder SpotifyTab / YouTubeTab / BBCiPlayerTab with "Coming Soon" + @ts-nocheck. CookiesTab (lines 1-1268) holds Apple-Music-specific validation logic that needs to be decomposed into shared utilities before the unified table is viable.
- Files: new
src/components/settings/tabs/AccountsTab.tsx; decompose CookiesTab.tsx into shared validators (StatusBadge, BrowserInstructions, ExpiryWarning); extend settings.rs schema to surface per-service AccountStatus
- Effort: one-PR medium
- Verdict: recommend, defer until at least Spotify (M9) has real integration — otherwise the unified abstraction may need reshaping. Start with the CookiesTab decomposition now so the eventual Accounts work is straightforward.
13. Sidebar per-service connection status strip
Below the sidebar's existing update button: one small dot per configured service, green/amber/red driven by the same preflight checks (check_cookies_before_download, check_wrapper_health, MusicKit token validity). Click opens Settings > Accounts. Amber gently pulses (prefers-reduced-motion respected) when a token is within 7 days of expiry — proactive renewal before a failed download.
- Files: Sidebar.tsx footer; new helper polling existing preflight IPCs; tie into
serviceStatusStore.ts (already staged)
- Effort: medium
- Verdict: recommend, gated on M8+ (one dot for Apple Music pre-M8 is fine but uninteresting)
14. First-launch service picker
Wizard Step 1 becomes "Which services will you use?" — checkboxes per service. Subsequent dependency-install + credential-prompt steps iterate only over selected services. Stores enabled_services: Vec<MediaServiceId> in settings; sidebar filter chips (#10) and connection strip (#13) auto-hide unselected services.
- Files: SetupWizard components; settings schema + migration; sidebar conditional rendering
- Effort: medium
- Verdict: recommend, gated on M8+
Phase 3 — Medium-term polish
15. Cmd/Ctrl+K command palette / cross-store search
A persistent top-of-window search across Queue + History + Library Scan with scope chips (All / Queue / History / Library) and service chips (reuse #10). Results render with the same per-row vocabulary established in #0-3 (responsive columns, platform icon, art thumb, Artist — Album — Track) so users learn one row format everywhere. Reuses @tanstack/react-virtual already in ActivityLog.tsx.
- Effort: medium
- Verdict: recommend (transforms findability once data grows; OnTheSpot's standout pattern that none of the other recommendations replicate)
16. Batch row selection + bulk-actions toolbar
Click-to-select / Shift+click range / Cmd-Ctrl+click toggle. When ≥1 row selected, queue header morphs into a contextual toolbar ("3 selected · Cancel · Retry · Move to top · Export · Clear"). Existing abort_all_downloads IPC (#620) becomes one button on that toolbar instead of a separate red action. Pairs cleanly with #5 (hovering an unselected row reveals individual actions; selection mode supersedes hover).
- Effort: medium
- Verdict: recommend; respect anti-pattern 4 (selection augments, never replaces, single-row actions)
Phase 4 — Defer
17. Sidebar service grouping (Queue → expandable per-service)
Adds virtualizer row-height complexity for marginal benefit over the cheaper filter chips (#10). Wait for user feedback from #100 multi-service rollout to confirm grouping is actually wanted.
Suggested rollout
Recommendation 0 (responsive column system) lands first as the framework — it's the foundation everything else snaps into. Once 0 is in place, recommendations 1-9 fit comfortably across 2-3 small follow-up PRs in the same release window — they don't conflict and don't depend on multi-service code. Bundle as a "queue polish" pre-release tagged 1.10.0-alpha.NN.
Phase 2 work begins as soon as #102 (M8 BBC iPlayer) lands and reuses the column system to drop the platform-icon column into a populated state. Phase 3 sequentially after that. Phase 4 evaluated post-multi-service-launch based on real user feedback.
Related
Summary
As MeedyaDL approaches the multi-service rollout (#100 EPIC → M8 BBC iPlayer → M9 Spotify → M10 YouTube), the queue / download / settings UX needs polish that scales beyond the current Apple-Music-only assumption. This issue captures a researched, codebase-verified design proposal inspired by OnTheSpot (a similar multi-service music downloader, PyQt6-based) — borrowing its cleanest patterns while deliberately rejecting its rougher edges.
Methodology: 11 specific polish recommendations + 6 net-new from a completeness pass were each verified against the current codebase (file paths, existing helpers, effort estimate) before landing in this issue. Each item below carries its concrete "files to change" pointer and effort tier.
What OnTheSpot does well (worth borrowing)
What OnTheSpot does poorly (deliberately rejecting)
Anti-patterns to avoid (load-bearing — preserve in future Claude sessions)
md/lg/xl/2xl. Provide a hover-tooltip or click-to-expand affordance so users on narrow windows can still see hidden data on demand. Don't dump everything onto the row at every width.Phase 1 — Strongly recommend, can land pre-M8 (Apple-Music-only era still benefits)
These don't depend on multi-service code landing first.
0. Responsive column visibility system (foundation — lands first)
Build the queue row as a CSS-Grid-based layout with up to ~8 columns whose visibility tiers at Tailwind breakpoints. Subsequent Phase 1 items (per-row platform icon, art thumb, status pill, codec, file path…) all slot into this system rather than each adding ad-hoc width.
Tier hierarchy (always-visible at the top, least-essential hides first):
md(≥ 768px)lg(≥ 1024px)xl(≥ 1280px)ALAC,Atmos,4K HDR) · Content type (Album/Single/Music Video/Playlist)2xl(≥ 1536px)Tailwind's default breakpoints (
md768,lg1024,xl1280,2xl1536) align with typical Tauri-window-on-desktop widths (sidebar-collapsed narrow ~800px → big-monitor maximised ~2400px+). No customscreensconfig needed — confirmedtailwind.config.jsuses defaults.Click-to-expand affordance: even at narrow widths, the user can click/tap the row to reveal a secondary inline detail panel showing the hidden columns (codec, file path, timestamps, speed/ETA) for that one row. Reuses the existing fallback-warning expandable panel pattern in
QueueItem.tsx.Header row: in tabular mode, render a sticky column-header strip with the same responsive visibility — labels appear/disappear with their columns.
gridwithgrid-cols-[…]+ per-cellhidden md:flex/hidden lg:flex/hidden xl:flex/hidden 2xl:flexclasses)src/components/download/QueueRowExpansion.tsx(click-to-expand secondary panel)1. Per-row platform icon in queue
The
detectPlatform()helper +PlatformIconSVG-cached component already exist in GlobalProgressBar.tsx (lines ~76-87, 99-188) but are scoped to that one file. Surface the same icon in the queue row's Tier 2 column (≥md), left of the status pill.detectPlatform()+PlatformEntryinto a newsrc/lib/platform-config.ts(avoid naming collision with the existing OS-detectionusePlatform()hook); slim integration inQueueItem.tsxTier 2 column2. Album-art thumbnails on queue rows (Tier 1)
AlbumMetadataalready exposesartwork_square_urlandartwork_tall_url(apple_music_api.rs lines 237-243), fetched at enqueue viatry_fetch_metadata(). URLs are currently consumed only by the animated-artwork service — never exposed to the frontend.artwork_url: Option<String>toQueueItemStatusin models/download.rs; pass it through in download_queue.rs; mirror in types/index.ts (lines 964-1031); render lazy-loaded<img>~48×48 in QueueItem.tsx Tier 1 column3. Render "Artist — Album — Track" instead of raw URL (Tier 1)
album_nameandartist_namealready exist onQueueItemStatus(types/index.ts lines 979-982) — populated at enqueue per CLAUDE.md, used inprogress-caption.tsformatter for the global progress bar — butQueueItem.tsxline 541 still shows the raw URL. Same metadata, different rendering policy.4. Status pills (icon + label inside a coloured rounded-full)
STATE_CONFIGmapping in QueueItem.tsx (lines 205-231) already has icon + colorClass + label — pill rendering already used in the same file for the "Retry without Wrapper" pattern (lines 708-716) and inYouTubeTab.tsxline 38. Trivial swap. Lives in the Tier 1 status column.<StatusPill>intosrc/components/common/5. Hover-reveal row actions
At 50+ rows, always-visible action icons clutter visual scan.
group+group-hover:opacity-100pattern already used in ActivityLog.tsx line ~330. Tab-focused buttons must remain visible for keyboard a11y — the existingaria-label/titleannotations are already in place. Lives in the Tier 1 actions column.6. Micro-animations (row insert + status transition + expand-row slide)
prefers-reduced-motionis fully wired in globals.css lines 331-340 (suppresses to0.01ms). Existingtransition-colors/transition-all duration-300patterns already in QueueItem + ProgressBar. Safe to add a row-insert fade-slide, a status-transition icon swap, and a click-to-expand slide-down animation (paired with recommendation 0) without touching motion-sensitive users.@keyframesin globals.css around line 260-270; conditional class on QueueItem row; track newly-inserted IDs inQueueListVirtualized.tsx7. WCAG-AA-verified service brand colour tokens
Per CLAUDE.md, MeedyaDL has 4 platform themes +
a11y-high-contrast.css+a11y-colour-blind.css. No--service-*tokens exist today. Add tokens (5 services × 4 themes × 2 modes ≈ 40 declarations) with WCAG AA contrast verified against each background, plus CVD-safe variants ina11y-colour-blind.css.--service-apple-music/--service-youtube-music/--service-youtube/--service-spotify/--service-bbc-iplayerin base.css, macos.css, windows.css, linux.css, a11y-colour-blind.css; exportSERVICE_BRAND_COLOURSconstant in types/index.ts; register in tailwind.config.js--status-*tokens8. Undo for destructive queue operations
Clear All / Abort All / multi-row Cancel are all immediate and irreversible — accidental clicks on a 200-row queue are real frustration. Snapshot affected items in memory; surface a 5-second toast: "Cleared 47 items · Undo". Undo re-enqueues in original order with
mv_companion_overrideetc. preserved. Toast respectsnotification_auto_dismiss_seconds.downloadStore.ts(snapshot + restore actions);DownloadQueue.tsxtoolbar integration; reuse existing toast system9. Per-service "what gets downloaded" preview card on Download page
Different services produce wildly different artifacts (Apple Music: lyrics + animated art + companion codecs; BBC iPlayer: video + subtitles; Spotify: Ogg + lyrics). Surface a small accent card under the URL textarea once
detectService(url)resolves, listing what this service will download with the current settings + per-line links to the controlling settings.useSettingsFieldhookPhase 2 — Strongly recommend, but tie to multi-service landing (M8+)
These need at least one non-Apple-Music service to be functional before they land cleanly.
10. Service filter chips above queue
servicefield already exists onQueueItemStatus(types/index.ts line 970). Status-filter chip pattern already implemented in DownloadQueue.tsx lines 1139-1160 with toggle buttons, counts, reset logic — direct copy-paste shape. Conditional rendering: show only when ≥4 distinct services present in queue to avoid clutter pre-M8.servicefield reliably onQueueItemStatus11. Friendly multi-service empty state on Queue + Download
Both DownloadForm.tsx lines 871-875 and QueueListVirtualized.tsx lines 109-122 have generic empty states today.
MEDIA_SERVICE_LABELSconstant exists in types/index.ts but is unused in the UI. Multi-service empty state shows enabled-service icons + "Paste a URL or drop a link".src/components/common/ServiceIconBadge.tsxenabled_servicessetting (see recommendation 14) or ship only after M812. Unified Settings > Accounts page
Backend
PerServiceSettingsstubs forAppleMusicSettings/SpotifySettings/YouTubeSettingsalready exist (settings.rs lines 565-590). Frontend has placeholderSpotifyTab/YouTubeTab/BBCiPlayerTabwith "Coming Soon" +@ts-nocheck. CookiesTab (lines 1-1268) holds Apple-Music-specific validation logic that needs to be decomposed into shared utilities before the unified table is viable.src/components/settings/tabs/AccountsTab.tsx; decompose CookiesTab.tsx into shared validators (StatusBadge,BrowserInstructions,ExpiryWarning); extendsettings.rsschema to surface per-serviceAccountStatus13. Sidebar per-service connection status strip
Below the sidebar's existing update button: one small dot per configured service, green/amber/red driven by the same preflight checks (
check_cookies_before_download,check_wrapper_health, MusicKit token validity). Click opens Settings > Accounts. Amber gently pulses (prefers-reduced-motionrespected) when a token is within 7 days of expiry — proactive renewal before a failed download.serviceStatusStore.ts(already staged)14. First-launch service picker
Wizard Step 1 becomes "Which services will you use?" — checkboxes per service. Subsequent dependency-install + credential-prompt steps iterate only over selected services. Stores
enabled_services: Vec<MediaServiceId>in settings; sidebar filter chips (#10) and connection strip (#13) auto-hide unselected services.Phase 3 — Medium-term polish
15. Cmd/Ctrl+K command palette / cross-store search
A persistent top-of-window search across Queue + History + Library Scan with scope chips (All / Queue / History / Library) and service chips (reuse #10). Results render with the same per-row vocabulary established in #0-3 (responsive columns, platform icon, art thumb, Artist — Album — Track) so users learn one row format everywhere. Reuses
@tanstack/react-virtualalready inActivityLog.tsx.16. Batch row selection + bulk-actions toolbar
Click-to-select / Shift+click range / Cmd-Ctrl+click toggle. When ≥1 row selected, queue header morphs into a contextual toolbar ("3 selected · Cancel · Retry · Move to top · Export · Clear"). Existing
abort_all_downloadsIPC (#620) becomes one button on that toolbar instead of a separate red action. Pairs cleanly with #5 (hovering an unselected row reveals individual actions; selection mode supersedes hover).Phase 4 — Defer
17. Sidebar service grouping (Queue → expandable per-service)
Adds virtualizer row-height complexity for marginal benefit over the cheaper filter chips (#10). Wait for user feedback from #100 multi-service rollout to confirm grouping is actually wanted.
Suggested rollout
Recommendation 0 (responsive column system) lands first as the framework — it's the foundation everything else snaps into. Once 0 is in place, recommendations 1-9 fit comfortably across 2-3 small follow-up PRs in the same release window — they don't conflict and don't depend on multi-service code. Bundle as a "queue polish" pre-release tagged
1.10.0-alpha.NN.Phase 2 work begins as soon as #102 (M8 BBC iPlayer) lands and reuses the column system to drop the platform-icon column into a populated state. Phase 3 sequentially after that. Phase 4 evaluated post-multi-service-launch based on real user feedback.
Related