Skip to content

UI: Add features for player controls, lyrics notifications, and widgets - #1003

Draft
SteveZMTstudios wants to merge 21 commits into
FoedusProgramme:betafrom
SteveZMTstudios:feature/stevezmt
Draft

SteveZMTstudios wants to merge 21 commits into
FoedusProgramme:betafrom
SteveZMTstudios:feature/stevezmt

Conversation

@SteveZMTstudios

@SteveZMTstudios SteveZMTstudios commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Card widget — a new responsive home-screen widget family for quick playback control. One provider delivers pill (1×1), circle (2×2 w/ progress ring), card (4×1), medium (4×2) and large (4×4 / wide 5×4) layouts, plus favorite & shuffle actions on wide slots.
  • Notification lyrics — opt-in setting that surfaces the current synced lyric line in both the expanded media notification and the system media session metadata (lockscreen / BT / Android Auto), with the original title+artist preserved as the subtitle line.
  • Swipe cover to switch track on the full player (default enabled); gesture recognition keeps vertical gestures & single-tap behavior intact.
  • Optional rotating cookie play/pause button to match the cover-rotation feel while playing, controlled by a player setting.
  • "Always skip to previous track" behavior — opt-in flag so pressing Previous jumps straight to the last item instead of seeking back to track start, useful for heads-free and hardware-button use cases.
  • Widget favorite action connects through a dedicated playback-service helper so the current item's heart rating and widget state stay in sync across lyric/session updates.
  • Widget resources use Material You system colors on Android 12+ with stable theme-token fallbacks for pre-12 and night mode; default + zh-rCN strings added for all new settings and the widget picker label.

Test

Installed on my phone (android 16):

Screenshot_2026-08-22-19-54-58-26_b783bf344239542886fee7b48fa4b892

and i run it about 3 hours playing music, no crash and any error occured.

Also Windows subsystem of Android:
image

with music3 patch at nift4/media#2, works on Android 6 AVD:

image

And my low-performance platform (Android 8.1 MT6580 1GB RAM):
Screenshot_20260823-010351_Trebuchet

Even my Android 7.1 arm 512MB RAM device MT6572 1.2GHz x2,

Screenshot_20260823-234356

All works fine and stable.

CI Passed:

https://github.com/SteveZMTstudios/Gramophone/actions/runs/32650576403

@nift4

nift4 commented Aug 22, 2026

Copy link
Copy Markdown
Member

Hi, thank you very much for your PR.

To make review easier, please can you split features to have one PR per feature?

@SteveZMTstudios

Copy link
Copy Markdown
Contributor Author

sure im handling

@nift4

nift4 commented Aug 22, 2026

Copy link
Copy Markdown
Member

Please make sure the individual branches are buildable, some currently aren't. Thanks

@SteveZMTstudios

Copy link
Copy Markdown
Contributor Author

still cherrypickin

@SteveZMTstudios

SteveZMTstudios commented Aug 23, 2026 •

Copy link
Copy Markdown
Contributor Author

done.
Although all four branches can be compiled, due to capacity constraints, I only conducted a rigorous test on this comprehensive branch.

If you feel something is out of place, please point it out here. If you are satisfied with these changes, it is a good idea to merge this pull request but not others to avoid possible conflicts.

@nift4

nift4 commented Aug 23, 2026

Copy link
Copy Markdown
Member

Thanks, I will take a look when I have some time.

@SteveZMTstudios
SteveZMTstudios marked this pull request as draft August 23, 2026 07:20

@SteveZMTstudios SteveZMTstudios left a comment •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I am testing tested this change on my device chain to ensure the low_end device performance and old Android sdk compatibility.

Features & fixes:
- Add opt-in inline bracket word-by-word LRC parsing behind experimental setting (bracketWordSync, default off).
- Classify line-end closing timestamps unconditionally as LineEndSyncPoint to avoid fake single-word timings and phantom empty lines.
- Refactor SyntacticLrc.parseLrc with O(1) local line state machine (hasLyricInLine, hadWordSyncInLine, hasSyncPointInLine).
- Ensure lines yielding no words strictly produce null words instead of emptyList to preserve lyric UI highlight.
- Fix candidate score operator precedence for multi-feature lyrics.
- Trigger lyric reloads on bracketWordSync and trim preference changes.
- Actively clear notification lyric on blank/instrumental lines with whitespace placeholder.
- Sanitize lockscreen/OEM lyric export with translation filter and centisecond timestamp deduplication.
- Add 11 regression test cases in LrcUtilsTest covering edge cases and syntax combinations.
Note: corrected file copyright header to SteveZMTstudios (author mistakenly copied Akane Foundation header from template during creation, now corrected).
…to ui/widget

Note: corrected file copyright header to SteveZMTstudios (author mistakenly copied Akane Foundation header from template during creation, now corrected).
Note: corrected file copyright header to SteveZMTstudios (author mistakenly copied Akane Foundation header from template during creation, now corrected).
…void reflection crash

