Skip to content

feat: group multi-attachment messages into collections (collages / stacks / groups) - #3147

Closed
DeveloperBlue wants to merge 69 commits into
BlueBubblesApp:masterfrom
DeveloperBlue:developerblue/attachment-groups
Closed

feat: group multi-attachment messages into collections (collages / stacks / groups)#3147
DeveloperBlue wants to merge 69 commits into
BlueBubblesApp:masterfrom
DeveloperBlue:developerblue/attachment-groups

Conversation

@DeveloperBlue

@DeveloperBlue DeveloperBlue commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Edit

This PR has been superseded by the following incremental PRs:

  1. #3152 - fix: message parts - use partIds and helpers instead of unstable indices (1/7)
  2. #3166 - feat: refine image gallery fan stack (2/7)
  3. #3175 - feat: split collection stack into recomposable collection building blocks (3/7)
  4. #3176 - feat: add collage layout for 2-3 collection attachments (4/7)
  5. #3181 - feat: add grid layout for Material/Samsung collection attachments (5/7)
  6. #3182 - feat: add media collection overview gallery (6/7)
  7. #3183 - feat: add settings for multi-attachment collection layout (7/7)

This PR introduces grouping consecutive image/video message parts into media collections with collages, stacks, and grid layouts!

main features:

  • collection gallery page
    full-page grid for all items in the collection with their tapbacks
  • per-attachment tapbacks, long-press popovers, swipe-to-reply (collage)
  • mix-and-match collection layouts across iOS, Material, and Samsung skins
  • reply/thread handling per attachment part
  • better messageParts grouping and lookup

On the iOS skin, by default, 2-3 items are rendered as a collage and 4+ items are rendered as a fan stack. Material and Samsung render 2+ items with the Grid. You can configure this under Settings → Media Settings → Multi-Attachment Layouts.

iOS 2–3 collage iOS 4+ stack Material/Samsung 2+ grid
Screenshot_20260729_045127_BlueBubbles_Beta
stack.mp4
Screenshot_20260729_055815_BlueBubbles_Beta
Collection gallery Per-attachment tapback Swipe-to-reply collage card
collection_gallery.mp4
stack_react.mp4
collage_reply.mp4
Grid Override on iOS Collage Override for 4+ items Subject and body
Screenshot_20260729_061914_BlueBubbles_Beta Screenshot_20260729_062006_BlueBubbles_Beta Screenshot_20260729_061722_BlueBubbles_Beta

Refactors

This PR is wide in breadth, and while it touches a lot of files, it tries to be very targeted. Most of the core changes can be attributed to the following necessary refactors + bugfixes, wiring, and polish.

  • MessagePart / messageParts: collapse adjacent media-only parts with MessageHolder._collapseMediaCollectionParts.
    Reactions, replies, threads, and bubble effects now target real message-part IDs instead of the original list indices (problematic). Small new helpers for checking if a part group is the leading or trailing part group.
    These changes needed to be applied to reactions, replies, threads, and bubble effects (resolve by message-part ID instead of collapsed list index)
  • Attachment holders use optional AttachmentFrameMode (fixedCard, gridCell) frame modes that determine if they fill their parent container and render their drop shadow (e.g. in grid cells)
  • Fullscreen Viewers for Images and Videos now take a collection controller when opened from a collection
  • Collection-related widgets and helpers are moved into a /collections folder; current fan stack is heavily modified off the original message_image_gallery widget.
  • ChatMessages: threadsForParts for handling threads for attachment parts
  • Message Popover enforces minimum attachment size (e.g. opening a tiny image from a grid cell grows it to regular attachment size instead of keeping it tiny)
  • Reaction cloud bubble gets an "internal" tail variant to match iMessage's bubbles for stacks
  • Outer bubble-specific wrappers (SwipeToReply, MessagePopupHolder, etc.) are deferred and re-used by the internally in a collection per-card
  • Massive number of bugfixes and other polishes

Addresses #3122, #2605, #2812 and lays groundwork for sending multi-attachment messages

Tested on a physical android phone, tablet, and windows desktop.

@zlshames

zlshames commented Jul 29, 2026

Copy link
Copy Markdown
Member

