mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 12:07:55 +00:00
Send html in plain text mode (#2246)
This commit is contained in:
@@ -6598,7 +6598,7 @@
|
||||
repositoryURL = "https://github.com/matrix-org/matrix-wysiwyg-composer-swift";
|
||||
requirement = {
|
||||
kind = exactVersion;
|
||||
version = 2.19.0;
|
||||
version = 2.22.0;
|
||||
};
|
||||
};
|
||||
96495DD8554E2F39D3954354 /* XCRemoteSwiftPackageReference "posthog-ios" */ = {
|
||||
|
||||
@@ -139,8 +139,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/matrix-org/matrix-wysiwyg-composer-swift",
|
||||
"state" : {
|
||||
"revision" : "0aa1308c43451fd077e332f72d6a32135f258834",
|
||||
"version" : "2.19.0"
|
||||
"revision" : "5d3bdd55f8c68c216f91191a501c0d7225057f92",
|
||||
"version" : "2.22.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -267,9 +267,8 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
||||
return
|
||||
}
|
||||
let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID)
|
||||
switch await roomProxy?.timeline.sendMessage(replyText,
|
||||
html: nil,
|
||||
intentionalMentions: .empty) {
|
||||
let messageContent = messageEventContentFromMarkdown(md: replyText)
|
||||
switch await roomProxy?.timeline.sendMessageEventContent(messageContent) {
|
||||
case .success:
|
||||
break
|
||||
default:
|
||||
|
||||
@@ -2628,12 +2628,12 @@ class TimelineProxyMock: TimelineProxyProtocol {
|
||||
var editMessageHtmlOriginalIntentionalMentionsCalled: Bool {
|
||||
return editMessageHtmlOriginalIntentionalMentionsCallsCount > 0
|
||||
}
|
||||
var editMessageHtmlOriginalIntentionalMentionsReceivedArguments: (message: String, html: String?, eventID: String, intentionalMentions: IntentionalMentions)?
|
||||
var editMessageHtmlOriginalIntentionalMentionsReceivedInvocations: [(message: String, html: String?, eventID: String, intentionalMentions: IntentionalMentions)] = []
|
||||
var editMessageHtmlOriginalIntentionalMentionsReceivedArguments: (message: String, html: String, eventID: String, intentionalMentions: IntentionalMentions)?
|
||||
var editMessageHtmlOriginalIntentionalMentionsReceivedInvocations: [(message: String, html: String, eventID: String, intentionalMentions: IntentionalMentions)] = []
|
||||
var editMessageHtmlOriginalIntentionalMentionsReturnValue: Result<Void, TimelineProxyError>!
|
||||
var editMessageHtmlOriginalIntentionalMentionsClosure: ((String, String?, String, IntentionalMentions) async -> Result<Void, TimelineProxyError>)?
|
||||
var editMessageHtmlOriginalIntentionalMentionsClosure: ((String, String, String, IntentionalMentions) async -> Result<Void, TimelineProxyError>)?
|
||||
|
||||
func editMessage(_ message: String, html: String?, original eventID: String, intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
||||
func editMessage(_ message: String, html: String, original eventID: String, intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
||||
editMessageHtmlOriginalIntentionalMentionsCallsCount += 1
|
||||
editMessageHtmlOriginalIntentionalMentionsReceivedArguments = (message: message, html: html, eventID: eventID, intentionalMentions: intentionalMentions)
|
||||
editMessageHtmlOriginalIntentionalMentionsReceivedInvocations.append((message: message, html: html, eventID: eventID, intentionalMentions: intentionalMentions))
|
||||
@@ -2887,12 +2887,12 @@ class TimelineProxyMock: TimelineProxyProtocol {
|
||||
var sendMessageHtmlInReplyToIntentionalMentionsCalled: Bool {
|
||||
return sendMessageHtmlInReplyToIntentionalMentionsCallsCount > 0
|
||||
}
|
||||
var sendMessageHtmlInReplyToIntentionalMentionsReceivedArguments: (message: String, html: String?, eventID: String?, intentionalMentions: IntentionalMentions)?
|
||||
var sendMessageHtmlInReplyToIntentionalMentionsReceivedInvocations: [(message: String, html: String?, eventID: String?, intentionalMentions: IntentionalMentions)] = []
|
||||
var sendMessageHtmlInReplyToIntentionalMentionsReceivedArguments: (message: String, html: String, eventID: String?, intentionalMentions: IntentionalMentions)?
|
||||
var sendMessageHtmlInReplyToIntentionalMentionsReceivedInvocations: [(message: String, html: String, eventID: String?, intentionalMentions: IntentionalMentions)] = []
|
||||
var sendMessageHtmlInReplyToIntentionalMentionsReturnValue: Result<Void, TimelineProxyError>!
|
||||
var sendMessageHtmlInReplyToIntentionalMentionsClosure: ((String, String?, String?, IntentionalMentions) async -> Result<Void, TimelineProxyError>)?
|
||||
var sendMessageHtmlInReplyToIntentionalMentionsClosure: ((String, String, String?, IntentionalMentions) async -> Result<Void, TimelineProxyError>)?
|
||||
|
||||
func sendMessage(_ message: String, html: String?, inReplyTo eventID: String?, intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
||||
func sendMessage(_ message: String, html: String, inReplyTo eventID: String?, intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
||||
sendMessageHtmlInReplyToIntentionalMentionsCallsCount += 1
|
||||
sendMessageHtmlInReplyToIntentionalMentionsReceivedArguments = (message: message, html: html, eventID: eventID, intentionalMentions: intentionalMentions)
|
||||
sendMessageHtmlInReplyToIntentionalMentionsReceivedInvocations.append((message: message, html: html, eventID: eventID, intentionalMentions: intentionalMentions))
|
||||
|
||||
@@ -93,8 +93,6 @@ class CallScreenViewModel: CallScreenViewModelType, CallScreenViewModelProtocol
|
||||
switch action {
|
||||
case .callEnded:
|
||||
actionsSubject.send(.dismiss)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
@@ -31,7 +31,7 @@ enum ComposerToolbarVoiceMessageAction {
|
||||
}
|
||||
|
||||
enum ComposerToolbarViewModelAction {
|
||||
case sendMessage(plain: String, html: String?, mode: RoomScreenComposerMode, intentionalMentions: IntentionalMentions)
|
||||
case sendMessage(plain: String, html: String, mode: RoomScreenComposerMode, intentionalMentions: IntentionalMentions)
|
||||
case attach(ComposerAttachmentType)
|
||||
|
||||
case handlePasteOrDrop(provider: NSItemProvider)
|
||||
|
||||
@@ -87,6 +87,10 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
appSettings.$richTextEditorEnabled
|
||||
.map { !$0 }
|
||||
.assign(to: &wysiwygViewModel.$plainTextMode)
|
||||
|
||||
completionSuggestionService.suggestionsPublisher
|
||||
.weakAssign(to: \.state.suggestions, on: self)
|
||||
.store(in: &cancellables)
|
||||
@@ -107,9 +111,8 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
||||
case .previewVoiceMessage:
|
||||
actionsSubject.send(.voiceMessage(.send))
|
||||
default:
|
||||
let sendHTML = ServiceLocator.shared.settings.richTextEditorEnabled
|
||||
actionsSubject.send(.sendMessage(plain: wysiwygViewModel.content.markdown,
|
||||
html: sendHTML ? wysiwygViewModel.content.html : nil,
|
||||
html: wysiwygViewModel.content.html,
|
||||
mode: state.composerMode,
|
||||
intentionalMentions: wysiwygViewModel
|
||||
.getMentionsState()
|
||||
@@ -154,15 +157,13 @@ final class ComposerToolbarViewModel: ComposerToolbarViewModelType, ComposerTool
|
||||
set(text: "")
|
||||
}
|
||||
}
|
||||
|
||||
func handleKeyCommand(_ keyCommand: WysiwygKeyCommand) -> Bool {
|
||||
switch keyCommand {
|
||||
case .enter:
|
||||
process(viewAction: .sendMessage)
|
||||
return true
|
||||
case .shiftEnter:
|
||||
return false
|
||||
}
|
||||
|
||||
var keyCommands: [WysiwygKeyCommand] {
|
||||
[
|
||||
.enter { [weak self] in
|
||||
self?.process(viewAction: .sendMessage)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
@@ -24,7 +24,7 @@ struct ComposerToolbar: View {
|
||||
// Needs to be observable or the placeholder and the dictation state are not managed correctly.
|
||||
@ObservedObject var wysiwygViewModel: WysiwygComposerViewModel
|
||||
|
||||
let keyCommandHandler: KeyCommandHandler
|
||||
let keyCommands: [WysiwygKeyCommand]
|
||||
|
||||
@FocusState private var composerFocused: Bool
|
||||
@State private var frame: CGRect = .zero
|
||||
@@ -201,7 +201,7 @@ struct ComposerToolbar: View {
|
||||
placeholderColor: .compound.textSecondary,
|
||||
viewModel: wysiwygViewModel,
|
||||
itemProviderHelper: ItemProviderHelper(),
|
||||
keyCommandHandler: keyCommandHandler) { provider in
|
||||
keyCommands: keyCommands) { provider in
|
||||
context.send(viewAction: .handlePasteOrDrop(provider: provider))
|
||||
}
|
||||
}
|
||||
@@ -306,7 +306,7 @@ struct ComposerToolbar_Previews: PreviewProvider, TestablePreview {
|
||||
// The mock functon can't be used in this context because it does not hold a reference to the view model, losing the combine subscriptions
|
||||
ComposerToolbar(context: composerViewModel.context,
|
||||
wysiwygViewModel: wysiwygViewModel,
|
||||
keyCommandHandler: { _ in false })
|
||||
keyCommands: [])
|
||||
}
|
||||
.previewDisplayName("With Suggestions")
|
||||
|
||||
@@ -336,7 +336,7 @@ extension ComposerToolbar {
|
||||
}
|
||||
return ComposerToolbar(context: composerViewModel.context,
|
||||
wysiwygViewModel: wysiwygViewModel,
|
||||
keyCommandHandler: { _ in false })
|
||||
keyCommands: [])
|
||||
}
|
||||
|
||||
static func textWithVoiceMessage(focused: Bool = true) -> ComposerToolbar {
|
||||
@@ -352,7 +352,7 @@ extension ComposerToolbar {
|
||||
}
|
||||
return ComposerToolbar(context: composerViewModel.context,
|
||||
wysiwygViewModel: wysiwygViewModel,
|
||||
keyCommandHandler: { _ in false })
|
||||
keyCommands: [])
|
||||
}
|
||||
|
||||
static func voiceMessageRecordingMock() -> ComposerToolbar {
|
||||
@@ -368,7 +368,7 @@ extension ComposerToolbar {
|
||||
}
|
||||
return ComposerToolbar(context: composerViewModel.context,
|
||||
wysiwygViewModel: wysiwygViewModel,
|
||||
keyCommandHandler: { _ in false })
|
||||
keyCommands: [])
|
||||
}
|
||||
|
||||
static func voiceMessagePreviewMock(uploading: Bool) -> ComposerToolbar {
|
||||
@@ -385,6 +385,6 @@ extension ComposerToolbar {
|
||||
}
|
||||
return ComposerToolbar(context: composerViewModel.context,
|
||||
wysiwygViewModel: wysiwygViewModel,
|
||||
keyCommandHandler: { _ in false })
|
||||
keyCommands: [])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ struct MessageComposer_Previews: PreviewProvider, TestablePreview {
|
||||
let composerView = WysiwygComposerView(placeholder: L10n.richTextEditorComposerPlaceholder,
|
||||
viewModel: viewModel,
|
||||
itemProviderHelper: nil,
|
||||
keyCommandHandler: nil,
|
||||
keyCommands: nil,
|
||||
pasteHandler: nil)
|
||||
|
||||
return MessageComposer(composerView: composerView,
|
||||
|
||||
@@ -138,7 +138,7 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
|
||||
func toPresentable() -> AnyView {
|
||||
let composerToolbar = ComposerToolbar(context: composerViewModel.context,
|
||||
wysiwygViewModel: wysiwygViewModel,
|
||||
keyCommandHandler: composerViewModel.handleKeyCommand)
|
||||
keyCommands: composerViewModel.keyCommands)
|
||||
|
||||
return AnyView(RoomScreen(context: viewModel.context, composerToolbar: composerToolbar))
|
||||
}
|
||||
|
||||
@@ -461,7 +461,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
state.showLoading = false
|
||||
}
|
||||
|
||||
private func sendCurrentMessage(_ message: String, html: String?, mode: RoomScreenComposerMode, intentionalMentions: IntentionalMentions) async {
|
||||
private func sendCurrentMessage(_ message: String, html: String, mode: RoomScreenComposerMode, intentionalMentions: IntentionalMentions) async {
|
||||
guard !message.isEmpty else {
|
||||
fatalError("This message should never be empty")
|
||||
}
|
||||
|
||||
+2
-2
@@ -65,14 +65,14 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
|
||||
func processItemDisappearance(_ itemID: TimelineItemIdentifier) async { }
|
||||
|
||||
func sendMessage(_ message: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
inReplyTo itemID: TimelineItemIdentifier?,
|
||||
intentionalMentions: IntentionalMentions) async { }
|
||||
|
||||
func toggleReaction(_ reaction: String, to itemID: TimelineItemIdentifier) async { }
|
||||
|
||||
func editMessage(_ newMessage: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
original itemID: TimelineItemIdentifier,
|
||||
intentionalMentions: IntentionalMentions) async { }
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
func processItemDisappearance(_ itemID: TimelineItemIdentifier) { }
|
||||
|
||||
func sendMessage(_ message: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
inReplyTo itemID: TimelineItemIdentifier?,
|
||||
intentionalMentions: IntentionalMentions) async {
|
||||
var inReplyTo: String?
|
||||
@@ -148,7 +148,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
}
|
||||
|
||||
func editMessage(_ newMessage: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
original itemID: TimelineItemIdentifier,
|
||||
intentionalMentions: IntentionalMentions) async {
|
||||
MXLog.info("Edit message in \(roomID)")
|
||||
|
||||
+3
-3
@@ -50,12 +50,12 @@ protocol RoomTimelineControllerProtocol {
|
||||
func sendReadReceipt(for itemID: TimelineItemIdentifier) async -> Result<Void, RoomTimelineControllerError>
|
||||
|
||||
func sendMessage(_ message: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
inReplyTo itemID: TimelineItemIdentifier?,
|
||||
intentionalMentions: IntentionalMentions) async
|
||||
|
||||
func editMessage(_ newMessage: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
original itemID: TimelineItemIdentifier,
|
||||
intentionalMentions: IntentionalMentions) async
|
||||
|
||||
@@ -74,7 +74,7 @@ protocol RoomTimelineControllerProtocol {
|
||||
|
||||
extension RoomTimelineControllerProtocol {
|
||||
func sendMessage(_ message: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
intentionalMentions: IntentionalMentions) async {
|
||||
await sendMessage(message,
|
||||
html: html,
|
||||
|
||||
@@ -93,7 +93,7 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
}
|
||||
|
||||
func editMessage(_ message: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
original eventID: String,
|
||||
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
@@ -320,7 +320,7 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
}
|
||||
|
||||
func sendMessage(_ message: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
inReplyTo eventID: String? = nil,
|
||||
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
@@ -454,7 +454,7 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
// MARK: - Private
|
||||
|
||||
private func buildMessageContentFor(_ message: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
intentionalMentions: Mentions) -> RoomMessageEventContentWithoutRelation {
|
||||
let emoteSlashCommand = "/me "
|
||||
let isEmote: Bool = message.starts(with: emoteSlashCommand)
|
||||
@@ -462,18 +462,10 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
let content: RoomMessageEventContentWithoutRelation
|
||||
if isEmote {
|
||||
let emoteMessage = String(message.dropFirst(emoteSlashCommand.count))
|
||||
|
||||
var emoteHtml: String?
|
||||
if let html {
|
||||
emoteHtml = String(html.dropFirst(emoteSlashCommand.count))
|
||||
}
|
||||
let emoteHtml = String(html.dropFirst(emoteSlashCommand.count))
|
||||
content = buildEmoteMessageContentFor(emoteMessage, html: emoteHtml)
|
||||
} else {
|
||||
if let html {
|
||||
content = messageEventContentFromHtml(body: message, htmlBody: html)
|
||||
} else {
|
||||
content = messageEventContentFromMarkdown(md: message)
|
||||
}
|
||||
content = messageEventContentFromHtml(body: message, htmlBody: html)
|
||||
}
|
||||
return content.withMentions(mentions: intentionalMentions)
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ protocol TimelineProxyProtocol {
|
||||
func cancelSend(transactionID: String) async
|
||||
|
||||
func editMessage(_ message: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
original eventID: String,
|
||||
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError>
|
||||
|
||||
@@ -103,7 +103,7 @@ protocol TimelineProxyProtocol {
|
||||
func sendMessageEventContent(_ messageContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError>
|
||||
|
||||
func sendMessage(_ message: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
inReplyTo eventID: String?,
|
||||
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError>
|
||||
|
||||
@@ -124,7 +124,7 @@ protocol TimelineProxyProtocol {
|
||||
|
||||
extension TimelineProxyProtocol {
|
||||
func sendMessage(_ message: String,
|
||||
html: String?,
|
||||
html: String,
|
||||
intentionalMentions: IntentionalMentions) async -> Result<Void, TimelineProxyError> {
|
||||
await sendMessage(message,
|
||||
html: html,
|
||||
|
||||
@@ -81,8 +81,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
|
||||
}
|
||||
|
||||
func testHandleKeyCommand() {
|
||||
XCTAssertTrue(viewModel.handleKeyCommand(.enter))
|
||||
XCTAssertFalse(viewModel.handleKeyCommand(.shiftEnter))
|
||||
XCTAssertTrue(viewModel.keyCommands.count == 1)
|
||||
}
|
||||
|
||||
func testComposerFocusAfterEnablingRTE() {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Fix for plain text mode, using the RTE markdown to html conversion properly.
|
||||
+1
-1
@@ -64,7 +64,7 @@ packages:
|
||||
branch: 0.0.1
|
||||
WysiwygComposer:
|
||||
url: https://github.com/matrix-org/matrix-wysiwyg-composer-swift
|
||||
exactVersion: 2.19.0
|
||||
exactVersion: 2.22.0
|
||||
# path: ../matrix-wysiwyg/platforms/ios/lib/WysiwygComposer
|
||||
|
||||
# External dependencies
|
||||
|
||||
Reference in New Issue
Block a user