- Remove unsupported reflection setInt(setGravity) on TextViews in large layout preventing VIEW_MODE_ERROR crash
- Update responsive breakpoint mapping:
  * Circle: (40, 40) -> pillSingle, (100, 40) -> pill, (100, 95) -> circle (2x1 selects pill, 2x2 selects circle)
  * Card: (120, 50) -> card, (180, 75) -> medium, (180, 130) -> large, (250, 130) -> largeWide (3x1 selects medium, 3x2 selects large)
- Expose repeat and shuffle buttons on medium layout (selected by default 3x1 slot)
- Constrain card_widget cover maxWidth and button widths with minWidth on text column to prevent title column collapse
- Isolate CardWidgetStore SharedPreferences into GramophoneCardWidget to avoid polluting LastPlayedManager
- Move savePlaybackSnapshot before nulling instanceForWidgetAndLyricsOnly in GramophonePlaybackService.onDestroy
- Extract BaseWidgetProvider to decouple shared provider lifecycle, actions, and artwork caching
…r clipping

- Support 6 widget themes in Appearance settings (wallpaper/album art palette with follow-system, dark, and light modes)
- Resolve dynamic colors via CardWidgetColorResolver with LRU caching
- Add preview images for card and circle widgets in widget picker
- Fix double rounded corner issue on large 4x4 covers by relying on view clipToOutline and removing CardWidgetBitmapUtils
- Optimize responsive layout variants and prevent pill collapse
- Add DesktopWidgetTest and WidgetLayoutProbeTest suites
@SteveZMTstudios
SteveZMTstudios marked this pull request as draft September 19, 2026 18:53
Opt-in support for splitting delimited artist and genre tags into separate library entries, with the delimiter lists configurable from a new Tag Splitting section in Behavior settings. Both switches default to off, so nothing changes for existing libraries until the user enables it and the library is rescanned.

Core:
- TagSplitter: one tokenizer shared by artist and genre splitting.
  Symbol delimiters match anywhere, word delimiters only on whitespace boundaries, a leading backslash escapes either, results are trimmed and deduplicated case-insensitively, and the display string is   normalized onto the primary delimiter. Delimiter lists are stored per type as JSON in the default preferences and always fall back to the defaults when empty or invalid.
- Reader: artist aggregation becomes two deterministic passes.
  The first fills a canonical (trimmed, lowercased) name -> MediaStore artist id cache from every song; the second maps each song onto its artists, so the outcome no longer depends on scan order. Album artists are resolved by majority vote with a track-artist inference fallback, and artists without a MediaStore id get stable negative synthetic ids.
- Multi-value tags travel with the item as EXTRA_ARTIST_NAMES,
  EXTRA_GENRE_NAMES and EXTRA_RAW_ARTIST, keeping the raw tag available for display and letting the split values survive queue round-trips.

UI:
- Behavior settings gains a Tag Splitting category: two switches and a delimiter page each, disabled while their switch is off.
- SplitTagSettingsActivity edits symbols and words as dismissible chips, validates input while typing, and can reset to the defaults.
- Tapping the artist of a track that has several artists asks which one to open instead of guessing. Lookup is id -> exact name -> case-insensitive name.

Other:
- Search matches title, album, artist and genre through a single shared predicate, replacing three copies of the same expression.
- LastPlayedManager persists the new extras (queue format v4) and reads the tag-split config from the default preferences.
- Default delimiters are ';', ',' and '、'. ',', '&' and '/' are deliberately not included because they occur inside common single-entity names such as "AC/DC" and "Above & Beyond"; users can add them, and a name can be protected by escaping the character in the tag itself (AC\/DC).
- isColorOS() also matches realme UI, keeping StrictMode off on those devices.
- Hidden the favorite button in compact layouts to ensure the title displays correctly.
Lyrics no longer have to cover the whole player: with "Fullscreen lyrics"
turned off they are drawn inside the album cover area instead, so the artwork
stays visible while reading them.

* CompactLyricMetrics holds the compact-mode design constants (text size,
  spacing, horizontal padding, decoration scaling)
* LyricPanelController owns both LyricsView instances and is now the single
  entry point the sheet talks to. The inline view is a second instance living
  in inline_lyric_frame rather than a reparented one: ConstraintSet cannot move
  a view between parents, and the sheet itself goes GONE in fullscreen mode, so
  a single view inside it would be hidden by its own ancestor
* LyricsView no longer reaches up into FullBottomSheet to toggle the sheet; the
  host injects onFullPlayerVisibilityRequest, and the sheet resolves its own
  fullscreen view from onAttachedToWindow so the lazy lookup stays deferred
* the lyric button now uses ic_art_track, it was borrowing ic_collections_bookmark
  and that glyph reads as "save", not "show lyrics"
* inline_lyric_frame added to both layout/ and layout-w600dp-land/ variants
- Extract mid-button layout into sheet_cookie_button.xml (single authoritative XML declaration)
- Enforce full player layout parity across portrait and landscape via structural include
- Add cookie button rotation driven by a single rotation-state authority, synced on playback,
  preference and attach/detach changes
- Keep the cookie drawable in its own ImageView and suppress the button ripple so the previous
  press feedback is preserved
- Support swipe gestures on album cover to switch tracks with touch dead-zone resolution
- Add settings toggles and string resources in player settings
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.

2 participants