From 50a915c57b3511f0158772805e9d36535505235c Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Mon, 6 Jul 2026 17:48:34 -0500 Subject: feat(music): fancy GUI player with hero, cover art, and bar (phase 3) Phase 3 is the fancy visual layer from the prototype. In a graphical frame with cj/music-fancy-ui on, the player draws a now-playing hero (cover image, a serif amber title, a subtitle, and a progress bar) with thumbnailed serif rows below it. A TTY frame, or the toggle off, falls back to phase 1's plain text. The progress bar had a rendering but no data source. I added cj/music--mpv-get-property, which does an IPC round-trip that reads mpv's reply, so a file's bar fills from percent-pos. The old cj/music--mpv-command only sent commands and threw the reply away. A stream has no duration, so it shows "on air". The bar redraws on a ~1s timer that runs only across a playing span and skips when the buffer isn't visible. I split cj/music--header-text into shared playlist and controls pieces with a text-versus-fancy dispatcher, so the two render paths build from one place and can't drift. The hero replaces the Current line when a track plays. Rows gain a cover thumbnail and a serif name. Cover art comes from phase 2's non-blocking cj/music-art--for-track. A separate idle-timer pre-warm fetches the real art off the render path, so a slow favicon host never freezes playback start. The serif family defaults to the nov reading view's, and the amber comes from the themed warning face so the dupre theme owns it. The block-bar renderer has Normal, Boundary, and Error tests. The images, faces, and the bar advancing are a live check. The full suite is green. --- tests/test-music-config--bar-string.el | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/test-music-config--bar-string.el (limited to 'tests') diff --git a/tests/test-music-config--bar-string.el b/tests/test-music-config--bar-string.el new file mode 100644 index 00000000..bb6ac96f --- /dev/null +++ b/tests/test-music-config--bar-string.el @@ -0,0 +1,50 @@ +;;; test-music-config--bar-string.el --- Tests for the block progress bar -*- coding: utf-8; lexical-binding: t; -*- +;; +;; Author: Craig Jennings +;; +;;; Commentary: +;; Unit tests for `cj/music--bar-string': render a WIDTH-cell block bar from a +;; filled-cell count (from `cj/music--bar-fill'), or an "on air" marker when the +;; fill is `indeterminate' (a live stream with no duration). Face-carrying +;; text; the tests assert the rendered length and content, not the faces. +;; +;;; Code: + +(require 'ert) + +(defvar-keymap cj/custom-keymap :doc "Stub keymap for testing") + +(let ((emms-dir (car (file-expand-wildcards + (expand-file-name "elpa/emms-*" user-emacs-directory))))) + (when emms-dir (add-to-list 'load-path emms-dir))) + +(require 'emms) +(require 'music-config) + +(ert-deftest test-music-config--bar-string-normal-half () + "Normal: 10 of 20 cells filled renders a 20-cell bar." + (let ((s (substring-no-properties (cj/music--bar-string 10 20)))) + (should (= (length s) 20)) + (should (= (cl-count ?█ s) 10)) + (should (= (cl-count ?░ s) 10)))) + +(ert-deftest test-music-config--bar-string-boundary-empty () + "Boundary: zero fill is all empty cells." + (let ((s (substring-no-properties (cj/music--bar-string 0 20)))) + (should (= (cl-count ?█ s) 0)) + (should (= (cl-count ?░ s) 20)))) + +(ert-deftest test-music-config--bar-string-boundary-full () + "Boundary: full fill is all filled cells." + (let ((s (substring-no-properties (cj/music--bar-string 20 20)))) + (should (= (cl-count ?█ s) 20)) + (should (= (cl-count ?░ s) 0)))) + +(ert-deftest test-music-config--bar-string-indeterminate-on-air () + "Error/indeterminate: a stream renders an on-air marker, not a bar." + (let ((s (substring-no-properties (cj/music--bar-string 'indeterminate 20)))) + (should (string-match-p "on air" s)) + (should (= (cl-count ?█ s) 0)))) + +(provide 'test-music-config--bar-string) +;;; test-music-config--bar-string.el ends here -- cgit v1.2.3