diff --git a/ElementX/Resources/Assets.xcassets/images/media/microphone.imageset/Contents.json b/ElementX/Resources/Assets.xcassets/images/media/microphone.imageset/Contents.json new file mode 100644 index 000000000..d69e18648 --- /dev/null +++ b/ElementX/Resources/Assets.xcassets/images/media/microphone.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "microphone.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/ElementX/Resources/Assets.xcassets/images/media/microphone.imageset/microphone.svg b/ElementX/Resources/Assets.xcassets/images/media/microphone.imageset/microphone.svg new file mode 100644 index 000000000..7808332fc --- /dev/null +++ b/ElementX/Resources/Assets.xcassets/images/media/microphone.imageset/microphone.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/ElementX/Resources/Localizations/en.lproj/Localizable.strings b/ElementX/Resources/Localizations/en.lproj/Localizable.strings index 3bfd0c95a..536f943ce 100644 --- a/ElementX/Resources/Localizations/en.lproj/Localizable.strings +++ b/ElementX/Resources/Localizations/en.lproj/Localizable.strings @@ -148,6 +148,7 @@ "common_verification_cancelled" = "Verification cancelled"; "common_verification_complete" = "Verification complete"; "common_video" = "Video"; +"common_voice_message" = "Voice message"; "common_waiting" = "Waiting…"; "common_poll_end_confirmation" = "Are you sure you want to end this poll?"; "common_poll_summary" = "Poll: %1$@"; diff --git a/ElementX/Sources/Generated/Assets.swift b/ElementX/Sources/Generated/Assets.swift index fd93f899b..5ccdf4761 100644 --- a/ElementX/Sources/Generated/Assets.swift +++ b/ElementX/Sources/Generated/Assets.swift @@ -65,6 +65,7 @@ internal enum Asset { internal static let locationPointer = ImageAsset(name: "images/location-pointer") internal static let mediaPause = ImageAsset(name: "images/media-pause") internal static let mediaPlay = ImageAsset(name: "images/media-play") + internal static let microphone = ImageAsset(name: "images/microphone") internal static let addReaction = ImageAsset(name: "images/add-reaction") internal static let copy = ImageAsset(name: "images/copy") internal static let editOutline = ImageAsset(name: "images/edit-outline") diff --git a/ElementX/Sources/Generated/Strings.swift b/ElementX/Sources/Generated/Strings.swift index 2bf203476..c568229b7 100644 --- a/ElementX/Sources/Generated/Strings.swift +++ b/ElementX/Sources/Generated/Strings.swift @@ -332,6 +332,8 @@ public enum L10n { public static var commonVerificationComplete: String { return L10n.tr("Localizable", "common_verification_complete") } /// Video public static var commonVideo: String { return L10n.tr("Localizable", "common_video") } + /// Voice message + public static var commonVoiceMessage: String { return L10n.tr("Localizable", "common_voice_message") } /// Waiting… public static var commonWaiting: String { return L10n.tr("Localizable", "common_waiting") } /// %1$@ crashed the last time it was used. Would you like to share a crash report with us? diff --git a/ElementX/Sources/Screens/RoomScreen/View/Replies/TimelineReplyView.swift b/ElementX/Sources/Screens/RoomScreen/View/Replies/TimelineReplyView.swift index e4e7321ee..4be9b085e 100644 --- a/ElementX/Sources/Screens/RoomScreen/View/Replies/TimelineReplyView.swift +++ b/ElementX/Sources/Screens/RoomScreen/View/Replies/TimelineReplyView.swift @@ -30,7 +30,7 @@ struct TimelineReplyView: View { switch timelineItemReplyDetails { case .loaded(let sender, let content): switch content { - case .audio(let content), .voice(let content): + case .audio(let content): ReplyView(sender: sender, plainBody: content.body, formattedBody: nil, @@ -62,6 +62,11 @@ struct TimelineReplyView: View { 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(Asset.Images.microphone.name), cornerRadii: iconCornerRadii)) case .location: ReplyView(sender: sender, plainBody: L10n.commonSharedLocation, @@ -182,23 +187,25 @@ struct TimelineReplyView: View { struct TimelineReplyView_Previews: PreviewProvider, TestablePreview { static let viewModel = RoomScreenViewModel.mock - static var previews: some View { - VStack(alignment: .leading, spacing: 20) { - TimelineReplyView(placement: .timeline, timelineItemReplyDetails: .notLoaded(eventID: "")) + static var previewItems: [TimelineReplyView] { + let imageSource = MediaSourceProxy(url: "https://mock.com", mimeType: "image/png") + + return [ + TimelineReplyView(placement: .timeline, timelineItemReplyDetails: .notLoaded(eventID: "")), - TimelineReplyView(placement: .timeline, timelineItemReplyDetails: .loading(eventID: "")) + TimelineReplyView(placement: .timeline, timelineItemReplyDetails: .loading(eventID: "")), TimelineReplyView(placement: .timeline, timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"), - contentType: .text(.init(body: "This is a reply")))) + contentType: .text(.init(body: "This is a reply")))), TimelineReplyView(placement: .timeline, timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"), - contentType: .emote(.init(body: "says hello")))) + contentType: .emote(.init(body: "says hello")))), TimelineReplyView(placement: .timeline, timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Bot"), - contentType: .notice(.init(body: "Hello world")))) + contentType: .notice(.init(body: "Hello world")))), TimelineReplyView(placement: .timeline, timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"), @@ -206,32 +213,46 @@ struct TimelineReplyView_Previews: PreviewProvider, TestablePreview { duration: 0, waveform: nil, source: nil, - contentType: 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)))) - - let imageSource = MediaSourceProxy(url: "https://mock.com", mimeType: "image/png") + contentType: nil)))), TimelineReplyView(placement: .timeline, timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"), contentType: .image(.init(body: "Some image", source: imageSource, - thumbnailSource: 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)))) + thumbnailSource: imageSource)))), TimelineReplyView(placement: .timeline, timelineItemReplyDetails: .loaded(sender: .init(id: "", displayName: "Alice"), - contentType: .location(.init(body: "")))) + contentType: .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)))) + ] + } + + static var previews: some View { + VStack(alignment: .leading, spacing: 20) { + ForEach(0..