Skip to content

feat(chat): rebuild Edit Group in Edit Profile's shape - #994

Merged
bmc08gt merged 44 commits into
mainfrom
feat/edit-group-refresh
Oct 6, 2026
Merged

bmc08gt merged 44 commits into
mainfrom
feat/edit-group-refresh

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Rebuilds Edit Group in Edit Profile v2's shape, following the "Edit Group" section of the group profile refresh spec. Figma node 10918:265 was direction only.

Changes

  • Edit Group has an inset cover with a "Change cover" chip and the group photo overlapping it with "Change photo". Below them are Group name and Description cards that push their own screens. The pop when canEdit turns false is unchanged.
  • Cover (EditGroupCoverScreen) reuses EditGroupModel's upload and reservation path through the new saveCover, which sends only cover_picture.
  • Description (EditGroupDescriptionModel/Screen) is modelled on Edit Bio, with the same 160-character limit as the contract. An emptied field is sent as .clear, and descriptionModerated shows under the field.
  • Cover and description confirm before saving, as name and picture already do, because the change reaches everyone in the group.
  • Balance Requirements is read-only, since EditChatRequest has no rules field. It has Join and Chat rows, with Chat falling back to Join when the group sets no speaker minimum, plus the spec's footnote. The card is hidden when neither side has a minimum, the same rule the spec gives for the profile screen. The rows come from feat(chat): rebuild the group profile on the profile refresh #995's GroupBalanceRequirements; amounts use the gate panel's format.
  • applyEdit now seats the description from the EditChat response. Conversation(response.chat) carries the full post-edit description, so a cleared description lands as a clear and other edits leave it unchanged.
  • FieldCard and CoverChip move out of EditProfileScreen into ProfileFieldCard.swift, unchanged, so both editors share them. The picture screen's error mapping moves to DialogItem+GroupImageEdit so the cover screen can use it too.

Cover and description edits aren't sent to analytics. Shared-core's GroupField only defines name and picture, and logging a cover or description edit as a picture edit would miscount.

No UI smoke test touches Edit Group, so none needed updating.

bmc08gt added 30 commits October 5, 2026 23:00
The You tab becomes the profile in later slices, so the rows it held
move to a Settings screen reached from a gear on the tab: an interim
Profile section (the My Account editors until Edit Profile exists),
Security, Privacy, Advanced, and Account with a new Account Info screen
(phone, email, user ID, authority public key), then the version footer.

SettingsMyAccountScreen and SettingsAdvancedFeaturesScreen are removed,
and the UI smoke tests now reach Settings through the gear.

Base: origin/main 410bb5f.
…nfoDetails.Row

The UI tests' failure messages and doc comments still named My Account,
which this branch removed. Also rewraps a YouScreen doc comment that was
reflowed onto one 110-column line.
Rebuild the You tab as the user's own profile: cover banner, avatar,
name, handle and bio, a stats card (minimum to chat, date joined), and
an Edit Profile button. Share becomes a menu with "Share Profile" and
"Show Profile Card"; the card, link row, Share/Download and export move
to a full-screen ProfileCardScreen. A "Claim your username" row replaces
the username progress card. Add a cover subject to ProfileAvatarStore
and extract StartChattingFee from ConversationScreen. Remove
TipCardPresentation and the tab-bar expansion state. Exported card files
are now named "Chat with <name>".
Push the new chat when the DM record lands before the start-chatting sheet
dismisses, and only when the profile is still in front. Open Chat from a DM
returns to it instead of pushing a copy. Unmute from the menu reports errors
and analytics like the mute sheet, Start Chatting runs the give-cash gate in
both branches, and the toolbar buttons get accessibility labels.
The profile screens had the right controls in a centred, inset-card
layout that didn't follow the design. Follow nodes 10961:314 and
10990:494 instead: a full-bleed 214pt banner (flat #323234 when there is
no cover), a left-aligned 84pt avatar overlapping it, Edit Profile and
Share in the avatar row, left-aligned name, handle and bio, and a
two-column stats card with labels above values.

