Repository navigation
refactor(profile): key the profile header and cover on what they render - #993
Merged
Merged
Conversation
ProfileCoverBanner and ProfileHeaderView took a UserID and derived the cover subject and the avatar from it, so a group profile could not use either. The banner now takes a ProfileCover (picture plus the subject it loads under), built with .user(_:picture:) or .group(_:picture:). The header takes that cover, an avatar view slot, and title/subtitle/bodyText, matching Android's ProfileHeader(cover, avatar, title, subtitle, body). The ring and overlap stay in the header. User callers pass a ProfileHeaderAvatar, which draws the same ContactAvatarView at 84pt. AvatarSubject gains groupCover(ConversationID): the original blob, authorized as .chatProfile, cached in the cover pool. Layout constants move to a non-generic ProfileHeaderMetrics so callers below the header don't spell out its generic parameters.
bmc08gt
force-pushed
the
refactor/profile-header-render-inputs
branch
from
October 6, 2026 20:15
79ad9ef to
d1e5c5e
Compare
bmc08gt
added this pull request to stack #997
October 6, 2026 21:56
bmc08gt
added a commit
that referenced
this pull request
Oct 6, 2026
#993 moved the profile inset to ProfileHeaderMetrics and gave ProfileHeaderView a fourth generic parameter, so the old ProfileHeaderView<EmptyView, EmptyView, EmptyView>.inset no longer compiles.
bmc08gt
added a commit
that referenced
this pull request
Oct 6, 2026
* feat(profile): favorite public groups on profiles Edit Profile gets a "Favorite Public Groups" card that opens a picker of the user's public groups, saved with SetFeaturedGroups. The You tab and other users' profiles list those groups under the stats card and open the chat on tap; the section hides when there are none. The picker's candidates are the currently featured groups plus joined public groups, so a group the user has since left can still be removed. Selection keeps the server's order, appends new picks, and caps at 10, which the contract enforces as a validation error rather than a result code. A denied save (a group went private) gets its own dialog. Own-profile state lives in a FeaturedGroups unit on SessionContainer, shared by the You tab, the Edit Profile card and the picker. Featured groups stay out of ConversationStore: they are list-shaped and may belong to chats the viewer is not in. * fix(profile): draw favorite public groups as Figma does The section now sits under a divider with a heading-weight title, and its rows drop the card and separators for a 48pt rounded-square picture beside the title and description (node 10961:111). ContactAvatarView takes an optional corner radius for that; every existing caller stays a circle. Another person's featured groups now report a failed load instead of dropping it silently, matching the own-profile path. * fix(profile): match the favorite groups picker to Figma Titles the screen "Favorite Groups", drops the row separators, and adds the footer line from node 10961:188. The search prompt now reads "Search your public groups". * fix(profile): tighten the favorite groups list and its tokens Group descriptions use appTextSmall, the subtitle token RecipientRow uses, instead of the smaller appTextCaption, and wrap to two lines. Rows drop the 66pt minimum height that stacked on the list's own insets. The picker shows a spinner until the group feed is read, so the list appears whole instead of growing from the featured groups. Save sits below the list, as in the other Edit Profile editors, rather than over it. * fix(profile): keep the group search field in place and space out favorite groups The picker swapped a spinner for the List while loading, which rebuilt the List and dropped the search field attached to it. The List now stays, with the spinner drawn over it, and the field is pinned with navigationBarDrawer(displayMode: .always) so it shows before any scroll. Profile rows get 16pt between them (was 2pt) and 24pt under the heading (was 12pt). * fix(profile): blur the group list under a pinned Save button Save is pinned with scrollEdgeBar(.bottom), so rows scroll under it. A new hardScrollEdge(for:) modifier in FlipcashUI swaps the app-wide soft edge for the hard one on this list, which blurs the rows out instead of leaving them readable. The disabled filled style is a 10% tint, so the button gets a backgroundMain backing in its own shape to stop rows showing through it. * fix(profile): drop the hard scroll edge under the group picker's Save The hard edge drew a full-width blurred band with a line across it behind the button. The picker goes back to the app-wide soft edge, and the button's own backing keeps rows from showing through it. hardScrollEdge had no other caller, so it goes too. * fix(profile): read the favorite groups inset from ProfileHeaderMetrics #993 moved the profile inset to ProfileHeaderMetrics and gave ProfileHeaderView a fourth generic parameter, so the old ProfileHeaderView<EmptyView, EmptyView, EmptyView>.inset no longer compiles.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ProfileCoverBannerandProfileHeaderViewtook aUserIDand derived the cover subject and the avatar from it, so a group profile could not use either. This changes them to take their render inputs, with no visual change for user profiles.ProfileCover, which is a picture plus theAvatarSubjectit loads under. Build it with.user(_:picture:)or.group(_:picture:). The load, blurhash and placeholder paths are the same as before.cover, anavatarview slot, andtitle/subtitle/bodyText, matching Android'sProfileHeader(cover, avatar, title, subtitle, body, …). The ring and the 42pt overlap stay in the header. User callers passProfileHeaderAvatar, which draws the sameContactAvatarViewat 84pt. The banner-controls, row-actions and under-subtitle slots are unchanged, and so are the accessibility identifiers.AvatarSubject.groupCover(ConversationID): loads the original blob under.chatProfileand caches it in the cover pool, not the thumbnail pool.cache(for:)is now an exhaustiveswitch, so a new subject can't fall through to the thumbnail cache.ProfileHeaderMetrics: the layout constants move to this non-generic enum, so callers below the header no longer spell outProfileHeaderView<EmptyView, EmptyView, EmptyView>.inset.Callers updated:
UserProfileScreen,YouScreen,EditProfileScreen,ChangeCoverPictureScreen,ProfileStatsCard.The group profile screen will build on this in a separate PR. It also needs
Conversation.coverPicture, which is onmain(881cdc4) but not yet on this stack.