isnt this already implemented? Not the same exact implementation as you. but the photo gallery image fan widget widget i made does the same for the most part. It's also extremely difficult to review the PR when there are 57 changed files...

@jjoelj

jjoelj commented Jul 29, 2026

Copy link
Copy Markdown
Member

This looks visually good but we're gonna need a list of specific changes in each file, and reasons for the change. Or break this into much smaller PRs that can stand on their own.

@DeveloperBlue

DeveloperBlue commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Sorry for the huge PR, the end result definitely got away from me.

I can break this PR down into about 3 smaller PRs:
(and include a file list of what files were changed and why for each)

  1. messageParts grouping refactor (~15 files)
    This is a necessary refactor; master already collapsed adjacent media parts into a group, but much of of the app still wrongfully treated the part list indices as message part ids. This introduced a lot of silent issues. Just to briefly name some of the areas affected: threads, replies, reactions (partially fixed on master), stickers, and leading/trailing chrome and bubble tail

  2. Collections implementation (~26 files)
    Unfortunately this one still ends up being a large PR, but is the main feature addition:

  • New collage and grid widget, updated stack widget, plus their reusable components, shared helpers, and docs (8-10 files)
  • AttachmentHolder gets a frame-mode so media fills collage and stack cards/grid cells (~7 files)
  • Deferring parent gestures/reactions/popovers down to per-card (~6 files)
  • routing/passing params down (bloats the file count)

~60 files to ~25 is a big change, but I understand if this still overwhelms the review process. The list of file changes would hopefully alleviate some of the review work.

I may be able to break the AttachmentHolder changes out into a separate PR, if requested, but it would be difficult to review with no visual places to see the changes- it depends on the collection widgets.

  1. Gallery grid overview + settings (~16 files, more self-contained)
    This would include the full-page collection grid (with displaying tapbacks), grid buttons on the fullscreen viewers' headers, and media settings overrides.

--

Wiring, passing parameters, and docs updates also inflate the file counts of those PRs, but I think as three separate PRs it should be much easier to go through.

Again sorry for the large PR! This is a feature I've wanted for a while, and even have some branches pre-beta of trying to get the impl. right. Going forward, I'll make adjustments so they are more comprehensive to review.

If this works for you guys, I can start splitting it up and open # 1 later this week/next week when I can

@DeveloperBlue

Copy link
Copy Markdown
Contributor Author

isnt this already implemented? Not the same exact implementation as you. but the photo gallery image fan widget widget i made does the same for the most part.

Also just to clarify,
The fan stack in my PR is a heavily modified version of the existing fan stack you added- I did not rebuild that one from scratch.
It has the messageParts fixes I mention in my other comment, visual refactors to align with the new stack and the grid, and I extracted some helpers for reuse. There were also a few sizing/aspect-ratio issues I discovered while daily driving it. The existing stack hadn't gotten around to covering some of those issues yet, but I did also see the gesture fixes you made on master, and those have were folded in as well.

UX wise, I don't think the fan stack is the best widget for 2-3 images. Native iMessage uses the vertical collage, and Material uses the grid for those cases. On master, it is also currently gated to just iOS.

I actually had a branch pre-beta where I tried to implement the collage and stack, and I just could never get a stack as smooth as this one :P that was my biggest blocker from implementing this last year, but since you took care of it the rest was easy to follow up on.

Thanks again for the time you guys put into these.

@jjoelj

jjoelj commented Jul 30, 2026

Copy link
Copy Markdown
Member

If you can, make each collection implementation its own commit or even its own PR so that the cascading changes are easier to track. I want to be able to tell what exactly you changed about the stack, for example. Worry less about file count and more about the number of architectural changes or new widgets you're including in each PR.

Also make sure the PR check is passing

@zlshames

Copy link
Copy Markdown
Member

A couple questions:

  1. Does tapping and holding a specific image bring up the menu for that specific image part?
  2. Does reacting to a specific image apply it to that specific image part or the first image in the stack?

@DeveloperBlue

Copy link
Copy Markdown
Contributor Author

A couple questions:

  1. Does tapping and holding a specific image bring up the menu for that specific image part?
  2. Does reacting to a specific image apply it to that specific image part or the first image in the stack?

Yes and yes, they both target the specific image part

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.

3 participants