Skip to content

Add the Flick Replay home screen widget and responsive widget layouts - #313

Merged
ultraelectronica merged 8 commits into
mainfrom
versionF
Oct 14, 2026
Merged

ultraelectronica merged 8 commits into
mainfrom
versionF

Conversation

@ultraelectronica

Copy link
Copy Markdown
Member

Summary

Adds a "Flick Replay" home screen widget that shows today's listening snapshot
and gives the existing widgets a shared responsive-layout and interaction polish
pass.

Flick Replay widget (new)

  • New ReplayWidgetProvider renders today's listening snapshot — listening time,
    play count, day-over-day deltas, and today's top album covers — styled after the
    in-app Replay card. Four looks: Acid (default), Night, Signal, and Album, which
    tints the surface from today's top cover and picks a readable foreground +
    secondary/accent palette from measured contrast.
  • The whole widget is tappable and deep-links to the Recap screen.
  • Geometry is computed per widget size by WidgetLayoutPolicy.replay(...): it
    sizes the headline values, keeps the two metric columns readable, loses rear
    sleeves before sacrificing them, drops the comparison caption at short heights,
    and exposes a spoken content description (summary, deltas, and the open action).
  • Artwork is drawn as one binder-bounded sleeve deck (WidgetReplayArtwork) with
    a rotation-contained ornament orbit, RTL-aware positioning, and a byte-bounded
    LRU cache; the widget is registered in the manifest with a resizable 4×2 provider.

Replay data sync (Dart)

  • WidgetSyncService gains a Replay path: it watches listening history (debounced)
    plus a midnight timer, reads today's and yesterday's ListeningRecap, and
    publishes time/plays, percent deltas, and up to three local album covers to the
    shared widget state. Unchanged snapshots are skipped, refreshes are coalesced so
    a stale write cannot land, and a not-yet-ready database keeps the retry flag set
    instead of publishing misleading zeros.
  • Writes invalidate the stored day first and publish it last, so a native refresh
    that races a write cannot mix yesterday's covers with today. A day-key mismatch
    makes the native widget render an empty state, so a stale snapshot never looks
    current. WidgetReplaySnapshot centralizes the local-only cover filter (native
    widgets cannot read remote/SAF URIs), the day key, and the clamped/unknown delta math.
  • WidgetIntentHandler adds the flickwidget://recap/open intent, a
    generation-guarded native launch handshake (channel-ready inbox + detach
    acknowledgement) so taps arriving before/after the Dart handler are dispatched
    exactly once, and NavigationHelper.navigateToRecap for the destination.

Widget settings

  • The widget settings screen gains a Replay tab with Acid/Night/Signal/Album look
    options. The choice persists through app preferences (widgetReplayLook,
    default acid) and is pushed to the widget immediately.

Responsive layouts and interaction polish

  • New ResponsiveWidgetProvider base renders Android 12+ OPTION_APPWIDGET_SIZES
    variants (capped at 16) and portrait/landscape sizes for older launchers; the
    mini, flagship, compact, and replay providers all share it.
  • Adds compact narrow/short/square layouts and a 110dp 2×2 target on API 31+
    while legacy launchers keep a 156dp minimum, restructures the flagship and mini
    layouts into included sub-layouts with a thumbnail-based mini player, and enables
    flagship resizing.
  • Replaces static button ovals with ripple drawables for play/transport controls,
    adds an active-transport background and outline clipping, and adds accessibility
    strings for playback state and elapsed/duration labels.

Related issue

none

Checklist

  • flutter analyze passes
  • flutter test passes
  • Rust changes: cargo test --manifest-path rust/Cargo.toml passes
  • Built and ran the app if the change touches a playback path (flutter run --flavor full)
  • Generated code regenerated and committed if bridge/drift/freezed models changed
  • CHANGELOG.md updated for user-facing changes
  • No secrets, keys, tokens, or machine-local files committed
  • One change per PR; no unrelated reformatting in the same diff
  • Hardware tested if the Rust audio engine or USB/DAC output changed

Extract WidgetViews, WidgetLayoutPolicy, WidgetPlaybackState, and
WidgetUpcomingTrack helpers so all widget providers share layout,
text, playback, and art logic. Add responsive layouts for compact,
flagship, and mini widgets including a square compact fallback and
gradient surfaces. Cache rendered bitmaps and parsed cover art.
Replace static oval shapes with ripple drawables for play and
transport buttons, add active transport background, and update
widget layouts to use outline clipping.

Add widget dimension resources for compact sizing. Enable
resizing on the flagship widget and support vertical/horizontal
resize. Restructure flagship and mini player layouts to use
included sub-layouts and a thumbnail-based mini player design.

Add accessibility strings for playback state and elapsed/duration
labels.
- New ReplayWidgetProvider with four look presets (acid, night, signal,
  artwork)
- Widget settings screen gains a Replay tab that opens today's listening
  recap
- WidgetSyncService watches listening history and refreshes the Replay
  snapshot on change and at midnight
- WidgetIntentHandler adds categorized recap/queue intents and a native
  launch handshake with generation-based lifecycle guarding
- Default replay look is acid; selection persists via app preferences
Introduce a responsive "Flick Replay" widget that shows today's
listening snapshot (time, plays, deltas, top covers) styled after the
in-app Replay card, with Acid/Signal/Night/Artwork looks. Includes
shared layout policy, text/artwork/progress rendering helpers, palette
math, and a launch inbox that buffers widget taps until the Dart
channel handler is ready.
Introduce widget resources for compact, flagship, and replay
variants, including drawables, sizes, styles, and dims. Legacy
launchers infer spans from dp, so compact keeps a 156dp minimum on
older versions while v31 requesters get the 110dp 2x2 target.

Add layout policy, replay state, launch inbox, and resource tests
covering geometry, accessibility targets, and palette contrast.
@ultraelectronica ultraelectronica self-assigned this Oct 14, 2026
@ultraelectronica
ultraelectronica merged commit 0979324 into main Oct 14, 2026
6 checks passed
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