Share opens a sheet with Share Profile, Show Profile Card and Copy Link
in place of the menu. The other-user profile draws its back and overflow
buttons over the banner with no navigation bar, and the pinned button is
white over a fade. The Finish Your Profile card and the card-colour
cover fallback are gone, with their tests.
Move the You tab's gear and the other-user profile's back and overflow
controls into the navigation bar, so the app-wide soft scroll edge draws
the top fade. Drop the "You" title, the cover's dark overlay and the
pinned button's gradient; the pinned button now sits in a scroll edge bar.

Replace Mute/Unmute in the overflow menu with one "Mute Notifications"
entry that opens MuteChatSheet, whose "Never" option unmutes.

Top-align the stats card labels, and left-align the share sheet's
"Share User Profile" title with a shorter detent.
The profile screens matched Figma pixel values: ten font sizes, four RGB
colours and one-off radii and paddings that no other screen uses. Swap
them for the app* font tokens, the textMain/textSecondary/backgroundRow
colours, glass buttons, and the PartialSheet + ChatActionRow sheet that
Mute Notifications already uses.
… the bar

At rest the iOS 26 soft edge only darkened the cover banner and left a hard band where it stopped.
Under the handle they took the bio's spot. The action row's height comes
from the share button, so a badge appearing on mute or block no longer
moves the content below it. The stats card uses Metrics.boxRadius like the
app's other cards.
Share and Edit Profile now match the design (node 10961:323, 10961:335):
38pt tall, a 22pt share glyph, 18pt side padding on Edit Profile, and a
flat fill at 10% of the action colour. Over the #19191A background that
is the design's #303031. On glass the circle rendered at 34pt and the
capsule at 31pt.
appTextBody is Avenir Regular, a weight nothing else in the app uses, so
the bio read as a different typeface next to the header. Use
appTextMessage, the Medium weight chat bubbles use.
The profile hides the tab bar, so the toast host drew 12pt above the bottom
edge, over the pinned button. A screen can now mark a bottom bar with
toastClearance(_:); the host measures it and keeps the toast above it while
it is on screen.
The entrance moved the toast by its own padded height, so a toast raised
over the profile's pinned button travelled up from the screen edge past
the button. It now rises the 56pt a toast 12pt off the edge always did.
…rofile header

The You tab's Edit Profile button now pushes Edit Profile instead of
Settings, and Settings drops its interim Profile section.

Edit Profile draws its cover with ProfileCoverBanner and its avatar at
the You tab's 84pt with the same 5pt ring, so the two screens show the
same empty cover. The parked CoverBanner, with its 3:1 card-colour
fill, is removed; the cover editor previews a picked image through
ProfileCoverBanner's new preview parameter. Row insets match Settings
(25/20), values sit against the chevron, and the empty-cover plus uses
appDisplayMedium instead of a 40pt system font.
…ards

The cover sits in an inset card with a Change cover chip, the avatar
overlaps its edge with a camera badge, and Name, Username, Bio and
Minimum to Chat are label/value cards that open the existing editors.
A Medium-weight label reads as secondary next to the bold value.
iOS 18 keeps the opaque chip, since the row fill vanishes on a photo.
…tton

The glass takes a backgroundMain tint so the label holds on a bright
cover, and the chip is a button beside the cover card rather than a
label inside it, so the interactive glass responds to its own press.
Both open the cover editor.
…f the profile card

Drop the link row and Share button; the profile's Share menu already offers both.
The card springs in from 0.55 scale with the bill pop's timing while the backdrop fades in, and Close plays it in reverse. The cover is presented and dismissed without its slide so the reveal is the only motion.
…glass swaps to Download in place

