Skip to content

feat: home-screen widgets with matches waiting for a reply (WidgetKit + Glance)#83

Open
GSTJ wants to merge 8 commits into
mainfrom
GSTJ/widgets
Open

feat: home-screen widgets with matches waiting for a reply (WidgetKit + Glance)#83
GSTJ wants to merge 8 commits into
mainfrom
GSTJ/widgets

Conversation

@GSTJ

@GSTJ GSTJ commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Summary

Home-screen widgets on iOS and Android showing how many matches are waiting for your reply, with up to three dog photos, tapping opens the messages tab.

Details

  • iOS: WidgetKit extension in SwiftUI (small and medium sizes) via an apple-targets config plugin. Data comes from an App Group snapshot the app writes on foreground/background and after match updates.
  • Android: Glance widget in Kotlin inside a local Expo module, manifest wired via Gradle merging, reading the same snapshot from shared preferences.
  • Dog photos are pre-downloaded (max 3) to shared storage so the widget renders offline; a broken URL just omits that photo, never crashes the widget.
  • Friendly localized empty and logged-out states (en + pt-BR), including native-side placeholder strings before the first snapshot exists.
  • "Waiting for reply" means the last message is theirs or no message exists yet.
  • Version bumped to 1.5.0.

Testing steps

  1. Install the build and open the app once logged in (this writes the widget's data).
  2. iPhone: long-press the home screen, add widget, search Pegada: add the small and the medium ones. They should show your waiting-matches count and up to three dog photos.
  3. Android: long-press the home screen, widgets, Pegada: same content.
  4. Tap the widget: the app opens on the messages tab.
  5. Reply to a match and background the app: the widget count should drop shortly after.
  6. Log out and check the widget: it should show a friendly sign-in message instead of stale data.

GSTJ added 3 commits July 8, 2026 16:28
Adds a widget on both platforms showing how many matches are waiting
for a reply, with up to 3 dog avatars. Tapping it deep links into the
messages tab (pegada://messages).

- iOS: WidgetKit extension (small + medium) generated at prebuild by
  @bacons/apple-targets from targets/matches-widget; reads a JSON
  snapshot from App Group UserDefaults (group.app.pegada) and avatar
  files from the shared container.
- Android: androidx.glance 1.1.1 widget inside a new local Expo module
  (modules/pegada-widget) with its own receiver + provider XML wired
  through the library manifest; reads the same snapshot from
  SharedPreferences.
- One shared JS service (services/matchesWidget) builds the localized
  snapshot, downloads up to 3 avatars via the new expo-file-system API
  (App Group container on iOS, document dir on Android) and hands it to
  the native module, which reloads the OS timelines. Synced on (app)
  mount, foreground/background transitions, matches query updates, and
  cleared to a sign-in prompt on logout.
- All user-facing copy is localized (en + pt-BR): snapshot strings via
  i18next, pre-snapshot placeholders via Android string resources and a
  minimal locale check in Swift.
- Version bumped to 1.5.0 (native change).
…nsion target

iOS allows one widget extension per app, so targets/matches-widget becomes
the shared targets/pegada-widgets target (deploymentTarget 16.2,
byte-identical config across feature branches). The widget keeps its iOS 17
floor via @available / #available gates in MatchesWidget.swift and
PegadaWidgetsBundle.swift. Also drops the hardcoded appleTeamId; the team id
comes from EAS credentials at release build time.
GSTJ added 5 commits July 8, 2026 18:21
…nches

The app-intents and live-status branches declare ^4.0.7; the exact 4.0.7 pin
here made every cross-branch merge conflict on package.json + lockfile for no
behavioral difference (both resolve to 4.0.7).
…anguage

The widget colorsets were silently EMPTY: expo-target.config.js used
{ color, darkColor } but @bacons/apple-targets expects { light, dark },
so every Color("...") in the widget resolved to nothing. Colors now
mirror packages/shared/themes exactly (same hsl strings, true black
dark theme, dark-variant brand pink).

iOS (WidgetKit):
- bundle Gilroy (Bold/SemiBold/Medium/ExtraBold) in the extension via
  the synced target folder + UIAppFonts, with a CTFontManager runtime
  registration fallback; map weights to the app's roles
- lowercase "pegada" wordmark (matches the logo), overflow +N as a
  brand-pink coin inside the avatar stack instead of loose text,
  medium family now shows the overflow instead of dropping it
- single paw motif per surface: pawprint watermark bleeding from the
  bottom-trailing corner at 10% opacity, emoji hero removed from the
  empty state

Android (Glance):
- same theme tokens via day/night ColorProvider, tinted paw glyph in
  the header, background-colored ring around avatars, brand-tinted
  initial badge when a photo is missing or fails to decode (slots no
  longer collapse), Medium-weight message text
- Glance 1.1.1 ceiling documented in-code: no custom typeface, no
  gradients, no negative spacing; sizes/weights compensate

Verified on iPhone 17 Pro Max sim + API 35 emulator, light and dark,
populated and empty states.
The MEDIUM home-screen widget (WidgetKit + Glance) rendered the match
count as a big pink numeral, then repeated it in the counted i18n
string right underneath ("5" followed by "5 matches waiting for your
reply"). Add a countless variant (widget.waitingForReplyCountless) and
thread it through the snapshot contract as `messageCountless` so
layouts that already show the numeral can drop the count from the
text instead of duplicating it. SMALL keeps the counted string since
it has no numeral.
…urated P3

@bacons/apple-targets always tags generated colorset Contents.json as
"color-space": "display-p3", but it gets there by parsing the config's
CSS color as plain sRGB and writing those components verbatim - it
never actually gamut-converts. On a wide-gamut display that made the
widget pink read visibly more saturated than the app's real brand pink
(measured ~#FF55A3 vs #EF62A1). The plugin has no color-space option,
and prebuild rewrites every colorset unconditionally, so a hand-fixed
Contents.json would just get clobbered on the next run.

Feed the plugin the sRGB->Display-P3 gamut-mapped equivalent of each
theme color instead (as rgb() strings, computed by the new
scripts/srgb-to-p3-widget-colors.js), so the P3-tagged colorset it
writes renders back to the original sRGB appearance on a P3 display.
Survives prebuild by construction since it's regenerated from the
config every time.
oxfmt --check caught these on CI: a local expo prebuild run after the
P3 color-space fix regenerated the colorsets without a trailing
newline. No color values changed, formatting only.
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