From 1b782d910b0560d0f3e96b4ac641a4afa323e68f Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Wed, 22 Apr 2026 17:31:23 +0100 Subject: [PATCH] ML-142.1: capture task --- ...-and-selection-bar-to-ScrobbleLive.Show.md | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 backlog/tasks/ml-142.1 - Port-Finished-at-picker-and-selection-bar-to-ScrobbleLive.Show.md diff --git a/backlog/tasks/ml-142.1 - Port-Finished-at-picker-and-selection-bar-to-ScrobbleLive.Show.md b/backlog/tasks/ml-142.1 - Port-Finished-at-picker-and-selection-bar-to-ScrobbleLive.Show.md new file mode 100644 index 00000000..777062b4 --- /dev/null +++ b/backlog/tasks/ml-142.1 - Port-Finished-at-picker-and-selection-bar-to-ScrobbleLive.Show.md @@ -0,0 +1,58 @@ +--- +id: ML-142.1 +title: Port Finished at picker and selection bar to ScrobbleLive.Show +status: To Do +assignee: [] +created_date: '2026-04-22 16:30' +labels: + - ui + - scrobble +dependencies: [] +references: + - lib/music_library_web/live/scrobble_live/show.ex + - lib/music_library_web/components/release.ex + - backlog/ml-142/plan.md +parent_task_id: ML-142 +priority: medium +--- + +## Description + + +Bring the `/scrobble/:release_id` page (`MusicLibraryWeb.ScrobbleLive.Show`) up to ML-142 parity for the two affordances that affect scrobbling outcomes: the `Finished at` date/time picker and the pinned selection-bar footer. + +Today the page imports `medium/1` and `scrobble_button_label/1` from `MusicLibraryWeb.Components.Release` — so the per-medium UI stays visually consistent — but reimplements its own `scrobble_release`, `scrobble_medium`, and `scrobble_selected_tracks` handlers, each hard-coding `DateTime.utc_now/0`. There is no picker (users cannot back-date or forward-date a scrobble) and no selection bar (when tracks are selected, the user sees no count/duration summary and the only scrobble affordance is an icon-only header button whose behaviour depends on hidden selection state via `scrobble_button_label/1`). + +`ScrobbleLive.Show` was explicitly called out as out-of-scope in ML-142 — see `backlog/ml-142/plan.md`: "A full sticky-bar + picker port to `ScrobbleLive.Show`. That page uses its own layout (not the sheet) and can be iterated on separately once the LiveComponent pattern is settled." That deferred work is the subject of this task. + +## Out of scope + +- `⋯` overflow menu on this page (Print tracklist for release + per-medium). +- Connect Last.fm dropdown entry — the page already has a top-of-page alert banner for that state. +- Extracting a shared function component or LiveHelper is an implementation decision, not a requirement. Implementer may duplicate or refactor; the acceptance criteria are outcome-based. + +## Reusable pieces the implementer can draw on + +- `MusicLibraryWeb.Components.Release.apply_form_params/3` — already public, already used by this LiveView. +- `MusicLibraryWeb.Components.Release.medium/1` — already imported. +- `MusicLibrary.ScrobbleActivity.scrobble_release/3`, `scrobble_medium/4`, `scrobble_tracks/4` — already used. +- Private helpers in `Release` that may need to be promoted (implementer's choice): `parse_finished_at/1`, `selection_bar/1`, `selected_tracks_summary/2`. +- `scrobble_button_label/1` will likely become unused after AC#8 — remove if so. +- `lib/music_library_web/live_helpers/` pattern (e.g. `record_actions.ex`) is a possible refactor target but not required. + + +## Acceptance Criteria + +- [ ] #1 The page renders a `Finished at` date/time picker in the tracks section header when Last.fm is connected, initialised to the current time at mount +- [ ] #2 The picker has a `Now` reset affordance that resets the value back to the current time +- [ ] #3 `Scrobble release` uses the picker value; no longer calls `DateTime.utc_now/0` directly inside the handler +- [ ] #4 Per-medium `Scrobble disc`/`Scrobble side` uses the picker value; no longer calls `DateTime.utc_now/0` directly inside the handler +- [ ] #5 `Scrobble selected tracks` uses the picker value; no longer calls `DateTime.utc_now/0` directly inside the handler +- [ ] #6 A selection bar renders at the bottom of the tracks section whenever `MapSet.size(@selected_tracks) > 0`, showing track count, medium count (when > 1), aggregate duration, and a `Scrobble selected` button +- [ ] #7 The selection bar is not rendered when no tracks are selected +- [ ] #8 The selection bar stays visible while the tracks list is scrolled on narrow viewports (`position: sticky` or equivalent layout — implementer's choice given this page sits inside `Layouts.app`, not the sheet) +- [ ] #9 The icon-only header scrobble button (which currently toggles via `scrobble_button_label/1`) is replaced by a solid `Scrobble release` button; the selection bar owns the scrobble-selected role +- [ ] #10 All new user-facing strings wrapped in `gettext`; `.pot`/`.po` files regenerated via `mix gettext.extract --merge` +- [ ] #11 LiveView tests cover: picker default state initialised to `utc_now`, picker value propagating to all three scrobble handlers, `reset_to_now` event, selection-bar hidden when no tracks selected, selection-bar shown with correct copy when tracks selected +- [ ] #12 The existing AC#14 regression test (per-medium scrobble works with cross-medium tracks selected, at `test/music_library_web/live/scrobble_live/show_test.exs:115`) continues to pass +