mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Update how file captions are rendered (#3554)
* Update the File/Audio captions layout to match Figma. * Fix caption sizing issues. The send info label was being added incorrectly. * Update icon size and regenerate snapshots. * Fix a regression in the location timeline item layout.
This commit is contained in:
+32
-24
@@ -10,18 +10,16 @@ import SwiftUI
|
||||
|
||||
struct AudioRoomTimelineView: View {
|
||||
let timelineItem: AudioRoomTimelineItem
|
||||
|
||||
|
||||
var body: some View {
|
||||
TimelineStyler(timelineItem: timelineItem) {
|
||||
Label(title: { Text(timelineItem.body) },
|
||||
icon: { Image(systemName: "waveform")
|
||||
.foregroundColor(.compound.iconPrimary)
|
||||
})
|
||||
.labelStyle(RoomTimelineViewLabelStyle())
|
||||
.font(.compound.bodyLG)
|
||||
.padding(.vertical, 12)
|
||||
.padding(.horizontal, 6)
|
||||
.accessibilityLabel(L10n.commonAudio)
|
||||
MediaFileRoomTimelineContent(filename: timelineItem.content.filename,
|
||||
fileSize: timelineItem.content.fileSize,
|
||||
caption: timelineItem.content.caption,
|
||||
formattedCaption: timelineItem.content.formattedCaption,
|
||||
additionalWhitespaces: timelineItem.additionalWhitespaces(),
|
||||
isAudioFile: true)
|
||||
.accessibilityLabel(L10n.commonAudio)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,21 +28,31 @@ struct AudioRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = TimelineViewModel.mock
|
||||
|
||||
static var previews: some View {
|
||||
body.environmentObject(viewModel.context)
|
||||
VStack(spacing: 20) {
|
||||
AudioRoomTimelineView(timelineItem: makeItem(filename: "audio.ogg",
|
||||
fileSize: 2 * 1024 * 1024))
|
||||
|
||||
AudioRoomTimelineView(timelineItem: makeItem(filename: "Best Song Ever.mp3",
|
||||
fileSize: 7 * 1024 * 1024,
|
||||
caption: "This song rocks!"))
|
||||
}
|
||||
.environmentObject(viewModel.context)
|
||||
}
|
||||
|
||||
static var body: some View {
|
||||
AudioRoomTimelineView(timelineItem: AudioRoomTimelineItem(id: .randomEvent,
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
canBeRepliedTo: true,
|
||||
isThreaded: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(filename: "audio.ogg",
|
||||
duration: 300,
|
||||
waveform: nil,
|
||||
source: nil,
|
||||
contentType: nil)))
|
||||
static func makeItem(filename: String, fileSize: UInt, caption: String? = nil) -> AudioRoomTimelineItem {
|
||||
.init(id: .randomEvent,
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
canBeRepliedTo: true,
|
||||
isThreaded: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(filename: filename,
|
||||
caption: caption,
|
||||
duration: 300,
|
||||
waveform: nil,
|
||||
source: nil,
|
||||
fileSize: fileSize,
|
||||
contentType: nil))
|
||||
}
|
||||
}
|
||||
|
||||
+95
-48
@@ -13,63 +13,110 @@ struct FileRoomTimelineView: View {
|
||||
|
||||
var body: some View {
|
||||
TimelineStyler(timelineItem: timelineItem) {
|
||||
Label { Text(timelineItem.body) } icon: {
|
||||
CompoundIcon(\.document)
|
||||
.foregroundColor(.compound.iconPrimary)
|
||||
}
|
||||
.labelStyle(RoomTimelineViewLabelStyle())
|
||||
.font(.compound.bodyLG)
|
||||
.padding(.vertical, 8)
|
||||
.padding(.horizontal, 6)
|
||||
.accessibilityLabel(L10n.commonFile)
|
||||
MediaFileRoomTimelineContent(filename: timelineItem.content.filename,
|
||||
fileSize: timelineItem.content.fileSize,
|
||||
caption: timelineItem.content.caption,
|
||||
formattedCaption: timelineItem.content.formattedCaption,
|
||||
additionalWhitespaces: timelineItem.additionalWhitespaces())
|
||||
.accessibilityLabel(L10n.commonFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Content
|
||||
|
||||
struct MediaFileRoomTimelineContent: View {
|
||||
let filename: String
|
||||
let fileSize: UInt?
|
||||
let caption: String?
|
||||
let formattedCaption: AttributedString?
|
||||
let additionalWhitespaces: Int
|
||||
var isAudioFile = false
|
||||
|
||||
var icon: KeyPath<CompoundIcons, Image> {
|
||||
isAudioFile ? \.audio : \.attachment
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
filePreview
|
||||
|
||||
if let formattedCaption {
|
||||
FormattedBodyText(attributedString: formattedCaption,
|
||||
additionalWhitespacesCount: additionalWhitespaces)
|
||||
} else if let caption {
|
||||
FormattedBodyText(text: caption,
|
||||
additionalWhitespacesCount: additionalWhitespaces)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var filePreview: some View {
|
||||
Label {
|
||||
HStack(spacing: 4) {
|
||||
Text(filename)
|
||||
.truncationMode(.middle)
|
||||
|
||||
if let fileSize {
|
||||
Text("(\(fileSize.formatted(.byteCount(style: .file))))")
|
||||
.layoutPriority(1) // We want the filename to truncate rather than the size.
|
||||
}
|
||||
}
|
||||
.font(.compound.bodyLG)
|
||||
.foregroundStyle(.compound.textPrimary)
|
||||
.lineLimit(1)
|
||||
} icon: {
|
||||
CompoundIcon(icon, size: .xSmall, relativeTo: .body)
|
||||
.foregroundColor(.compound.iconPrimary)
|
||||
.scaledPadding(8)
|
||||
.background(.compound.iconOnSolidPrimary, in: Circle())
|
||||
}
|
||||
.labelStyle(.custom(spacing: 8, alignment: .center))
|
||||
.padding(.horizontal, 4) // Add to the styler's padding of 8, as we use the default insets for the caption.
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct FileRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = TimelineViewModel.mock
|
||||
|
||||
static var previews: some View {
|
||||
body.environmentObject(viewModel.context)
|
||||
VStack(spacing: 20.0) {
|
||||
FileRoomTimelineView(timelineItem: makeItem(filename: "document.pdf"))
|
||||
|
||||
FileRoomTimelineView(timelineItem: makeItem(filename: "document.pdf",
|
||||
fileSize: 3 * 1024 * 1024))
|
||||
|
||||
FileRoomTimelineView(timelineItem: makeItem(filename: "spreadsheet.xlsx",
|
||||
fileSize: 17 * 1024,
|
||||
caption: "The important figures you asked me to send over."))
|
||||
|
||||
FileRoomTimelineView(timelineItem: makeItem(filename: "document.txt",
|
||||
fileSize: 456,
|
||||
caption: "Plain caption",
|
||||
formattedCaption: "Formatted caption"))
|
||||
}
|
||||
.environmentObject(viewModel.context)
|
||||
}
|
||||
|
||||
static var body: some View {
|
||||
VStack(spacing: 20.0) {
|
||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .randomEvent,
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
canBeRepliedTo: true,
|
||||
isThreaded: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(filename: "document.pdf",
|
||||
source: nil,
|
||||
thumbnailSource: nil,
|
||||
contentType: nil)))
|
||||
|
||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .randomEvent,
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
canBeRepliedTo: true,
|
||||
isThreaded: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(filename: "document.docx",
|
||||
source: nil,
|
||||
thumbnailSource: nil,
|
||||
contentType: nil)))
|
||||
|
||||
FileRoomTimelineView(timelineItem: FileRoomTimelineItem(id: .randomEvent,
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
canBeRepliedTo: true,
|
||||
isThreaded: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(filename: "document.txt",
|
||||
source: nil,
|
||||
thumbnailSource: nil,
|
||||
contentType: nil)))
|
||||
}
|
||||
static func makeItem(filename: String,
|
||||
fileSize: UInt? = nil,
|
||||
caption: String? = nil,
|
||||
formattedCaption: AttributedString? = nil) -> FileRoomTimelineItem {
|
||||
.init(id: .randomEvent,
|
||||
timestamp: "Now",
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
canBeRepliedTo: true,
|
||||
isThreaded: false,
|
||||
sender: .init(id: "Bob"),
|
||||
content: .init(filename: filename,
|
||||
caption: caption,
|
||||
formattedCaption: formattedCaption,
|
||||
source: nil,
|
||||
fileSize: fileSize,
|
||||
thumbnailSource: nil,
|
||||
contentType: nil))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user