mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 19:44:05 +00:00
Add support for rendering media captions in the timeline. (#3429)
This commit is contained in:
@@ -257,7 +257,7 @@ private extension EventBasedTimelineItemProtocol {
|
|||||||
switch self {
|
switch self {
|
||||||
case is ImageRoomTimelineItem, is VideoRoomTimelineItem:
|
case is ImageRoomTimelineItem, is VideoRoomTimelineItem:
|
||||||
// In case a reply detail or a thread decorator is present we render the color and the padding
|
// In case a reply detail or a thread decorator is present we render the color and the padding
|
||||||
return self.replyDetails != nil || self.isThreaded ? defaultColor : nil
|
return self.replyDetails != nil || self.isThreaded || self.hasMediaCaption ? defaultColor : nil
|
||||||
default:
|
default:
|
||||||
return defaultColor
|
return defaultColor
|
||||||
}
|
}
|
||||||
@@ -283,8 +283,7 @@ private extension EventBasedTimelineItemProtocol {
|
|||||||
// In case a reply detail or a thread decorator is present we render the color and the padding
|
// In case a reply detail or a thread decorator is present we render the color and the padding
|
||||||
case is ImageRoomTimelineItem,
|
case is ImageRoomTimelineItem,
|
||||||
is VideoRoomTimelineItem:
|
is VideoRoomTimelineItem:
|
||||||
return self.replyDetails != nil ||
|
return self.replyDetails != nil || self.isThreaded || self.hasMediaCaption ? defaultInsets : .zero
|
||||||
self.isThreaded ? defaultInsets : .zero
|
|
||||||
case let locationTimelineItem as LocationRoomTimelineItem:
|
case let locationTimelineItem as LocationRoomTimelineItem:
|
||||||
return locationTimelineItem.content.geoURI == nil ||
|
return locationTimelineItem.content.geoURI == nil ||
|
||||||
self.replyDetails != nil ||
|
self.replyDetails != nil ||
|
||||||
|
|||||||
@@ -152,9 +152,9 @@ private extension TimelineItemSendInfo {
|
|||||||
layoutType = switch timelineItem {
|
layoutType = switch timelineItem {
|
||||||
case is TextBasedRoomTimelineItem:
|
case is TextBasedRoomTimelineItem:
|
||||||
.overlay(capsuleStyle: false)
|
.overlay(capsuleStyle: false)
|
||||||
case is ImageRoomTimelineItem,
|
case let message as EventBasedMessageTimelineItemProtocol where message is ImageRoomTimelineItem || message is VideoRoomTimelineItem:
|
||||||
is VideoRoomTimelineItem,
|
.overlay(capsuleStyle: !message.hasMediaCaption)
|
||||||
is StickerRoomTimelineItem:
|
case is StickerRoomTimelineItem:
|
||||||
.overlay(capsuleStyle: true)
|
.overlay(capsuleStyle: true)
|
||||||
case let locationTimelineItem as LocationRoomTimelineItem:
|
case let locationTimelineItem as LocationRoomTimelineItem:
|
||||||
.overlay(capsuleStyle: locationTimelineItem.content.geoURI != nil)
|
.overlay(capsuleStyle: locationTimelineItem.content.geoURI != nil)
|
||||||
|
|||||||
+43
-9
@@ -12,18 +12,35 @@ struct ImageRoomTimelineView: View {
|
|||||||
@EnvironmentObject private var context: TimelineViewModel.Context
|
@EnvironmentObject private var context: TimelineViewModel.Context
|
||||||
let timelineItem: ImageRoomTimelineItem
|
let timelineItem: ImageRoomTimelineItem
|
||||||
|
|
||||||
|
var hasMediaCaption: Bool { timelineItem.content.caption != nil }
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
TimelineStyler(timelineItem: timelineItem) {
|
TimelineStyler(timelineItem: timelineItem) {
|
||||||
LoadableImage(mediaSource: source,
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
mediaType: .timelineItem,
|
LoadableImage(mediaSource: source,
|
||||||
blurhash: timelineItem.content.blurhash,
|
mediaType: .timelineItem,
|
||||||
mediaProvider: context.mediaProvider) {
|
blurhash: timelineItem.content.blurhash,
|
||||||
placeholder
|
mediaProvider: context.mediaProvider) {
|
||||||
|
placeholder
|
||||||
|
}
|
||||||
|
.timelineMediaFrame(height: timelineItem.content.height,
|
||||||
|
aspectRatio: timelineItem.content.aspectRatio)
|
||||||
|
.accessibilityElement(children: .ignore)
|
||||||
|
.accessibilityLabel(L10n.commonImage)
|
||||||
|
// This clip shape is distinct from the one in the styler as that one
|
||||||
|
// operates on the entire message so wouldn't round the bottom corners.
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: hasMediaCaption ? 6 : 0))
|
||||||
|
|
||||||
|
if let attributedCaption = timelineItem.content.formattedCaption {
|
||||||
|
FormattedBodyText(attributedString: attributedCaption,
|
||||||
|
additionalWhitespacesCount: timelineItem.additionalWhitespaces(),
|
||||||
|
boostEmojiSize: true)
|
||||||
|
} else if let caption = timelineItem.content.caption {
|
||||||
|
FormattedBodyText(text: caption,
|
||||||
|
additionalWhitespacesCount: timelineItem.additionalWhitespaces(),
|
||||||
|
boostEmojiSize: true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.timelineMediaFrame(height: timelineItem.content.height,
|
|
||||||
aspectRatio: timelineItem.content.aspectRatio)
|
|
||||||
.accessibilityElement(children: .ignore)
|
|
||||||
.accessibilityLabel(L10n.commonImage)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +104,23 @@ struct ImageRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
aspectRatio: 0.7,
|
aspectRatio: 0.7,
|
||||||
blurhash: "L%KUc%kqS$RP?Ks,WEf8OlrqaekW",
|
blurhash: "L%KUc%kqS$RP?Ks,WEf8OlrqaekW",
|
||||||
contentType: .gif)))
|
contentType: .gif)))
|
||||||
|
|
||||||
|
ImageRoomTimelineView(timelineItem: ImageRoomTimelineItem(id: .randomEvent,
|
||||||
|
timestamp: "Now",
|
||||||
|
isOutgoing: false,
|
||||||
|
isEditable: false,
|
||||||
|
canBeRepliedTo: true,
|
||||||
|
isThreaded: false,
|
||||||
|
sender: .init(id: "Bob"),
|
||||||
|
content: .init(filename: "Blurhashed.jpg",
|
||||||
|
caption: "This is a great image 😎",
|
||||||
|
source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"),
|
||||||
|
thumbnailSource: nil,
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
aspectRatio: 1,
|
||||||
|
blurhash: "L%KUc%kqS$RP?Ks,WEf8OlrqaekW",
|
||||||
|
contentType: .gif)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-5
@@ -12,13 +12,30 @@ struct VideoRoomTimelineView: View {
|
|||||||
@EnvironmentObject private var context: TimelineViewModel.Context
|
@EnvironmentObject private var context: TimelineViewModel.Context
|
||||||
let timelineItem: VideoRoomTimelineItem
|
let timelineItem: VideoRoomTimelineItem
|
||||||
|
|
||||||
|
private var hasMediaCaption: Bool { timelineItem.content.caption != nil }
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
TimelineStyler(timelineItem: timelineItem) {
|
TimelineStyler(timelineItem: timelineItem) {
|
||||||
thumbnail
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
.timelineMediaFrame(height: timelineItem.content.height,
|
thumbnail
|
||||||
aspectRatio: timelineItem.content.aspectRatio)
|
.timelineMediaFrame(height: timelineItem.content.height,
|
||||||
.accessibilityElement(children: .ignore)
|
aspectRatio: timelineItem.content.aspectRatio)
|
||||||
.accessibilityLabel(L10n.commonVideo)
|
.accessibilityElement(children: .ignore)
|
||||||
|
.accessibilityLabel(L10n.commonVideo)
|
||||||
|
// This clip shape is distinct from the one in the styler as that one
|
||||||
|
// operates on the entire message so wouldn't round the bottom corners.
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: hasMediaCaption ? 6 : 0))
|
||||||
|
|
||||||
|
if let attributedCaption = timelineItem.content.formattedCaption {
|
||||||
|
FormattedBodyText(attributedString: attributedCaption,
|
||||||
|
additionalWhitespacesCount: timelineItem.additionalWhitespaces(),
|
||||||
|
boostEmojiSize: true)
|
||||||
|
} else if let caption = timelineItem.content.caption {
|
||||||
|
FormattedBodyText(text: caption,
|
||||||
|
additionalWhitespacesCount: timelineItem.additionalWhitespaces(),
|
||||||
|
boostEmojiSize: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +117,19 @@ struct VideoRoomTimelineView_Previews: PreviewProvider, TestablePreview {
|
|||||||
thumbnailSource: nil,
|
thumbnailSource: nil,
|
||||||
aspectRatio: 0.7,
|
aspectRatio: 0.7,
|
||||||
blurhash: "L%KUc%kqS$RP?Ks,WEf8OlrqaekW")))
|
blurhash: "L%KUc%kqS$RP?Ks,WEf8OlrqaekW")))
|
||||||
|
|
||||||
|
VideoRoomTimelineView(timelineItem: VideoRoomTimelineItem(id: .randomEvent,
|
||||||
|
timestamp: "Now",
|
||||||
|
isOutgoing: false,
|
||||||
|
isEditable: false,
|
||||||
|
canBeRepliedTo: true,
|
||||||
|
isThreaded: false,
|
||||||
|
sender: .init(id: "Bob"),
|
||||||
|
content: .init(filename: "video.mp4",
|
||||||
|
caption: "This is a caption",
|
||||||
|
duration: 21,
|
||||||
|
source: nil,
|
||||||
|
thumbnailSource: nil)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
@@ -24,3 +24,20 @@ protocol EventBasedMessageTimelineItemProtocol: EventBasedTimelineItemProtocol {
|
|||||||
var contentType: EventBasedMessageTimelineItemContentType { get }
|
var contentType: EventBasedMessageTimelineItemContentType { get }
|
||||||
var isThreaded: Bool { get }
|
var isThreaded: Bool { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension EventBasedMessageTimelineItemProtocol {
|
||||||
|
var hasMediaCaption: Bool {
|
||||||
|
switch contentType {
|
||||||
|
case .audio(let content):
|
||||||
|
content.caption != nil
|
||||||
|
case .file(let content):
|
||||||
|
content.caption != nil
|
||||||
|
case .image(let content):
|
||||||
|
content.caption != nil
|
||||||
|
case .video(let content):
|
||||||
|
content.caption != nil
|
||||||
|
case .emote, .notice, .text, .location, .voice:
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f63e72b33f82f8b679dd8b1fc810078438914d70d395c23abd13571d01643597
|
oid sha256:6cf2fd3de65756ae06e150b5353386e9b5bb554d18da2f77b0cf54246c3920eb
|
||||||
size 227546
|
size 285656
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f63e72b33f82f8b679dd8b1fc810078438914d70d395c23abd13571d01643597
|
oid sha256:6cf2fd3de65756ae06e150b5353386e9b5bb554d18da2f77b0cf54246c3920eb
|
||||||
size 227546
|
size 285656
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:fb0bce1bf5571926c9ae760503e3aff11bfa962d646e257ab9481bc9496b95a6
|
oid sha256:0b2d7c9d9bf570589eb48fbbb11bf11f2970229599a5be9b06d3f54e855e0d06
|
||||||
size 169079
|
size 224889
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:fb0bce1bf5571926c9ae760503e3aff11bfa962d646e257ab9481bc9496b95a6
|
oid sha256:0b2d7c9d9bf570589eb48fbbb11bf11f2970229599a5be9b06d3f54e855e0d06
|
||||||
size 169079
|
size 224889
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:919c37cec762f3a5ead4e55e611e78bc3b6a52fdb6c2f2435d387511bdaf3bb3
|
oid sha256:f0f9e472dd0a7675c25bc5856aca8f3e8ed94b157aa2dea3683e8a7cf17b588c
|
||||||
size 81177
|
size 94892
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:919c37cec762f3a5ead4e55e611e78bc3b6a52fdb6c2f2435d387511bdaf3bb3
|
oid sha256:f0f9e472dd0a7675c25bc5856aca8f3e8ed94b157aa2dea3683e8a7cf17b588c
|
||||||
size 81177
|
size 94892
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:bbf8a9e38c8188356a7e9758b7afbcbc84c4b58b4ada32999e1591883c99704c
|
oid sha256:8e4e25d87b4335854f8cd67072ef0e8e89a50a9a56dbc10b6cf01ee725731767
|
||||||
size 40312
|
size 52197
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:bbf8a9e38c8188356a7e9758b7afbcbc84c4b58b4ada32999e1591883c99704c
|
oid sha256:8e4e25d87b4335854f8cd67072ef0e8e89a50a9a56dbc10b6cf01ee725731767
|
||||||
size 40312
|
size 52197
|
||||||
|
|||||||
Reference in New Issue
Block a user