ML-176: requirements

This commit is contained in:
Claudio Ortolina
2026-05-10 14:39:03 +01:00
parent d4b30a93dc
commit cc0d97b160
3 changed files with 208 additions and 0 deletions
@@ -0,0 +1,41 @@
---
id: ML-176
title: "Presto: add search application with on-screen keyboard"
status: To Do
assignee: []
created_date: "2026-05-10 13:34"
updated_date: "2026-05-10 13:36"
labels:
- presto
- search
- feature
milestone: m-0
dependencies:
- ML-176.1
- ML-176.2
priority: medium
---
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
Add a search feature to the Presto application that lets users type a query on an on-screen QWERTY keyboard, search the collection via a new API query parameter, and browse results reusing the existing record list and detail views.
The app is unified with the existing "Records On This Day" calendar: boot shows a splash screen with two entry points — "Search Collection" and "Today's Records".
<!-- SECTION:DESCRIPTION:END -->
## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 Splash screen on boot shows 'Search Collection' and 'Today's Records' entry points
- [ ] #2 User can search the collection by typing on an on-screen QWERTY keyboard and tapping OK
- [ ] #3 Search results display as a scrollable list of records with cover art, title, artist, format, and year
- [ ] #4 Tapping a search result opens the record detail view (same as day view detail)
- [ ] #5 Back navigation is context-aware: returns to search results from search detail, to day view from day detail
- [ ] #6 Existing 'Records On This Day' calendar flow is unchanged
- [ ] #7 GET /api/v1/collection accepts optional q parameter for FTS5 full-text search
- [ ] #8 Empty query on API returns all records (backward compatible)
<!-- AC:END -->
@@ -0,0 +1,52 @@
---
id: ML-176.1
title: "API: accept search query parameter on GET /api/v1/collection"
status: To Do
assignee: []
created_date: "2026-05-10 13:35"
labels:
- api
- backend
- collection
milestone: m-0
dependencies: []
references:
- lib/music_library/records/search.ex (FTS5 search implementation)
- lib/music_library_web/controllers/collection_json.ex (response format)
modified_files:
- lib/music_library_web/controllers/collection_controller.ex
parent_task_id: ML-176
priority: medium
---
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
Extend the existing `GET /api/v1/collection` endpoint to accept an optional `q` query parameter for full-text search.
When `q` is present and non-empty, pass it to `Collection.search_records/2` instead of the current empty-string default. When absent or empty, preserve existing behavior (return all collection records).
The existing FTS5 search in `Records.Search` handles the query — no new search logic is needed. It searches across all indexed fields (title, artists, genres) and supports the `artist:`, `album:`, etc. structured syntax, though the Presto client will only send plain text.
**Response format**: unchanged — the existing `CollectionJSON.index/1` already returns `{total, limit, offset, records}` with all fields the Presto needs.
**Key decisions** (from user):
- Collection-only scope (purchased_at IS NOT NULL) — already the default for this endpoint
- Alphabetical ordering — already the default
- Plain text query — passed as-is to FTS5
- Always returns paginated (limit/offset) — existing behavior
<!-- SECTION:DESCRIPTION:END -->
## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 GET /api/v1/collection returns all records when q is absent (existing behavior unchanged)
- [ ] #2 GET /api/v1/collection?q=beatles returns only records matching FTS5 query for 'beatles'
- [ ] #3 GET /api/v1/collection?q= returns all records (empty string treated as no query)
- [ ] #4 GET /api/v1/collection?q=beatles&limit=5&offset=0 respects pagination with search
- [ ] #5 Response format matches existing schema: {total, limit, offset, records} with all record fields
- [ ] #6 Controller test covers: no q param, empty q, populated q, q with no matches, q with pagination
<!-- AC:END -->
@@ -0,0 +1,115 @@
---
id: ML-176.2
title: "Presto: add splash screen, search views, and on-screen keyboard"
status: To Do
assignee: []
created_date: "2026-05-10 13:35"
labels:
- presto
- search
- micropython
milestone: m-0
dependencies: []
references:
- presto/AGENTS.md (constraints and patterns)
- presto/README.md (API contract)
modified_files:
- presto/records_on_the_day.py
parent_task_id: ML-176
priority: medium
---
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
Refactor `presto/records_on_the_day.py` into a unified app with a splash screen, search capability, and the existing calendar. All work is in the single MicroPython file.
## New states
- `STATE_HOME` (new, default on boot/wake)
- `STATE_SEARCH_INPUT` (new — search box + on-screen keyboard)
- `STATE_SEARCH_RESULTS` (new — results list, reuses day-view rendering)
- `STATE_MONTH` / `STATE_DAY` / `STATE_RECORD` (existing, unchanged logic)
## Splash screen (STATE_HOME)
- Two large touch targets: "Search Collection" and "Today's Records"
- "Today's Records" → transitions to existing `STATE_MONTH` / today's records flow
- "Search Collection" → transitions to `STATE_SEARCH_INPUT`
- On boot and display wake: always show `STATE_HOME`
## On-screen keyboard (part of STATE_SEARCH_INPUT)
- 3-row QWERTY layout: qwertyuiop / asdfghjkl / zxcvbnm
- Bottom row: [123 toggle] [space] [⌫ backspace] [OK]
- Numbers keyboard: 1234567890 / symbols row / [ABC toggle] [space] [⌫] [OK]
- Space and ⌫ are shared between both layouts
- Lowercase only, no shift/caps
- OK button disabled (dimmed) when query is empty
- Each key is a rounded rectangle, touch-mapped to append/delete chars
- Visual feedback on key press (brief highlight)
- Query buffer displayed in a text field area above the keyboard, max ~50 chars
## Search triggering
- User types query, presses OK
- OK calls `fetch_search_results(query)` → API
- Transitions to `STATE_SEARCH_RESULTS`
## Search results (STATE_SEARCH_RESULTS)
- Reuses existing `_draw_record_list()`, scroll, and row rendering from day view
- Header shows "Search: <query>" with Back button
- Back returns to `STATE_SEARCH_INPUT` (preserving query so user can refine)
- Tapping a record → `STATE_RECORD` (detail view, unchanged)
- Back from detail → returns to search results
- Empty results: "No records found" full-screen message
- Error: "Could not reach server" with retry-on-tap (same as day view)
- 20 results per page, no infinite scroll
## API client
- New `fetch_search_results(query)` function
- Calls `GET /api/v1/collection?q=<url-encoded-query>&limit=20`
- Parses `{total, records, ...}` response
- Returns `(records_list, error_flag)` tuple (same shape as `fetch_records`)
## Navigation state
- Track previous state to know where "Back" in detail view should go
- Detail Back → search results when entered from search
- Detail Back → day view when entered from day
- Month view and search views both have "Back to Home"
## Constraints
- Must reuse existing record row rendering (`_draw_record_row`), detail view (`draw_record_detail`), thumbnail fetching, WiFi, NTP, display sleep logic
- Scroll performance rules from AGENTS.md still apply
- Memory: no large buffers, keep GC pressure low
<!-- SECTION:DESCRIPTION:END -->
## Acceptance Criteria
<!-- AC:BEGIN -->
- [ ] #1 On boot, splash screen shows with 'Search Collection' and 'Today's Records' buttons
- [ ] #2 Tapping 'Today's Records' opens the existing month calendar (unchanged behavior)
- [ ] #3 Tapping 'Search Collection' opens search input view with on-screen QWERTY keyboard
- [ ] #4 Keyboard: tapping letter keys builds query string shown in input field
- [ ] #5 Keyboard: backspace removes last character
- [ ] #6 Keyboard: 123/ABC toggle switches between QWERTY and numbers keyboard layouts
- [ ] #7 Keyboard: OK button is visually disabled (dimmed) when query is empty
- [ ] #8 Keyboard: OK button triggers API search when query is non-empty
- [ ] #9 Search results display using same record row layout as day view (cover, title, artist, format, year)
- [ ] #10 Search results: Back button returns to search input view with query preserved
- [ ] #11 Search results: tapping a record opens detail view
- [ ] #12 Detail view Back returns to search results when entered from search
- [ ] #13 Detail view Back returns to day view when entered from day
- [ ] #14 Empty results show 'No records found' full-screen message
- [ ] #15 API error shows 'Could not reach server' with retry-on-tap
- [ ] #16 Display sleep/wake always returns to splash screen
- [ ] #17 Scroll in search results works identically to day view scroll
- [ ] #18 Keyboard renders correctly at 720×720: all keys visible and tappable
- [ ] #19 Back-to-Home navigation available from month view and search views
<!-- AC:END -->