mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Show room encryption state in the composer (#3841)
* Fixes #3835 - Show room encryption state in the composer * Update the preview test snapshots * Update the UI test snapshots.
This commit is contained in:
@@ -73,6 +73,8 @@ struct ComposerToolbarViewState: BindableState {
|
||||
var audioPlayerState: AudioPlayerState
|
||||
var audioRecorderState: AudioRecorderState
|
||||
|
||||
let isRoomEncrypted: Bool
|
||||
|
||||
var bindings: ComposerToolbarViewStateBindings
|
||||
|
||||
var isUploading: Bool {
|
||||
|
||||
@@ -66,6 +66,7 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
||||
title: L10n.commonVoiceMessage,
|
||||
duration: 0),
|
||||
audioRecorderState: .init(),
|
||||
isRoomEncrypted: roomProxy.isEncrypted,
|
||||
bindings: .init()),
|
||||
mediaProvider: mediaProvider)
|
||||
|
||||
|
||||
@@ -157,9 +157,11 @@ struct ComposerToolbar: View {
|
||||
selectedRange: $context.selectedRange,
|
||||
composerView: composerView,
|
||||
mode: context.viewState.composerMode,
|
||||
placeholder: placeholder,
|
||||
composerFormattingEnabled: context.composerFormattingEnabled,
|
||||
showResizeGrabber: context.composerFormattingEnabled,
|
||||
isExpanded: $context.composerExpanded) {
|
||||
isExpanded: $context.composerExpanded,
|
||||
isEncrypted: context.viewState.isRoomEncrypted) {
|
||||
sendMessage()
|
||||
} editAction: {
|
||||
context.send(viewAction: .editLastMessage)
|
||||
@@ -222,8 +224,16 @@ struct ComposerToolbar: View {
|
||||
private var placeholder: String {
|
||||
switch context.viewState.composerMode {
|
||||
case .reply(_, _, let isThread):
|
||||
return isThread ? L10n.actionReplyInThread : L10n.richTextEditorComposerPlaceholder
|
||||
return isThread ? L10n.actionReplyInThread : composerPlaceholder
|
||||
default:
|
||||
return composerPlaceholder
|
||||
}
|
||||
}
|
||||
|
||||
private var composerPlaceholder: String {
|
||||
if context.viewState.isRoomEncrypted {
|
||||
return L10n.richTextEditorComposerEncryptedPlaceholder
|
||||
} else {
|
||||
return L10n.richTextEditorComposerPlaceholder
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,16 @@ struct MessageComposer: View {
|
||||
@Binding var plainComposerText: NSAttributedString
|
||||
@Binding var presendCallback: (() -> Void)?
|
||||
@Binding var selectedRange: NSRange
|
||||
|
||||
let composerView: WysiwygComposerView
|
||||
let mode: ComposerMode
|
||||
let placeholder: String
|
||||
|
||||
let composerFormattingEnabled: Bool
|
||||
let showResizeGrabber: Bool
|
||||
@Binding var isExpanded: Bool
|
||||
let isEncrypted: Bool
|
||||
|
||||
let sendAction: () -> Void
|
||||
let editAction: () -> Void
|
||||
let pasteAction: PasteHandler
|
||||
@@ -37,7 +42,7 @@ struct MessageComposer: View {
|
||||
}
|
||||
|
||||
composerTextField
|
||||
.messageComposerStyle(header: header)
|
||||
.messageComposerStyle(header: header, isEncrypted: isEncrypted)
|
||||
// Explicitly disable all animations to fix weirdness with the header immediately
|
||||
// appearing whilst the text field and keyboard are still animating up to it.
|
||||
.animation(.noAnimation, value: mode)
|
||||
@@ -64,7 +69,7 @@ struct MessageComposer: View {
|
||||
onAppearAction()
|
||||
}
|
||||
} else {
|
||||
MessageComposerTextField(placeholder: L10n.richTextEditorComposerPlaceholder,
|
||||
MessageComposerTextField(placeholder: placeholder,
|
||||
text: $plainComposerText,
|
||||
presendCallback: $presendCallback,
|
||||
selectedRange: $selectedRange,
|
||||
@@ -195,8 +200,8 @@ private struct MessageComposerHeaderLabelStyle: LabelStyle {
|
||||
// MARK: - Style
|
||||
|
||||
extension View {
|
||||
func messageComposerStyle(header: some View = EmptyView()) -> some View {
|
||||
modifier(MessageComposerStyleModifier(header: header))
|
||||
func messageComposerStyle(header: some View = EmptyView(), isEncrypted: Bool) -> some View {
|
||||
modifier(MessageComposerStyleModifier(header: header, isEncrypted: isEncrypted))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,14 +209,20 @@ private struct MessageComposerStyleModifier<Header: View>: ViewModifier {
|
||||
private let composerShape = RoundedRectangle(cornerRadius: 21, style: .circular)
|
||||
|
||||
let header: Header
|
||||
let isEncrypted: Bool
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
VStack(alignment: .leading, spacing: -6) {
|
||||
header
|
||||
|
||||
content
|
||||
.tint(.compound.iconAccentTertiary)
|
||||
.padding(.vertical, 10)
|
||||
HStack(alignment: .top, spacing: 6) {
|
||||
icon
|
||||
.scaledOffset(y: 2)
|
||||
|
||||
content
|
||||
.tint(.compound.iconAccentTertiary)
|
||||
}
|
||||
.padding(.vertical, 10)
|
||||
}
|
||||
.padding(.horizontal, 12.0)
|
||||
.clipShape(composerShape)
|
||||
@@ -224,6 +235,17 @@ private struct MessageComposerStyleModifier<Header: View>: ViewModifier {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var icon: some View {
|
||||
if isEncrypted {
|
||||
CompoundIcon(\.lockSolid, size: .xSmall, relativeTo: .compound.bodyMD)
|
||||
.foregroundStyle(.compound.iconSuccessPrimary)
|
||||
} else {
|
||||
CompoundIcon(\.lockOff, size: .xSmall, relativeTo: .compound.bodyMD)
|
||||
.foregroundStyle(.compound.iconTertiary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
@@ -274,7 +296,8 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
|
||||
]
|
||||
|
||||
static func messageComposer(_ content: NSAttributedString = .init(string: ""),
|
||||
mode: ComposerMode = .default) -> MessageComposer {
|
||||
mode: ComposerMode = .default,
|
||||
placeholder: String = L10n.richTextEditorComposerEncryptedPlaceholder) -> MessageComposer {
|
||||
let viewModel = WysiwygComposerViewModel(minHeight: 22,
|
||||
maxExpandedHeight: 250)
|
||||
viewModel.setMarkdownContent(content.string)
|
||||
@@ -290,9 +313,11 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
|
||||
selectedRange: .constant(NSRange(location: 0, length: 0)),
|
||||
composerView: composerView,
|
||||
mode: mode,
|
||||
placeholder: placeholder,
|
||||
composerFormattingEnabled: false,
|
||||
showResizeGrabber: false,
|
||||
isExpanded: .constant(false),
|
||||
isEncrypted: false,
|
||||
sendAction: { },
|
||||
editAction: { },
|
||||
pasteAction: { _ in },
|
||||
@@ -307,14 +332,16 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
|
||||
messageComposer(.init(string: "Some message"),
|
||||
mode: .edit(originalEventOrTransactionID: .eventID(UUID().uuidString), type: .default))
|
||||
|
||||
let longMessage = "Short loin ground round tongue hamburger, fatback salami shoulder. Beef turkey sausage kielbasa strip steak. Alcatra capicola pig tail pancetta chislic."
|
||||
messageComposer(.init(string: longMessage),
|
||||
mode: .edit(originalEventOrTransactionID: .eventID(UUID().uuidString), type: .default))
|
||||
|
||||
messageComposer(mode: .reply(eventID: UUID().uuidString,
|
||||
replyDetails: .loaded(sender: .init(id: "Kirk"),
|
||||
eventID: "123",
|
||||
eventContent: .message(.text(.init(body: "Text: Where the wild things are")))),
|
||||
isThread: false))
|
||||
|
||||
Color.clear.frame(height: 20)
|
||||
|
||||
messageComposer(.init(string: "Some new caption"),
|
||||
mode: .edit(originalEventOrTransactionID: .eventID(UUID().uuidString), type: .addCaption))
|
||||
messageComposer(.init(string: "Some updated caption"),
|
||||
@@ -338,7 +365,8 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
|
||||
VStack(spacing: 8) {
|
||||
ForEach(replyTypes, id: \.self) { replyDetails in
|
||||
messageComposer(mode: .reply(eventID: UUID().uuidString,
|
||||
replyDetails: replyDetails, isThread: true))
|
||||
replyDetails: replyDetails, isThread: true),
|
||||
placeholder: L10n.actionReplyInThread)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user