The card was a full-screen cover with its own toolbar button laid over the
You tab's gear. The two glass buttons sampled different backdrops, so the
glass shifted and changed colour as the cover settled and cleared. The card
is now an overlay in the You tab, the tab's one toolbar button swaps its
glyph between Settings and Download, and the tab bar hides while it is up.
The keyboard and Save button rose while the screen was still sliding in, so Save animated in from off screen. Name, Username, Bio, username lookup and group name now focus after the push finishes.
bmc08gt added 12 commits October 6, 2026 13:05
Edit Profile read only the account's own fee and showed "Not set" when there was none, while the You tab showed the regional minimum others actually pay. Both now use StartChattingFee.
A scan always opens the person's profile after the card's 750ms hold. A
username search and a transaction's details open the DM when it exists
and the profile until then, through DMRoute. The profile is where the
paid chat starts, so nothing routes into a conversation by user ID any
more, and tipConversationForUser and tipConversationForUserSendingCash
are removed.
Every route to a person now lands on their profile until a DM exists, and
the profile owns the paid start-chatting flow. ConversationScreen only opens
an existing chat, so the tipDM context, the chatExists/startChattingFee
plumbing, the full-width Start Chatting bar, and the open-time Send Cash are
unreachable.
Scanning opens the profile now, so the old wait for the empty chat's
send-cash button timed out with the profile on screen.
Scan prompts, the tutorial step, the scan error alert, the setup card screen and the unnamed export file now say "Profile Card". Identifiers and analytics event names keep tip card; the code rename is a later chore.

Delete UsernameProgressCard: Edit Profile's Username card replaced it and nothing references it.
It has no callers after the You tab redesign, but it may come back.
EditChatRequest has carried cover_picture since flipcash2 0.18.0, but
ChatService.editChat never set it. Build the request in
ChatService.editChatRequest so it can be tested without a transport, and
set cover_picture from an optional blob ID; nil leaves the field unset,
like title and profile picture.

GroupChatEditing.editChat now takes the description edit and the cover
blob ID too, and EditGroupModel passes .unchanged and nil for both, so
the existing name and picture edits send the same request as before.
EditGroupPictureScreen shows the photo-rejection copy for
coverPictureBlobNotAccepted.
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.
…to feat/edit-group-refresh

* origin/feat/edit-chat-cover-picture:
  feat(chat): send cover_picture and description through editChat
  chore(deps): bump flipcash2-client-protocol to 0.18.0
  feat(chat): persist group cover picture
  feat(chat): adopt flipcash2 0.18.0 cover picture, membership and featured-group contract
  fix(chat): show the reply quote on a photo reply
  fix(chat): open the reactors sheet from a long press anywhere in the reaction row
  feat(chat): double-tap a photo to react
  fix(chat): keep a photo retryable when its chat can't be fetched offline
  fix(blob): stop waiting on finalization after three lost polls
  fix(chat): send a photo whose upload failed offline
Edit Group now has the inset cover with a "Change cover" chip, the group photo
overlapping it with a caption, and cards that push their own screens: Group
name and Description. Balance Requirements is read-only, because
`EditChatRequest` has no rules field. Chat shows the Join amount when the group
sets no speaker minimum, and the card is hidden when neither side has one.

The cover screen uploads through EditGroupModel's existing reservation path and
sends only `cover_picture`. Description is modelled on Edit Bio, and an emptied
field goes out as an explicit clear. Both confirm before saving, like name and
picture, since the change reaches everyone in the group.

`applyEdit` now seats the description from the EditChat response, so a cleared
description lands as a clear without waiting for the stream. FieldCard and
CoverChip move out of EditProfileScreen so both editors share them, and the
picture screen's error mapping moves to a shared dialog the cover screen also
uses.
@bmc08gt bmc08gt self-assigned this Oct 6, 2026
@bmc08gt
bmc08gt force-pushed the refactor/profile-header-render-inputs branch from 79ad9ef to d1e5c5e Compare October 6, 2026 20:15
@bmc08gt
bmc08gt changed the base branch from refactor/profile-header-render-inputs to main October 6, 2026 23:02
@bmc08gt
bmc08gt merged commit 7594715 into main Oct 6, 2026
2 of 3 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