Skip to content

feat: pin the community playlist to the top of the sidebar - #426

Merged
LargeModGames merged 3 commits into
mainfrom
feat/community-playlist-sidebar-pin
Aug 7, 2026
Merged

LargeModGames merged 3 commits into
mainfrom
feat/community-playlist-sidebar-pin

Conversation

@LargeModGames

@LargeModGames LargeModGames commented Aug 7, 2026 •

Copy link
Copy Markdown
Owner

Summary

Pins the "spotatui community" playlist to the top of the Spotify playlists sidebar so people can open the shared, Discord-curated playlist in one keystroke. Toggleable (default on) via a Settings row and a one-time first-run prompt that tells people how to add songs (the /queue command in the spotatui Discord). It hides itself automatically once you follow the playlist, so it never double-shows. Also moves "+ Add Playlist" to the top of the sidebar and makes that row mouse-clickable (it was keyboard-only before).

Testing

  • cargo fmt --all: clean
  • cargo clippy --no-default-features --features telemetry -- -D warnings: clean
  • cargo test --no-default-features --features telemetry: 562 passed
  • cargo check --features all-sources,cover-art: clean
  • cargo clippy --features all-sources,cover-art -- -D warnings: clean

Additional notes

  • Represented as a PlaylistFolderItem::CommunityPin variant, injected only at display time (never persisted), so the compiler enforces handling at every match site.
  • Prompt state persists in state.yml (community_pin_prompt_shown); the pin and prompt only appear when Spotify is the active source and you don't already follow the playlist.
  • Adds a CHANGELOG entry under Unreleased.
  • UI change; screenshots to follow.

💬 Questions or want to chat with other contributors? Join the spotatui Discord.

Summary by CodeRabbit

  • New Features
    • Added a curated community Spotify playlist to the sidebar.
    • Added a first-launch prompt with options to keep, hide, or dismiss the playlist.
    • Added a setting to enable or disable the community playlist pin.
    • Added a “+ Add Playlist” row at the top of the sidebar, with keyboard and mouse support.
    • Automatically hides the community playlist after it is followed.

Adds a pinned spotatui community entry at the top of the Spotify playlists sidebar that opens the shared playlist the Discord /queue bot fills. It is toggleable (default on) with a Settings row and a one-time first-run prompt that points people to /queue in Discord, and it hides itself once you follow the playlist. Also moves the Add Playlist button to the top of the sidebar and makes that row mouse-clickable, which it was not before.
@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c076be3-fa33-4717-a093-7c0517c5f4ad

📥 Commits

Reviewing files that changed from the base of the PR and between c108a82 and c4e3db1.

📒 Files selected for processing (2)
  • src/core/app.rs
  • src/infra/network/library.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/infra/network/library.rs
  • src/core/app.rs

📝 Walkthrough

Walkthrough

Adds a configurable Spotify community playlist pin. The pin uses a synthetic sidebar row, appears after the add-playlist row, opens the playlist, and hides after following. A first-launch prompt records its state and supports keep, hide, and dismiss actions.

Changes

Community playlist pin

