Add the gallery timeline item rendered as a placeholder

Introduces the GalleryRoomTimelineItem and its typed GalleryItem model (reusing the existing per-message content types), builds it in the RoomTimelineItemFactory and routes it through RoomTimelineItemView. For now it renders as a placeholder; the grid/list media views and the full-screen preview land in follow-up PRs.

Co-authored-by: svetoslav.mitov <svetoslav.mitov@sportinno.com>
This commit is contained in:
Mauro Romito
2026-07-24 11:10:17 +02:00
committed by Mauro
parent 3796fdc966
commit 4a9cd02fbc
12 changed files with 289 additions and 22 deletions
@@ -129,6 +129,13 @@ struct TimelineReplyView: View {
plainBody: L10n.commonSharedLocation,
formattedBody: nil,
icon: .init(kind: .icon(\.locationPin)))
case .gallery(let content):
ReplyView(sender: sender,
plainBody: content.caption ?? content.body,
formattedBody: content.formattedCaption,
icon: content.items.first?.thumbnailSource.map { .init(kind: .mediaSource($0)) }
?? content.items.first?.mediaSource.map { .init(kind: .mediaSource($0)) }
?? .init(kind: .icon(\.attachment)))
}
case .poll(let question):
ReplyView(sender: sender,
@@ -82,6 +82,12 @@ struct TimelineThreadSummaryView: View {
plainBody: L10n.commonSharedLocation,
formattedBody: nil,
numberOfReplies: numberOfReplies)
case .gallery(let content):
ThreadView(senderID: senderID,
sender: sender,
plainBody: content.caption ?? content.body,
formattedBody: content.formattedCaption,
numberOfReplies: numberOfReplies)
}
case .poll(let question):
ThreadView(senderID: senderID,
@@ -0,0 +1,22 @@
//
// Copyright 2026 Element Creations Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import Compound
import SwiftUI
struct GalleryRoomTimelineView: View {
let timelineItem: GalleryRoomTimelineItem
var body: some View {
TimelineStyler(timelineItem: timelineItem) {
// Placeholder rendering — the grid/list media views land in a follow-up.
FormattedBodyText(text: timelineItem.content.caption ?? timelineItem.content.body,
trailingReservedSize: timelineItem.trailingReservedSize,
boostFontSize: timelineItem.shouldBoost)
}
}
}