From 8ad5489a5e386e80c29f64de0225c788ad8be554 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 11:22:40 +0100 Subject: [PATCH 1/8] Add new localisation for ended poll replies --- Riot/Assets/en.lproj/Vector.strings | 2 ++ Riot/Generated/Strings.swift | 4 ++++ .../MXKSendReplyEventStringLocalizer.swift | 20 +++++++++++-------- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 95531c6da6..e2d45c94ed 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2368,6 +2368,8 @@ Tap the + to start adding people."; "poll_timeline_ended_text" = "Ended the poll"; +"poll_timeline_reply_ended_poll" = "Ended poll"; + // MARK: - Location sharing "location_sharing_title" = "Location"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 105a5d70e8..e098748096 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -4883,6 +4883,10 @@ public class VectorL10n: NSObject { public static var pollTimelineOneVote: String { return VectorL10n.tr("Vector", "poll_timeline_one_vote") } + /// Ended poll + public static var pollTimelineReplyEndedPoll: String { + return VectorL10n.tr("Vector", "poll_timeline_reply_ended_poll") + } /// Final results based on %lu votes public static func pollTimelineTotalFinalResults(_ p1: Int) -> String { return VectorL10n.tr("Vector", "poll_timeline_total_final_results", p1) diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKSendReplyEventStringLocalizer.swift b/Riot/Modules/MatrixKit/Models/Room/MXKSendReplyEventStringLocalizer.swift index f22c779fd1..4c942bccdd 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKSendReplyEventStringLocalizer.swift +++ b/Riot/Modules/MatrixKit/Models/Room/MXKSendReplyEventStringLocalizer.swift @@ -18,34 +18,38 @@ import Foundation class MXKSendReplyEventStringLocalizer: NSObject, MXSendReplyEventStringLocalizerProtocol { func senderSentAnImage() -> String { - return VectorL10n.messageReplyToSenderSentAnImage + VectorL10n.messageReplyToSenderSentAnImage } func senderSentAVideo() -> String { - return VectorL10n.messageReplyToSenderSentAVideo + VectorL10n.messageReplyToSenderSentAVideo } func senderSentAnAudioFile() -> String { - return VectorL10n.messageReplyToSenderSentAnAudioFile + VectorL10n.messageReplyToSenderSentAnAudioFile } func senderSentAVoiceMessage() -> String { - return VectorL10n.messageReplyToSenderSentAVoiceMessage + VectorL10n.messageReplyToSenderSentAVoiceMessage } func senderSentAFile() -> String { - return VectorL10n.messageReplyToSenderSentAFile + VectorL10n.messageReplyToSenderSentAFile } func senderSentTheirLocation() -> String { - return VectorL10n.messageReplyToSenderSentTheirLocation + VectorL10n.messageReplyToSenderSentTheirLocation } func senderSentTheirLiveLocation() -> String { - return VectorL10n.messageReplyToSenderSentTheirLiveLocation + VectorL10n.messageReplyToSenderSentTheirLiveLocation } func messageToReplyToPrefix() -> String { - return VectorL10n.messageReplyToMessageToReplyToPrefix + VectorL10n.messageReplyToMessageToReplyToPrefix + } + + func replyToEndedPoll() -> String { + VectorL10n.pollTimelineReplyEndedPoll } } From a8d041da3bec620176826203f70e40375ee3032c Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 12:43:11 +0100 Subject: [PATCH 2/8] =?UTF-8?q?Add=20replacement=20logic=20for=20=E2=80=9C?= =?UTF-8?q?Ended=20poll=E2=80=9D=20text?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Utils/EventFormatter/MXKEventFormatter.m | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index cee8dccecc..4a7f6dc0ea 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -31,6 +31,7 @@ #import "GeneratedInterface-Swift.h" static NSString *const kHTMLATagRegexPattern = @"([^<]*)"; +static NSString *const kEndedPollPattern = @".*
.*
(.*)
"; @interface MXKEventFormatter () { @@ -1808,6 +1809,7 @@ - (NSAttributedString*)renderHTMLString:(NSString*)htmlString } html = [self renderReplyTo:html withRoomState:roomState]; + html = [self renderPollEndedReplyTo:html repliedEvent:repliedEvent]; } // Apply the css style that corresponds to the event state @@ -2014,6 +2016,39 @@ - (NSString*)renderReplyTo:(NSString*)htmlString withRoomState:(MXRoomState*)roo return html; } +- (NSString*)renderPollEndedReplyTo:(NSString*)htmlString repliedEvent:(MXEvent*)repliedEvent { + static NSRegularExpression *endedPollRegex; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + endedPollRegex = [NSRegularExpression regularExpressionWithPattern:kEndedPollPattern options:NSRegularExpressionCaseInsensitive error:nil]; + }); + + NSTextCheckingResult* match = [endedPollRegex firstMatchInString:htmlString options:0 range:NSMakeRange(0, htmlString.length)]; + NSString* finalString = htmlString; + + if (!(match && match.numberOfRanges > 1)) { + // no useful match found + return finalString; + } + + NSRange groupRange = [match rangeAtIndex:1]; + NSString* replacementText; + + if (repliedEvent) { + MXEvent* pollStartedEvent = [mxSession.store eventWithEventId:repliedEvent.relatesTo.eventId inRoom:repliedEvent.roomId]; + replacementText = [MXEventContentPollStart modelFromJSON:pollStartedEvent.content].question; + } + + if (replacementText == nil) { + replacementText = VectorL10n.pollTimelineReplyEndedPoll; + } + + finalString = [htmlString stringByReplacingCharactersInRange:groupRange withString:replacementText]; + + return finalString; +} + - (void)postFormatMutableAttributedString:(NSMutableAttributedString*)mutableAttributedString forEvent:(MXEvent*)event andRepliedEvent:(MXEvent*)repliedEvent From 69f3df08670d1220ec244e08e5ae1002cada82a2 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 15:05:35 +0100 Subject: [PATCH 3/8] Improve formatter --- .../MatrixKit/Utils/EventFormatter/MXKEventFormatter.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index 4a7f6dc0ea..1e7d53fe95 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -2024,9 +2024,14 @@ - (NSString*)renderPollEndedReplyTo:(NSString*)htmlString repliedEvent:(MXEvent* endedPollRegex = [NSRegularExpression regularExpressionWithPattern:kEndedPollPattern options:NSRegularExpressionCaseInsensitive error:nil]; }); - NSTextCheckingResult* match = [endedPollRegex firstMatchInString:htmlString options:0 range:NSMakeRange(0, htmlString.length)]; NSString* finalString = htmlString; + if (repliedEvent.eventType != MXEventTypePollEnd) { + return finalString; + } + + NSTextCheckingResult* match = [endedPollRegex firstMatchInString:htmlString options:0 range:NSMakeRange(0, htmlString.length)]; + if (!(match && match.numberOfRanges > 1)) { // no useful match found return finalString; From 80ce6b7f517f67fa2007f301071ee5ea05bc3bf2 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 16:10:15 +0100 Subject: [PATCH 4/8] =?UTF-8?q?Handle=20edge=20cases=20for=20plain=20?= =?UTF-8?q?=E2=80=9Cbody=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MatrixKit/Utils/EventFormatter/MXKEventFormatter.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index 1e7d53fe95..c8dce874af 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -1882,6 +1882,12 @@ - (NSString*)buildHTMLStringForEvent:(MXEvent*)event inReplyToEvent:(MXEvent*)re { MXJSONModelSetString(repliedEventContent, repliedEvent.content[kMXMessageBodyKey]); } + if (!repliedEventContent && repliedEvent.eventType == MXEventTypePollStart) { + repliedEventContent = [MXEventContentPollStart modelFromJSON:repliedEvent.content].question; + } + if (!repliedEventContent && repliedEvent.eventType == MXEventTypePollEnd) { + repliedEventContent = MXSendReplyEventDefaultStringLocalizer.new.replyToEndedPoll; + } } // No message content in a non-redacted event. Formatter should use fallback. From 2a2df206b59f6d39788824e5925d166521df6f3b Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 17:22:38 +0100 Subject: [PATCH 5/8] Improve code --- .../MatrixKit/Utils/EventFormatter/MXKEventFormatter.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m index c8dce874af..422e089902 100644 --- a/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m +++ b/Riot/Modules/MatrixKit/Utils/EventFormatter/MXKEventFormatter.m @@ -31,7 +31,7 @@ #import "GeneratedInterface-Swift.h" static NSString *const kHTMLATagRegexPattern = @"([^<]*)"; -static NSString *const kEndedPollPattern = @".*
.*
(.*)
"; +static NSString *const kRepliedTextPattern = @".*
.*
(.*)
"; @interface MXKEventFormatter () { @@ -2027,7 +2027,7 @@ - (NSString*)renderPollEndedReplyTo:(NSString*)htmlString repliedEvent:(MXEvent* static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - endedPollRegex = [NSRegularExpression regularExpressionWithPattern:kEndedPollPattern options:NSRegularExpressionCaseInsensitive error:nil]; + endedPollRegex = [NSRegularExpression regularExpressionWithPattern:kRepliedTextPattern options:NSRegularExpressionCaseInsensitive error:nil]; }); NSString* finalString = htmlString; From 956994269170229d1bac6650209ed073b1d2a09e Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 17:23:12 +0100 Subject: [PATCH 6/8] Add UTs --- ...wift => MXKEventFormatterSwiftTests.swift} | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) rename RiotTests/MatrixKitTests/{MXKEventFormatterTests.swift => MXKEventFormatterSwiftTests.swift} (72%) diff --git a/RiotTests/MatrixKitTests/MXKEventFormatterTests.swift b/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift similarity index 72% rename from RiotTests/MatrixKitTests/MXKEventFormatterTests.swift rename to RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift index 31db309545..03731dd50e 100644 --- a/RiotTests/MatrixKitTests/MXKEventFormatterTests.swift +++ b/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift @@ -29,9 +29,10 @@ private enum Constants { static let expectedEditedHTML = "
In reply to alice
Edited message
Reply" static let expectedEditedHTMLWithNewContent = "
In reply to alice
New content
Reply" static let expectedEditedHTMLWithParsedItalic = "
In reply to alice
New content
Reply" + static let expectedReplyToPollEndedEvent = "
In reply to alice
Ended poll
Reply" } -class MXKEventFormatterTests: XCTestCase { +class MXKEventFormatterSwiftTests: XCTestCase { func testBuildHTMLString() { let formatter = MXKEventFormatter() let repliedEvent = MXEvent() @@ -73,4 +74,39 @@ class MXKEventFormatterTests: XCTestCase { repliedEvent.wireContent[kMXMessageContentKeyNewContent] = nil XCTAssertNil(buildHTML()) } + + func testBuildHTMLStringWithPollEndedReply() { + let formatter = MXKEventFormatter() + let repliedEvent: MXEvent = .mockEvent(eventType: kMXEventTypeStringPollEnd, body: nil) + + let event = MXEvent() + event.sender = "bob" + event.wireType = kMXEventTypeStringRoomMessage + event.wireContent = [ + kMXMessageTypeKey: kMXMessageTypeText, + kMXMessageBodyKey: Constants.replyBody, + kMXEventRelationRelatesToKey: [kMXEventContentRelatesToKeyInReplyTo: ["event_id": Constants.repliedEventId]] + ] + + let formattedText = formatter.buildHTMLString(for: event, inReplyTo: repliedEvent) + + XCTAssertEqual(formattedText, Constants.expectedReplyToPollEndedEvent) + } +} + +private extension MXEvent { + static func mockEvent(eventType: String, body: String? = Constants.repliedEventBody) -> MXEvent { + let repliedEvent = MXEvent() + repliedEvent.sender = "alice" + repliedEvent.roomId = Constants.roomId + repliedEvent.eventId = Constants.repliedEventId + repliedEvent.wireType = eventType + repliedEvent.wireContent = [kMXMessageTypeKey: kMXMessageTypeText] + + if let body = body { + repliedEvent.wireContent[kMXMessageBodyKey] = body + } + + return repliedEvent + } } From 91c61eb8f535f0ae23f022ec4720f008b072f4cb Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 17:25:14 +0100 Subject: [PATCH 7/8] Cleanup --- .../MatrixKitTests/MXKEventFormatterSwiftTests.swift | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift b/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift index 03731dd50e..457f108530 100644 --- a/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift +++ b/RiotTests/MatrixKitTests/MXKEventFormatterSwiftTests.swift @@ -35,17 +35,10 @@ private enum Constants { class MXKEventFormatterSwiftTests: XCTestCase { func testBuildHTMLString() { let formatter = MXKEventFormatter() - let repliedEvent = MXEvent() + let repliedEvent: MXEvent = .mockEvent(eventType: kMXEventTypeStringRoomMessage) let event = MXEvent() func buildHTML() -> String? { return formatter.buildHTMLString(for: event, inReplyTo: repliedEvent) } - // Initial setup. - repliedEvent.sender = "alice" - repliedEvent.roomId = Constants.roomId - repliedEvent.eventId = Constants.repliedEventId - repliedEvent.wireType = kMXEventTypeStringRoomMessage - repliedEvent.wireContent = [kMXMessageTypeKey: kMXMessageTypeText, - kMXMessageBodyKey: Constants.repliedEventBody] event.sender = "bob" event.wireType = kMXEventTypeStringRoomMessage event.wireContent = [ From 0df3c31d6bde15e32ed30dff5cd35750a8c06481 Mon Sep 17 00:00:00 2001 From: Alfonso Grillo Date: Wed, 18 Jan 2023 17:27:30 +0100 Subject: [PATCH 8/8] Add changelog.d file --- changelog.d/pr-7284.change | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/pr-7284.change diff --git a/changelog.d/pr-7284.change b/changelog.d/pr-7284.change new file mode 100644 index 0000000000..edab718561 --- /dev/null +++ b/changelog.d/pr-7284.change @@ -0,0 +1 @@ +Polls: render replies to poll events better.