Reply to a poll (#2087)

* Refactor TimelineItemReplyDetails for polls

* Fix reply for polls

* Update reply details factory

* Revert Poll Hashable conformance

* PR comments
This commit is contained in:
Alfonso Grillo
2023-11-15 16:57:34 +01:00
committed by GitHub
parent 0b9da83470
commit 9f1092b0b6
8 changed files with 179 additions and 150 deletions
@@ -31,48 +31,56 @@ struct TimelineReplyView: View {
switch timelineItemReplyDetails {
case .loaded(let sender, let content):
switch content {
case .audio(let content):
case .message(let content):
switch content {
case .audio(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: nil,
icon: .init(kind: .systemIcon("waveform"), cornerRadii: iconCornerRadii))
case .emote(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: content.formattedBody)
case .file(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: nil,
icon: .init(kind: .iconAsset(Asset.Images.document), cornerRadii: iconCornerRadii))
case .image(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: nil,
icon: .init(kind: .mediaSource(content.thumbnailSource ?? content.source), cornerRadii: iconCornerRadii))
case .notice(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: content.formattedBody)
case .text(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: content.formattedBody)
case .video(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: nil,
icon: content.thumbnailSource.map { .init(kind: .mediaSource($0), cornerRadii: iconCornerRadii) })
case .voice:
ReplyView(sender: sender,
plainBody: L10n.commonVoiceMessage,
formattedBody: nil,
icon: .init(kind: .icon(\.micOnOutline), cornerRadii: iconCornerRadii))
case .location:
ReplyView(sender: sender,
plainBody: L10n.commonSharedLocation,
formattedBody: nil,
icon: .init(kind: .iconAsset(Asset.Images.addLocation), cornerRadii: iconCornerRadii))
}
case .poll(let question):
ReplyView(sender: sender,
plainBody: content.body,
plainBody: question,
formattedBody: nil,
icon: .init(kind: .systemIcon("waveform"), cornerRadii: iconCornerRadii))
case .emote(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: content.formattedBody)
case .file(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: nil,
icon: .init(kind: .iconAsset(Asset.Images.document), cornerRadii: iconCornerRadii))
case .image(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: nil,
icon: .init(kind: .mediaSource(content.thumbnailSource ?? content.source), cornerRadii: iconCornerRadii))
case .notice(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: content.formattedBody)
case .text(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: content.formattedBody)
case .video(let content):
ReplyView(sender: sender,
plainBody: content.body,
formattedBody: nil,
icon: content.thumbnailSource.map { .init(kind: .mediaSource($0), cornerRadii: iconCornerRadii) })
case .voice:
ReplyView(sender: sender,
plainBody: L10n.commonVoiceMessage,
formattedBody: nil,
icon: .init(kind: .icon(\.micOnOutline), cornerRadii: iconCornerRadii))
case .location:
ReplyView(sender: sender,
plainBody: L10n.commonSharedLocation,
formattedBody: nil,
icon: .init(kind: .iconAsset(Asset.Images.addLocation), cornerRadii: iconCornerRadii))
icon: .init(kind: .iconAsset(Asset.Images.timelinePoll), cornerRadii: iconCornerRadii))
}
default:
LoadingReplyView()
@@ -223,7 +231,7 @@ struct TimelineReplyView_Previews: PreviewProvider, TestablePreview {
static var previewItems: [TimelineReplyView] {
let imageSource = MediaSourceProxy(url: "https://mock.com", mimeType: "image/png")
return [
TimelineReplyView(placement: .timeline, timelineItemReplyDetails: .notLoaded(eventID: "")),
@@ -231,60 +239,60 @@ struct TimelineReplyView_Previews: PreviewProvider, TestablePreview {
TimelineReplyView(placement: .timeline,
timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "This is a reply")))),
eventContent: .message(.text(.init(body: "This is a reply"))))),
TimelineReplyView(placement: .timeline,
timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .emote(.init(body: "says hello")))),
eventContent: .message(.emote(.init(body: "says hello"))))),
TimelineReplyView(placement: .timeline,
timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Bob"),
contentType: .notice(.init(body: "Hello world")))),
eventContent: .message(.notice(.init(body: "Hello world"))))),
TimelineReplyView(placement: .timeline,
timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .audio(.init(body: "Some audio",
duration: 0,
waveform: nil,
source: nil,
contentType: nil)))),
eventContent: .message(.audio(.init(body: "Some audio",
duration: 0,
waveform: nil,
source: nil,
contentType: nil))))),
TimelineReplyView(placement: .timeline,
timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .file(.init(body: "Some file",
source: nil,
thumbnailSource: nil,
contentType: nil)))),
eventContent: .message(.file(.init(body: "Some file",
source: nil,
thumbnailSource: nil,
contentType: nil))))),
TimelineReplyView(placement: .timeline,
timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .image(.init(body: "Some image",
source: imageSource,
thumbnailSource: imageSource)))),
eventContent: .message(.image(.init(body: "Some image",
source: imageSource,
thumbnailSource: imageSource))))),
TimelineReplyView(placement: .timeline,
timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .video(.init(body: "Some video",
duration: 0,
source: nil,
thumbnailSource: imageSource)))),
eventContent: .message(.video(.init(body: "Some video",
duration: 0,
source: nil,
thumbnailSource: imageSource))))),
TimelineReplyView(placement: .timeline,
timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .location(.init(body: "")))),
eventContent: .message(.location(.init(body: ""))))),
TimelineReplyView(placement: .timeline,
timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .voice(.init(body: "Some voice message",
duration: 0,
waveform: nil,
source: nil,
contentType: nil)))),
eventContent: .message(.voice(.init(body: "Some voice message",
duration: 0,
waveform: nil,
source: nil,
contentType: nil))))),
TimelineReplyView(placement: .timeline,
timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Bob"),
contentType: .notice(.init(body: "", formattedBody: attributedStringWithMention)))),
eventContent: .message(.notice(.init(body: "", formattedBody: attributedStringWithMention))))),
TimelineReplyView(placement: .timeline,
timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Bob"),
contentType: .notice(.init(body: "", formattedBody: attributedStringWithAtRoomMention))))
eventContent: .message(.notice(.init(body: "", formattedBody: attributedStringWithAtRoomMention)))))
]
}
@@ -421,7 +421,8 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
sender: .init(id: "whoever"),
content: .init(body: "A long message that should be on multiple lines."),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))), groupStyle: .single))
eventContent: .message(.text(.init(body: "Short"))))),
groupStyle: .single))
AudioRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
timestamp: "10:42",
@@ -436,7 +437,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
source: nil,
contentType: nil),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))))
eventContent: .message(.text(.init(body: "Short"))))))
FileRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
timestamp: "10:42",
@@ -450,7 +451,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
thumbnailSource: nil,
contentType: nil),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))))
eventContent: .message(.text(.init(body: "Short"))))))
ImageRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
timestamp: "10:42",
isOutgoing: true,
@@ -460,7 +461,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
sender: .init(id: ""),
content: .init(body: "Some image", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"), thumbnailSource: nil),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))))
eventContent: .message(.text(.init(body: "Short"))))))
LocationRoomTimelineView(timelineItem: .init(id: .random,
timestamp: "Now",
isOutgoing: false,
@@ -473,7 +474,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
longitude: 12.496366),
description: "Location description description description description description description description description"),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))))
eventContent: .message(.text(.init(body: "Short"))))))
LocationRoomTimelineView(timelineItem: .init(id: .random,
timestamp: "Now",
isOutgoing: false,
@@ -484,7 +485,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
content: .init(body: "Fallback geo uri description",
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: nil),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))))
eventContent: .message(.text(.init(body: "Short"))))))
VoiceMessageRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
timestamp: "10:42",
@@ -499,7 +500,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
source: nil,
contentType: nil),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))),
eventContent: .message(.text(.init(body: "Short"))))),
playerState: AudioPlayerState(id: .timelineItemIdentifier(.random), duration: 10, waveform: EstimatedWaveform.mockWaveform))
}
.environmentObject(viewModel.context)
@@ -530,7 +531,8 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
sender: .init(id: "whoever"),
content: .init(body: "A long message that should be on multiple lines."),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))), groupStyle: .single))
eventContent: .message(.text(.init(body: "Short"))))),
groupStyle: .single))
RoomTimelineItemView(viewState: .init(item: TextRoomTimelineItem(id: .init(timelineID: ""),
timestamp: "10:42",
@@ -541,7 +543,8 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
sender: .init(id: "whoever"),
content: .init(body: "Short message"),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "A long message that should be on more than 2 lines and so will be clipped by the layout.")))), groupStyle: .single))
eventContent: .message(.text(.init(body: "A long message that should be on more than 2 lines and so will be clipped by the layout."))))),
groupStyle: .single))
}
.environmentObject(viewModel.context)
}
@@ -156,8 +156,9 @@ struct TimelineItemPlainStylerView_Previews: PreviewProvider, TestablePreview {
sender: .init(id: "whoever"),
content: .init(body: "A long message that should be on multiple lines."),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))), groupStyle: .single))
eventContent: .message(.text(.init(body: "Short"))))),
groupStyle: .single))
AudioRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
timestamp: "10:42",
isOutgoing: true,
@@ -171,7 +172,7 @@ struct TimelineItemPlainStylerView_Previews: PreviewProvider, TestablePreview {
source: nil,
contentType: nil),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))))
eventContent: .message(.text(.init(body: "Short"))))))
FileRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
timestamp: "10:42",
isOutgoing: false,
@@ -184,7 +185,7 @@ struct TimelineItemPlainStylerView_Previews: PreviewProvider, TestablePreview {
thumbnailSource: nil,
contentType: nil),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))))
eventContent: .message(.text(.init(body: "Short"))))))
ImageRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
timestamp: "10:42",
isOutgoing: true,
@@ -194,7 +195,7 @@ struct TimelineItemPlainStylerView_Previews: PreviewProvider, TestablePreview {
sender: .init(id: ""),
content: .init(body: "Some image", source: MediaSourceProxy(url: .picturesDirectory, mimeType: "image/png"), thumbnailSource: nil),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))))
eventContent: .message(.text(.init(body: "Short"))))))
LocationRoomTimelineView(timelineItem: .init(id: .random,
timestamp: "Now",
isOutgoing: false,
@@ -207,7 +208,7 @@ struct TimelineItemPlainStylerView_Previews: PreviewProvider, TestablePreview {
longitude: 12.496366),
description: "Location description description description description description description description description"),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))))
eventContent: .message(.text(.init(body: "Short"))))))
LocationRoomTimelineView(timelineItem: .init(id: .random,
timestamp: "Now",
isOutgoing: false,
@@ -218,7 +219,7 @@ struct TimelineItemPlainStylerView_Previews: PreviewProvider, TestablePreview {
content: .init(body: "Fallback geo uri description",
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: nil),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))))
eventContent: .message(.text(.init(body: "Short"))))))
VoiceMessageRoomTimelineView(timelineItem: .init(id: .init(timelineID: ""),
timestamp: "10:42",
isOutgoing: true,
@@ -232,12 +233,12 @@ struct TimelineItemPlainStylerView_Previews: PreviewProvider, TestablePreview {
source: nil,
contentType: nil),
replyDetails: .loaded(sender: .init(id: "", displayName: "Alice"),
contentType: .text(.init(body: "Short")))),
eventContent: .message(.text(.init(body: "Short"))))),
playerState: AudioPlayerState(id: .timelineItemIdentifier(.init(timelineID: "")), duration: 10, waveform: EstimatedWaveform.mockWaveform))
}
.environmentObject(viewModel.context)
}
static var previews: some View {
VStack(alignment: .leading, spacing: 0) {
ForEach(1..<MockRoomTimelineController().timelineItems.count, id: \.self) { index in
@@ -136,6 +136,6 @@ struct LocationRoomTimelineView_Previews: PreviewProvider, TestablePreview {
content: .init(body: "Fallback geo uri description",
geoURI: .init(latitude: 41.902782, longitude: 12.496366), description: "Location description description description description description description description description"),
replyDetails: .loaded(sender: .init(id: "Someone"),
contentType: .text(.init(body: "The thread content goes 'ere.")))))
eventContent: .message(.text(.init(body: "The thread content goes 'ere."))))))
}
}