Layer / File(s) Summary
Pin contracts and persisted settings
src/core/app.rs, src/core/plugin_api.rs, src/core/state.rs, src/core/user_config.rs
Adds the synthetic playlist row, prompt routes, configuration flag, and persisted prompt state.
Sidebar visibility and rendering
src/core/app.rs, src/tui/ui/library.rs, CHANGELOG.md
Shows the pin only for the Spotify root when enabled and unfollowed. Places it after the add-playlist row and documents the feature.
Playlist selection and row mapping
src/core/app.rs, src/infra/network/library.rs, src/tui/handlers/playlist.rs, src/tui/handlers/mouse.rs
Adjusts keyboard, mouse, deletion, unfollow, and restored-selection handling for synthetic rows and the leading add-playlist row.
First-launch prompt flow
src/infra/network/library.rs, src/tui/handlers/*, src/tui/runner.rs, src/tui/ui/*
Triggers and renders the prompt. Enter and Esc keep the setting. H disables it. Each action records that the prompt was shown.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SpotifyRefresh
  participant App
  participant Sidebar
  participant User
  participant CommunityPinPrompt
  SpotifyRefresh->>App: refresh playlists
  App->>App: check source, setting, follow state, and prompt state
  App->>Sidebar: insert CommunityPin after + Add Playlist
  App->>CommunityPinPrompt: open first-launch prompt when conditions match
  User->>CommunityPinPrompt: choose H, Enter, or Esc
  CommunityPinPrompt->>App: update setting and prompt state
  App->>Sidebar: redraw playlist rows
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title uses the required feat: prefix, clearly describes the main change, and uses a concise imperative subject.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/community-playlist-sidebar-pin
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/community-playlist-sidebar-pin

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/core/app.rs`:
- Around line 3417-3438: Update get_selected_playlist_id so the raw
self.playlists fallback subtracts the visible CommunityPin offset when the pin
is shown and playlist_folder_items is empty, matching the display ordering used
by get_playlist_display_items and the library UI. Preserve existing handling for
the add row, pin, folders, and normal display items. Add a regression test with
the pin visible, empty playlist_folder_items, and multiple raw playlists,
asserting a row after the pin returns the corresponding playlist id.

In `@src/tui/runner.rs`:
- Around line 774-777: Update the back-key handler in runner.rs to add an
ActiveBlock::CommunityPinPrompt branch alongside AnnouncementPrompt, invoking
handlers::community_pin_prompt::handler(Key::Esc, &mut app) instead of falling
through to app.pop_navigation_stack().
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f625b7d9-1868-474f-a2e2-658158a658d4

📥 Commits

Reviewing files that changed from the base of the PR and between c41ca2b and c108a82.

📒 Files selected for processing (14)
  • CHANGELOG.md
  • src/core/app.rs
  • src/core/plugin_api.rs
  • src/core/state.rs
  • src/core/user_config.rs
  • src/infra/network/library.rs
  • src/tui/handlers/community_pin_prompt.rs
  • src/tui/handlers/mod.rs
  • src/tui/handlers/mouse.rs
  • src/tui/handlers/playlist.rs
  • src/tui/runner.rs
  • src/tui/ui/library.rs
  • src/tui/ui/mod.rs
  • src/tui/ui/popups.rs

Comment thread src/core/app.rs
Comment thread src/tui/runner.rs
Comment on lines +774 to +777
ActiveBlock::CommunityPinPrompt => {
ui::draw_main_layout(f, &app);
ui::draw_community_pin_prompt(f, &app);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Confirm back_key_clears_playlist_filter's scope and
# community_pin_prompt::handler's match arms, to validate the fix above.
rg -n -A20 'fn back_key_clears_playlist_filter' src/tui/runner.rs
fd community_pin_prompt.rs src/tui/handlers --exec cat -n {}
rg -n -B2 -A10 'fn handler\(key: Key, app: &mut App\)' src/tui/handlers/community_pin_prompt.rs

Repository: LargeModGames/spotatui

Length of output: 6038


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== runner outline relevant regions =="
wc -l src/tui/runner.rs
rg -n -A8 -B8 'ActiveBlock::CommunityPinPrompt|ActiveBlock::AnnouncementPrompt|app.user_config.keys.back|Back|handle_app' src/tui/runner.rs | sed -n '1,220p'

echo "== handlers module imports/exports =="
cat -n src/tui/handlers/mod.rs | sed -n '1,120p'

echo "== network finish_playlists_fetch =="
wg='700,720'
if command -v sed >/dev/null; then
  sed -n '700,720p' src/infra/network/library.rs | cat -n
fi

echo "== app field persistence =="
rg -n -B3 -A3 'community_pin_prompt_shown|save_runtime_state|PersistedRuntimeState' src/core src/lib.rs src/tui -g '*.rs' | sed -n '1,180p'

echo "== deterministic path check in runner source =="
python3 - <<'PY'
from pathlib import Path
p=Path("src/tui/runner.rs")
s=p.read_text()
checks={
    "runner_imports_handlers_community_pin_prompt":"handlers::community_pin_prompt::handler" in s,
    "runner_imports_handlers_module":"crate::tui::handlers" in s,
    "community_pin_prompt_handler_mentions_back":any("ActiveBlock::CommunityPinPrompt" in line and s.split("\n").index(line) for line in s.splitlines()),
}
# Extract back-key block lines approximately
lines=s.splitlines(keepends=True)
for i,l in enumerate(lines,1):
    if "app.user_config.keys.back" in l:
        start=max(1,i-8); end=min(len(lines),i+28)
        print(f"\n-- back-key block around line {i} --")
        for n in range(start,end+1):
            print(f"{n}: {lines[n-1]}", end="")
        break
print(checks)
PY

Repository: LargeModGames/spotatui

Length of output: 21516


Add a CommunityPinPrompt branch to the back-key handler.

Esc works because handlers::handle_app routes it to handlers::community_pin_prompt::handler(Key::Esc, app), which marks the prompt shown and persists it. The back key is handled earlier in src/tui/runner.rs and falls through to app.pop_navigation_stack() for ActiveBlock::CommunityPinPrompt, so the prompt closes without the shown flag and can reappear on the next playlist refresh, follow, or unfollow. Add a dedicated branch next to AnnouncementPrompt that calls handlers::community_pin_prompt::handler(Key::Esc, &mut app).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tui/runner.rs` around lines 774 - 777, Update the back-key handler in
runner.rs to add an ActiveBlock::CommunityPinPrompt branch alongside
AnnouncementPrompt, invoking handlers::community_pin_prompt::handler(Key::Esc,
&mut app) instead of falling through to app.pop_navigation_stack().

Corrects two issues from review: the raw-page fallback in get_selected_playlist_id now offsets for the pinned row, so a selection past the pin maps to the right playlist while playlist_folder_items is still loading; and the first-run prompt is marked shown when it is pushed rather than only on dismiss, so it cannot reappear after a dismissal that bypasses the handler.
@LargeModGames
LargeModGames merged commit b3cf30d into main Aug 7, 2026
16 checks passed
@LargeModGames
LargeModGames deleted the feat/community-playlist-sidebar-pin branch August 7, 2026 13:06
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