Repository navigation
feat(profile): show supporter status as an animated halo and wings - #10382
Conversation
This comment has been minimized.
This comment has been minimized.
Prototype for #9914, gated by --dart-define=SUPPORTER_HALO_PREVIEW=true on the own profile: a halo and two wings positioned from the Figma frame, driven by one repeating controller, paused for reduced motion and when not visible. Co-Authored-By: Claude <noreply@anthropic.com>
…x is open They used to stay behind on the profile while only the avatar flew to the lightbox. They now fade and draw in toward the avatar as it takes off and return as it lands, following the lightbox route animation so an interrupted or swiped-back close stays in step. Refs #9914. Co-Authored-By: Claude <noreply@anthropic.com>
Tapping another supporter's avatar now opens a full-screen view where the avatar, halo and wings fly in as one piece and keep animating, with sparkles and hearts behind them, a short pitch, three benefits and a "Become a supporter" button. Your own profile keeps the plain lightbox. The new strings are English-only for now (known untranslated debt). Refs #9914. Co-Authored-By: Claude <noreply@anthropic.com>
The halo and wings were behind a dev-only preview flag. They now follow each profile's public supporter status (haloVisible from the supporters API), replacing the old heart-and-label badge. Another supporter's avatar opens the supporter view; everyone else gets the plain photo lightbox. Refs #9914 Co-Authored-By: Claude <noreply@anthropic.com>
…loses A Hero swaps its child for a placeholder while it flies, so the halo and wings remounted on landing and replayed their status fade-in. The fade now lives above the Hero and only plays when supporter status first arrives. Refs #9914 Co-Authored-By: Claude <noreply@anthropic.com>
The halo and wings already mark a supporter, so the heart label on the owner's profile was redundant. The owner's halo now follows their public status, and tapping it opens a supporter view in the same style as the one other people see. Refs #9914 Co-Authored-By: Claude <noreply@anthropic.com>
Supporters can now choose whether their halo shows publicly from Edit Profile, next to the rest of what others see on their profile. The setting flips as soon as it is tapped and reverts with an error if saving fails. Refs #9914 Co-Authored-By: Claude <noreply@anthropic.com>
The supporter view's copy was English-only and listed as untranslated debt; it now ships in all 22 locales, using each one's existing word for supporter. Refs #9914 Co-Authored-By: Claude <noreply@anthropic.com>
6f5b955 to
1fe762d
Compare
dcadenas
left a comment
There was a problem hiding this comment.
@Chardot I pushed 1fe762d, which keeps Japanese and Korean honorifics attached to the name, adds regression tests with an English control, and removes an unrelated blank-line edit.
Please re-review the updated branch.
The branch was rebased from 6f5b955 onto main at 10dcd1f to satisfy baseline guards on the current base.
All eight original patches and the additional fix were preserved unchanged, with no rebase conflicts.
Checks
- Formatting and full analysis passed.
- 204 focused tests, 65 guards, 9 goldens and 203 CI configuration tests passed.
- Configuration checks passed and the UI string scan was clean.
- The push hook also passed analysis, ARB consistency and 207 corresponding tests.
- The full sharded suite, service integration, native iOS, web build, generated outputs, tag-gate checks and reusable package, semantic-title and mergeability jobs were not run locally on this commit.
- GitHub reported no checks yet for 1fe762d at the post-push read, so CI is not established for this head.
Limitations and remaining evidence
I corrected the description's claim that owners always see the same status as other viewers.
Other viewers use public opt-in status, but an external-signer owner with a cached membership snapshot can see stale status after a change on another device until explicitly refreshing the Supporter screen.
Passive refresh deliberately avoids signer prompts; this limitation remains.
Fluent-speaker verification of the translations has not been performed.
@Chardot please replace the unknown contributing model identity with its actual provenance so independent model lineage can be established without guessing.
This is not an approval.
@hm21 @realmeylisdev your review requests remain pending; no duplicate requests were sent.
Agent-Model: openai/gpt-6.1-sol
Agent-Effort: medium
Agent-Harness: opencode/2.0.18
Agent-Context: fresh
Initiated-By: @dcadenas
This comment has been minimized.
This comment has been minimized.
The avatar's isOwnProfile doc said the owner's supporter view carries the public setting, but that view deliberately has none: a test asserts there is no switch, and the setting lives in Edit Profile and the Supporter screen. Also rejoins a wrapped doc line on SupporterHaloWings.
The supporter view copied the photo lightbox's whole route: the root navigator, the transparent barrier, the fade and the detached push. Both now go through one helper, so the comment explaining why the route sits on the root navigator, and must be a PageRoute for the Hero, covers both.
The description promises that viewers who already support Divine see no invitation in another supporter's view, but no test checked either side. These fail if the call to action is always or never shown.
The headline trimmed the leading space of every piece after the name, not only the one the line break replaces. A translation that puts the name in the middle of the sentence, which the ARB note invites, would render it glued to the next word. No shipped locale does that today, so the test overrides the English headline to put the name mid-sentence.
hm21
left a comment
There was a problem hiding this comment.
@Chardot I pushed four commits on top of @dcadenas's 1fe762d. One commit per finding, so each can be reverted alone:
36c7993docs: theisOwnProfiledoc on the header avatar said the owner's supporter view carries the public setting. It has none, and a test asserts that. Also rejoins a split doc line onSupporterHaloWings.238faccrefactor:_showSupporterLightboxcopied the whole root-navigator route of_showAvatarLightbox. Both now go through_pushAvatarLightbox, so the comment on why the route must be a root-navigatorPageRoutecovers both. No behaviour change.923f538test: nothing checked that viewers who already support Divine see no invitation. Two tests pin the call to action: shown to a non-supporter viewer, hidden for a supporter. Each fails when the call to action is forced always on or always off.ac388c4fix: the headline still ranpart.trimLeft()on every piece, so a name placed mid-sentence would be glued to the next word. The headline's ARB note invites that order ("reorder freely",mobile/lib/l10n/app_en.arb:9168). It now trims only the space the line break replaces. No shipped locale hits it, so the test overrides the English headline; it fails on 1fe762d.
Not fixed, needs a copy decision (non-blocking): supporterLightboxBadge is translated for its slot inside the headline, and some locales inflected it: pl Wspierających Divine is genitive (mobile/lib/l10n/app_pl.arb:3420), bg поддръжниците на Divine is lowercase with the definite article (mobile/lib/l10n/app_bg.arb:3530), ar داعمي Divine is oblique (mobile/lib/l10n/app_ar.arb:3413). The branch also uses it on its own, as the Edit Profile section title (mobile/lib/screens/profile_setup/widgets/supporter_recognition_section.dart:56) and as the supporter avatar's screen-reader label (mobile/lib/widgets/profile/profile_header_supporter_lightbox.dart:49). In those places the inflected forms read wrong. Either give the standalone uses their own key with nominative translations, or reuse supporterTitle ("Divine Supporters") for the section title. That choice is yours, and it belongs in the fluent-speaker pass.
Validation on ac388c4: flutter analyze lib test integration_test is clean, and 301 tests in the 8 affected suites pass locally. The ungrouped, placeholder, unpinned-assertion, Future.delayed, shared-setup and l10n-delegate guards pass. The pre-push hook passed. CI is still running on this head; I'll follow up once it finishes.
@dcadenas I left 1fe762d unchanged; my commits sit on top and touch only profile_header_media.dart, profile_header_supporter_lightbox.dart, supporter_halo_wings.dart and profile_header_widget_test.dart. @realmeylisdev your review request is still pending.
This review comes from the same model family that wrote 36c7993..ac388c4, so it is not an independent review of those commits. The original authoring model is still recorded as unknown.
Agent-Model: anthropic/claude-opus-5-5
Agent-Effort: max
Agent-Harness: claude-code/2.1.296
Agent-Context: fresh
Initiated-By: @hm21
This comment has been minimized.
This comment has been minimized.
hm21
left a comment
There was a problem hiding this comment.
LGTM. Required CI is green on ac388c4, including my four commits from the review above. The supporterLightboxBadge copy question stays open for the fluent-speaker pass and does not block merge.
Agent-Model: anthropic/claude-opus-5-5
Agent-Effort: max
Agent-Harness: claude-code/2.1.296
Agent-Context: fresh
Initiated-By: @hm21
dcadenas
left a comment
There was a problem hiding this comment.
@Chardot I pushed two localization fixes on top of ac388c4.
Please re-review the updated branch.
Changes I pushed
- 93e1f4b uses the existing standalone supporter title for the Edit Profile heading and avatar screen-reader label, addressing the inflected-label issue in the earlier review.
The contextual badge wording stays inside the headline, and regression tests cover both standalone uses. - 28818df removes an existing newline and incomplete subtitle fragment from the Telugu title, preserving its original first-line wording.
Generated text and an exact-value regression test were updated; no new translation key or Telugu wording was introduced.
The four preceding commits were retained, including the route helper, invitation tests, headline spacing fix and documentation corrections.
There is no new animation or navigation behavior change.
Checks
- Formatting and full analysis passed.
- 209 focused tests, including locale consistency and the new regressions, passed.
- 65 guards and 9 golden tests passed; the UI string scan was clean.
- The push hook passed analysis, locale consistency and 229 corresponding tests.
- The full sharded suite, service integration, native iOS, web build, generated-output CI, tag gates, configuration CI and reusable package, semantic-title and mergeability jobs were not run locally on this head.
- At the post-push read, nine GitHub checks were queued and Codex Configuration was running on 28818df; CI is not complete for this head (Mobile CI run).
Remaining evidence
This is not an approval.
The last separate review covered 93e1f4b; the final Telugu cleanup has local regression coverage but was not separately re-reviewed.
Translation naturalness was not assessed.
@Chardot the original contributing model is still recorded as unknown.
Please supply its truthful provenance so model independence can be established.
The current diff contains GPT and Claude contributions and still needs a full-diff review from a model lineage that contributed none of its changes.
Neither my review nor the existing Claude approval establishes that independence for the whole diff.
The disclosed external-signer limitation remains unchanged: an owner's cached membership can show stale status after a change on another device until an explicit Supporter-screen refresh.
Other viewers continue to use public opt-in status; passive refresh avoids signer prompts.
@hm21 the head moved after your approval; I have not re-requested your review.
@realmeylisdev your existing review request remains pending.
Agent-Model: openai/gpt-6.1-sol
Agent-Effort: medium
Agent-Harness: opencode/2.0.18
Agent-Context: fresh
Initiated-By: @dcadenas
The SupporterFailure-to-text extension lived in the Settings screen file, so the Edit Profile section imported that whole screen to word an error. It now sits in lib/l10n with the app's other code-to-string maps, and both screens import it from there. The extension itself is unchanged.
The owner's membership row and each benefit drew the same filled circle around an accent icon from two copies of the decoration. One small widget now draws it for both, so the two cannot drift apart.
The Edit Profile form spaces its fields 16pt apart, and a Column spaces its children even when one of them is empty. The supporter setting is empty for everyone who is not a supporter, so most accounts got 16pt of blank space at the end of the form. The setting now sits outside the spaced fields and adds the same gap above itself only when it shows.
The public supporter status lived inside the identity skeleton and was created lazily, so its request only started after the profile had loaded, and the halo always arrived a round trip late. The skeleton also remounts its child when it switches to content, which would have dropped an earlier answer. The status now sits above the skeleton and starts with the header, so both requests run together and the answer survives the switch.
The membership scope keyed its cubit on whether it could refresh, so the cubit was replaced when a Keycast signer became usable after sign-in. On your own profile the scope now wraps the avatar and bio, so that swap remounted the whole identity block on cold start, collapsing an expanded bio among other state. The cubit is now keyed on the account's repository alone, and the refresh it waited for runs from a listener on the signer becoming ready.
This comment has been minimized.
This comment has been minimized.
dcadenas
left a comment
There was a problem hiding this comment.
The twelve commits in 28818df..e819101 preserve the earlier supporter and title fixes; no actionable defect was found in that added range.
This is a technical review of the additions and the prior fixes they touch, not an approval or a new lineage-independent review of the entire diff.
Checks on e819101
- Full formatting and analysis passed, including a separate analysis of the extracted localization mapping.
- 312 focused tests across eight suites passed, including the new regressions and ARB consistency.
- 65 guards and 9 golden tests passed; the UI string scan was clean.
- Current-head CI passed, including Mobile CI.
The full sharded suite, service integration, native iOS, web/generated checks, tag gates and reusable package/semantic/mergeability jobs were not run locally. - Static integration with current main at a600e16 was clean, but the combined tree was not compiled locally.
Main overlaps localization files through unrelated editor keys, not supporter logic or keys.
The description now labels the original 1,137-test and simulator results as historical rather than implying they cover these twelve commits.
Accepted limits
- An owner's profile now makes an extra unauthenticated public-status request per mount; it does not prompt the signer or read private membership for guests.
- The disclosed external-signer own-view cache staleness remains unchanged until explicit Supporter-screen refresh after a cross-device change.
- No listener-count measurement or translation-naturalness assessment is claimed.
Remaining review evidence
@Chardot please supply the original contributing model's truthful provenance.
@realmeylisdev please record the provenance of the twelve new commits, using the actual contributing model declaration or a human-authored declaration as applicable.
Neither identity can be inferred from the GitHub commit author.
The full current diff includes known GPT and Claude contributions and still needs a qualifying review from a model lineage that contributed none of its changes.
Green CI and the older approval do not establish that independence.
Your existing review request remains pending, @realmeylisdev; no duplicate request was sent.
@hm21 this review covers a later head than your approval; I have not re-requested it.
Agent-Model: openai/gpt-6.1-sol
Agent-Effort: medium
Agent-Harness: opencode/2.0.18
Agent-Context: fresh
Initiated-By: @dcadenas
realmeylisdev
left a comment
There was a problem hiding this comment.
@Chardot I pushed 12 commits on top of 28818df, one per finding so you can revert any of them alone. Please look over the updated branch.
Pushed
841659dThe "Divine Supporter" words in the supporter view used the fixed brand green, about 2:1 against the light page. They now use the accent token, which is that same green in dark mode.9e2cc44The supporter view and its Hero shuttle created aCurvedAnimationduring build that was never disposed. They now drive the route animation through aCurveTween. With leak tracking on, opening the view reported one undisposedCurvedAnimationbefore and none after.3aeeefcA signed-out viewer opening a supporter's view built the membership repository and the in-app purchase listener behind it. Guests now get the invitation without that read.1e5f0e4On screens narrower than about 355pt, the supporter view's avatar group got clamped and the right wing slid about 30pt over the avatar. The group now scales down as one piece.763e242With reduced motion, the halo froze at full tilt and the wings sat uneven. It now holds level, with both wings at the middle of their swing.f7f5a8aThe membership tests checked English copy directly. They now read the l10n keys.335bef2The fourtry/catch ProviderNotFoundExceptionlookups are now nullable lookups.9cf21b3SupporterFailureMessagemoved from the Settings screen file tolib/l10n/supporter_failure_l10n.dart, so Edit Profile no longer imports the Settings screen.420d81eThe benefit rows and the membership row now share one icon badge widget.a6c0ecdNon-supporters had 16pt of blank space at the end of Edit Profile, because a Column adds spacing around empty children too. The section now sits outside the spaced fields and adds its own gap only when it shows.eca651dThe public supporter status was created lazily inside the identity skeleton, so its request only started after the profile had loaded. It now starts with the header and survives the skeleton's switch to content.e819101On your own profile, when a Keycast signer became ready after sign-in, the membership cubit got a new key and the whole avatar and bio block remounted. The cubit is now keyed on the repository alone, and the refresh runs from a listener instead.
Every fix that comes with a test was also run against the previous code, and the test fails there.
Open, for you to decide
None of these block merging from my side.
_ownPublicRecognition(mobile/lib/widgets/profile/profile_header_supporter_lightbox.dart:610) trusts the cached membership whenever there is one. ItsisSupportercheck goes by the device clock. Take an external-signer supporter whose subscription renewed: once the cachedexpirationDatepasses, their own profile drops the halo and shows the join chip again, while everyone else still sees the halo. One fix: trust the cache only when it says active or the server has confirmed it expired (isConfirmedInactive), and otherwise use the public answer. This is the expiry side of the stale-cache limitation the description already mentions.- The Edit Profile switch saves the moment it is tapped (
mobile/lib/screens/profile_setup/widgets/supporter_recognition_section.dart:69), so Cancel does not undo it, unlike the other fields on that screen. Either keep it instant and say so under the switch, or save it with the rest of the form. - The supporter view puts a full-screen 40-sigma blur (
mobile/lib/widgets/profile/profile_header_supporter_lightbox.dart:139) behind a halo that loops forever, so the blur is recomputed every frame while the view is open. I have not measured it on a low-end Android device. If the cost is real, snapshotting the blurred backdrop would remove it. - "Maybe later" (
mobile/lib/widgets/profile/profile_header_supporter_lightbox.dart:519) is a hand-built button.DivineButtonType.linkfits, but it adds the brand underline, so I left the look as it is.
Checks
flutter analyze lib test integration_test is clean. The supporter, profile header, Edit Profile and Settings suites pass (183 tests), and run_guards.sh passes. CI on e819101 is green: 28 checks passed, including Mobile CI, all eight test shards, Goldens and iOS Native Tests. The daily service-test publish was skipped.
@dcadenas I re-requested your review, since your reviews so far were comments. @hm21 the head has moved past your approval; I have not re-requested you.
I approve the code at this head, but this is not the independent review the policy asks for. Claude (hm21's commits and mine) and GPT have both written code in this diff, so that review needs a model from a different family.
Agent-Model: anthropic/claude-opus-5-5
Agent-Effort: xhigh
Agent-Harness: claude-code/2.1.308
Agent-Context: fresh
Initiated-By: @realmeylisdev
This reverts commit 3aeeefc. A signed-out viewer never reaches a profile. The router sends every unauthenticated location outside the auth, public-support and recorder routes to /welcome (app_router_redirect.dart), so the supporter view's call to action never builds for a guest. The guard and its test covered a path that cannot run.
… left" This reverts commit a6c0ecd. The gap is 16pt of extra space below the last field of a scrolled form that already ends in 24pt of padding. Closing it nested the form's main Column and made the supporter section carry the form's spacing, with two tests that pin padding values. That coupling costs more than the space.
The test fixed supporterTitle in app_te.arb to its current wording, so any correction from the fluent-speaker pass this PR still needs would fail it. The ARB fix from 28818df stays.
dcadenas
left a comment
There was a problem hiding this comment.
@Chardot I pushed 04e8dc5 on top of e819101 to fix the locally expired membership display.
Please look over the updated branch.
Four review items
- Fixed: when only the local clock has expired a cached membership, the owner's profile now falls back to the existing public supporter answer.
Server-confirmed expiry still overrides a stale public positive, and active membership's private-visibility choice still wins.
The compact join entry is hidden when that same display choice shows the public halo.
This changes display only, not entitlement data, purchase benefits or signer prompts. - Kept intentionally: the Edit Profile switch saves immediately, independently of the other profile-field drafts.
Cancel does not undo a visibility change that has saved; the description now states this explicitly. - Declined: the blur optimization remains an unmeasured performance hypothesis.
No low-end Android benchmark or per-frame cost is claimed, and no snapshot lifecycle was added without an observed regression. - Declined: the shared link-button substitution would add an underline and change the plain-text “Maybe later” appearance.
The existing button semantics and 48-point target remain.
Checks on 04e8dc5
- Full formatting and analysis passed.
- 314 focused tests across eight suites passed, including locally expired versus server-confirmed expiry controls and existing private-consent cases.
- 65 guards and 9 golden tests passed; the UI string scan was clean.
- The push hook also passed analysis, ARB consistency and 314 corresponding tests.
- The full sharded suite, service integration, native iOS, web/generated CI, tag gates, configuration jobs and reusable package/semantic/mergeability jobs were not run locally on this head.
- Static integration with current main at 2fb2b86 was clean and preserved supporter localization values; the combined tree was not compiled locally.
- At the post-push read, ten checks were queued on 04e8dc5; current-head CI is incomplete (Mobile CI run).
The previously disclosed active-membership external-signer cache staleness remains.
Rare owner-only temporary display differences while public status loads or a consent save completes remain accepted; other viewers still use public opt-in status.
Translation naturalness and hardware performance were not assessed.
This is not an approval.
@Chardot the original contributing model still needs truthful provenance.
@realmeylisdev your new contribution declaration is recorded, so that earlier provenance request is answered.
The full diff still needs a qualifying model-lineage review independent of every contributor; the GPT/Claude technical passes and existing approvals do not establish it.
@realmeylisdev @hm21 the head has moved after your approvals; neither review was re-requested.
Agent-Model: openai/gpt-6.1-sol
Agent-Effort: medium
Agent-Harness: opencode/2.0.18
Agent-Context: fresh
Initiated-By: @dcadenas
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
dcadenas
left a comment
There was a problem hiding this comment.
The three commits in 04e8dc5..606bab4 preserve the earlier cached-expiry fix and supporter-title cleanup; no actionable defect was found in the added range.
This is not an approval or a new lineage-independent review of the entire diff.
Accepted changes and tradeoffs
- The removed guest guard relies on the existing router redirects that keep signed-out and terms-pending users off protected profile routes.
Protected-route and universal-link tests passed; transient authentication timing was not measured. - Returning to the single spaced form column can leave an extra 16-point footer gap for existing non-supporters.
That cosmetic difference is accepted in exchange for the simpler layout; fields, focus, saving and visibility behavior remain. - Removing the literal Telugu assertion leaves the corrected title and generated text unchanged, while allowing future fluent wording changes.
ARB parity and placeholder coverage remain.
Checks on 606bab4
- Full formatting and analysis passed.
- 343 tests across ten focused suites passed, including protected-route and universal-link tests.
- 65 guards and 9 golden tests passed; the UI string scan was clean.
- The full sharded suite, service integration, native iOS, web/generated CI, configuration/tag gates and reusable package/semantic/mergeability jobs were not run locally on this head.
- Static integration with current main at cb5801e was clean; the combined tree was not compiled locally.
- At the CI read, 26 check runs had succeeded, one reporting job was skipped, and iOS Native Tests was still running; the Mobile CI aggregate was not yet present.
The existing instant-save/Cancel and external-signer cache disclosures still apply.
Translation naturalness was not assessed.
I made no new code change or push in this pass; the description's earlier SHA-labelled test results remain historical.
@Chardot truthful original contributing-model provenance is still missing.
The full current diff also needs a qualifying model-lineage review independent of every contributor; neither the GPT/Claude technical passes nor older approvals establish it.
@hm21 @realmeylisdev this review covers a later head than your approvals; neither review was re-requested.
Agent-Model: openai/gpt-6.1-sol
Agent-Effort: medium
Agent-Harness: opencode/2.0.18
Agent-Context: fresh
Initiated-By: @dcadenas
hm21
left a comment
There was a problem hiding this comment.
@Chardot I pushed three commits on top of @dcadenas's 04e8dc5. Each one can be reverted on its own:
d73c6ddreverts3aeeefc. A signed-out viewer never reaches a profile: the router sends unauthenticated users to/welcome(mobile/lib/router/app_router_redirect.dart:642), so the guest guard in the supporter view could not run.e03393erevertsa6c0ecd. The gap is 16pt of extra space below the last field of a scrolled form that already ends in 24pt of padding. Closing it nested the form's main Column and made the supporter section carry the form's spacing, with two tests that pin padding values.606bab4drops the test that pinssupporterTitleinapp_te.arbto its current wording, since any correction from the fluent-speaker pass would fail it. The ARB fix from28818dfstays.
The other ten commits from @realmeylisdev and 04e8dc5 look good to me.
flutter analyze is clean, the five affected suites pass (254 tests), and CI on 606bab4 is green.
LGTM. This is not the independent review the merge gate needs: the diff has Claude and GPT commits, so it still needs a review from another provider.
Agent-Model: anthropic/claude-opus-5-5
Agent-Effort: unknown
Agent-Harness: claude-code/2.1.296
Agent-Context: fresh
Initiated-By: @hm21
realmeylisdev
left a comment
There was a problem hiding this comment.
Re-reviewed at 606bab4. This covers @dcadenas's 04e8dc5 and @hm21's three commits on top of my earlier approval.
04e8dc5fixes open item 1 the way I suggested. A cache that only the device clock has expired now falls back to the public answer, and server-confirmed expiry still hides the halo. The new test checks both cases, so it fails if either one breaks.- Items 2 to 4 are settled. The description now says the switch saves immediately, and the blur and "Maybe later" stay as they are. I agree with all three.
d73c6ddis right, and my finding was wrong. The redirect sends signed-out users to/welcomefrom any route a profile can be on (mobile/lib/router/app_router_redirect.dart:642), so the guest guard was protecting a state the app cannot reach. I withdraw that finding.e03393e: the 16pt gap is real, but keeping the form simpler is a fair trade. I'm fine with it as is.606bab4: dropping the test that pinned one Telugu string is fine, since the ARB fix itself stays.
Both reverts exactly undo my commits. CI on 606bab4 is green, including Mobile CI and every test shard.
LGTM. A review from a third model family is still needed, since Claude and GPT both wrote code in this diff.
Agent-Model: anthropic/claude-opus-5-5
Agent-Effort: xhigh
Agent-Harness: claude-code/2.1.308
Agent-Context: fresh
Initiated-By: @realmeylisdev
rabble
left a comment
There was a problem hiding this comment.
Delegated read-only review published by coordinator.
Reviewed the supporter presentation, membership-state changes, profile integration, recognition setting and relevant regression coverage at 606bab4. No actionable introduced defect found.
Public profiles use public opt-in status. The owner display gives active membership consent precedence, falls back to public status when only the device clock expires a cache, and preserves server-confirmed expiry. Recognition saves optimistically and reverts on failure. Motion is gated for reduced motion, lifecycle and visibility. The tests cover private consent, expiry distinctions, lightbox navigation, reveal persistence and setting failures.
Current-head checks show 30 successes and one reporting skip, including all eight app-test shards, goldens and iOS native tests. I did not rerun app tests, assess translation fluency, or measure hardware rendering performance.
Technical approval only. The original contribution still declares Agent-Model: unknown, and both GPT and Claude subsequently contributed. Truthful original model provenance and a qualifying third-provider whole-diff review remain necessary before merge.
Agent-Model: openai/gpt-6[variant-unknown]
Agent-Effort: unknown
Agent-Harness: codex/unknown
Agent-Context: fresh
Initiated-By: @rabble
dcadenas
left a comment
There was a problem hiding this comment.
@Chardot I pushed c4359ec, a test-only change that strengthens vanished-profile coverage.
Please re-review the updated tests.
Production code, strings and assets are unchanged.
The old halo-absence assertion could pass with the supporter API disabled.
The new own-profile and other-profile cases first show a real public supporter halo, then use a fresh vanished-profile fixture, pin the vanished state, and verify that no halo or membership entry appears.
Both cases fail when the vanished-status gate is disabled; restored production code passes.
Independent review and checks
A separate read-only reviewer used fresh context, adversarial framing and a complete reading of the resulting diff, including test/helper bodies, localization structure and assets.
That review found the test gap, then reviewed the corrected tests and their interactions at c4359ec; no actionable finding remains.
The test contributor and publisher used shared authoring context, not the reviewer's fresh context.
- Full formatting and analysis passed.
- 345 tests across ten focused suites, 65 guards and 9 golden tests passed.
- The push hook also passed analysis, ARB consistency and 221 corresponding tests.
- The full sharded suite, service integration, native iOS, web/generated CI, configuration/tag gates and reusable package/semantic/mergeability jobs were not run locally on this head.
- Static integration with current main at 61cf0b9 was clean, with supporter localization values preserved; this combined tree was not compiled locally.
Earlier merged-tree test results cover an older main/head combination, not this candidate. - At the post-push read, ten checks were queued on c4359ec (Mobile CI run).
This is a non-approving handback only because current-head CI is incomplete; the review-quality gates are satisfied.
The instant-save/Cancel behavior, external-signer cache limits and accepted 16-point non-supporter footer gap remain as disclosed.
Translation naturalness and device rendering performance were not assessed.
The original contribution's model remains unknown, and the read-only reviewer's Claude family also contributed earlier changes.
These are disclosed limits to model diversity, not disqualifying conditions under the current review policy.
The fresh-context, complete-diff, adversarial review requirement is met; no third-provider review or human waiver is being requested.
@hm21 @realmeylisdev @rabble the head moved after your approvals; no review was re-requested.
Independent read-only reviewer:
Agent-Model: anthropic/claude-opus-5-5
Agent-Effort: unknown
Agent-Harness: claude-code/2.1.309
Agent-Context: fresh
Initiated-By: @dcadenas
Test-fix contributor and publisher:
Agent-Model: openai/gpt-6.1-sol
Agent-Effort: medium
Agent-Harness: opencode/2.0.18
Agent-Context: shared
Initiated-By: @dcadenas
Mobile PR PreviewPreview refreshed for Last refresh:
|
dcadenas
left a comment
There was a problem hiding this comment.
The complete resulting diff at c4359ec received a separate fresh-context, adversarial read-only review, including all changed tests/helpers and the final vanished-profile test repair.
No actionable finding remains.
The strengthened tests first show a real supporter halo, pin the vanished state, and fail when the vanished-status gate is disabled.
Checks
- Full formatting and analysis, 345 focused tests, 65 guards and 9 golden tests passed on this head.
- Current main at 61cf0b9 merged with c4359ec and passed 346 focused tests in a disposable tree.
Full analysis of that particular combined tree was not run; older merged-analysis results covered a different main/head pair. - 29 current-head check runs succeeded, including required Mobile CI, all eight test shards, service integration and iOS native tests.
The daily service-result publishing job was skipped, not the service tests. - Full-suite, service, native, web/generated, configuration/tag and reusable checks were inspected in CI rather than run locally.
Accepted limits
The immediate-save/Cancel behavior, external-signer cache staleness and 16-point non-supporter footer gap remain as disclosed.
Translation naturalness and hardware rendering performance were not assessed.
The original authoring model is unknown and the reviewer's Claude family overlaps earlier contributions; these limit diversity but do not disqualify the fresh-context, complete-diff review under the current policy.
Independent read-only reviewer:
Agent-Model: anthropic/claude-opus-5-5
Agent-Effort: unknown
Agent-Harness: claude-code/2.1.309
Agent-Context: fresh
Initiated-By: @dcadenas
Published by @dcadenas from that separate review and verified results.
The test-fix contributor's shared-context GPT identity remains separately recorded in the description; it is not the independent reviewer identity above.
Requested by Sebastian
Description
Today a Divine Supporter is marked by a small heart "Supporter" label under their username. It is easy to miss, and on your own profile it shows even when you chose not to show your support publicly. This PR replaces it with the supporter design from #9914: an animated halo and pair of wings around the profile avatar.
What changes for people:
haloVisiblefrom the supporters API), and fade in once that status loads, without moving the layout. With reduced motion turned on they appear still, with no fade.With an external signer and an existing cached membership snapshot, a setting changed on another device can remain stale here until an explicit refresh on the Supporter screen.
Why this approach:
Your own profile uses an existing membership snapshot first, so a setting changed locally can appear immediately without waiting for a public refetch.
Passive refresh avoids external-signer prompts, which means cross-device changes can leave your own view stale until you explicitly refresh on the Supporter screen.
If only the local clock has expired a cached membership and the server has not confirmed expiry, profile display falls back to the existing public supporter answer.
A server-confirmed expiry still overrides a stale public positive, and active private consent still takes precedence.
The compact join entry is hidden when the same display choice shows the public halo.
This does not change cached entitlements, purchase benefits or signer-refresh behavior.
Related Issue: Closes #9914
Main vs this branch
Same simulator (iPhone 16, iOS 18.5), same signed-in account, same screens, with public supporter status on for both accounts.
Out of Scope
Verification
Original author-reported checks (before the latest updates)
The following results, including the 1,137-test count and simulator checks, predate the twelve commits in 28818df..e819101 and do not establish validation of the current head.
flutter analyze lib test integration_test: no issues.flutter testovertest/widgets/profile/,test/widgets/supporter_membership_test.dart,test/screens/settings/,test/screens/profile_setup/,test/screens/profile_setup_screen_test.dart,test/blocs/supporter/andtest/l10n/: 1137 passed.mobile/scripts/ci/run_guards.sh: 65 passed, 0 failed.ProfileSwitchRowform cardEarlier checks on e819101 (before the cached-expiry fix)
No new simulator verification was performed for these updates.
Checks on 04e8dc5
Checks on 606bab4
3aeeefc(guest guard in the supporter view; signed-out users are redirected to/welcomebefore any profile) anda6c0ecd(Edit Profile column restructure for a 16pt bottom gap), and drops the Telugu exact-value test from28818df.flutter analyze lib test integration_test: no issues.profile_header_widget_test,profile_setup_screen_test,supporter_recognition_section_test,supporter_membership_testandarb_consistency_test: 254 passed.Checks on c4359ec
This update changes tests only; production code, strings and assets are unchanged.
The vanished-profile regression now first renders a public supporter halo, recreates the vanished-profile fixture with its vanished state explicitly checked, and verifies that both own and other vanished profiles show no halo or membership entry.
Both cases fail when the production vanished-status gate is temporarily disabled and pass with that gate restored.
Earlier merged-tree runs cover an older main/head combination, not c4359ec with this main.
Type of Change