From c6761c8b43f75dde16759b78102741ead9aa4e41 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 2 Apr 2024 15:06:28 +0200 Subject: [PATCH 01/79] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index 4cf4cbfbe..5df7a12db 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.9 -CURRENT_PROJECT_VERSION = 1.11.9 +MARKETING_VERSION = 1.11.10 +CURRENT_PROJECT_VERSION = 1.11.10 From 047be106928a7ae442d7aebe1f586acbf766d268 Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 4 Apr 2024 13:01:19 +0200 Subject: [PATCH 02/79] Analytics | Report expected UTDs as HistoricalMessage error --- .../DecryptionFailure+Analytics.swift | 21 +- .../Modules/Analytics/DecryptionFailure.swift | 5 + .../Analytics/DecryptionFailureTracker.swift | 18 +- Riot/Utils/EventFormatter.m | 2 +- RiotTests/DecryptionFailureTrackerTests.swift | 210 ++++++++++++++- RiotTests/FakeUtils.swift | 242 +++++++++++++++++- 6 files changed, 477 insertions(+), 21 deletions(-) diff --git a/Riot/Modules/Analytics/DecryptionFailure+Analytics.swift b/Riot/Modules/Analytics/DecryptionFailure+Analytics.swift index cd129aee3..5ed3c36c2 100644 --- a/Riot/Modules/Analytics/DecryptionFailure+Analytics.swift +++ b/Riot/Modules/Analytics/DecryptionFailure+Analytics.swift @@ -21,23 +21,34 @@ extension DecryptionFailure { public func toAnalyticsEvent() -> AnalyticsEvent.Error { - let timeToDecryptMillis: Int = if self.timeToDecrypt != nil { - Int(self.timeToDecrypt! * 1000) + let timeToDecryptMillis: Int = if let ttd = self.timeToDecrypt { + Int(ttd * 1000) } else { -1 } + + let isHistoricalEvent = if let localAge = self.eventLocalAgeMillis { + localAge < 0 + } else { false } + + let errorName = if isHistoricalEvent && self.trustOwnIdentityAtTimeOfFailure == false { + AnalyticsEvent.Error.Name.HistoricalMessage + } else { + self.reason.errorName + } + return AnalyticsEvent.Error( context: self.context, cryptoModule: .Rust, cryptoSDK: .Rust, domain: .E2EE, - eventLocalAgeMillis: nil, + eventLocalAgeMillis: self.eventLocalAgeMillis, isFederated: nil, isMatrixDotOrg: nil, - name: self.reason.errorName, + name: errorName, timeToDecryptMillis: timeToDecryptMillis, - userTrustsOwnIdentity: nil, + userTrustsOwnIdentity: self.trustOwnIdentityAtTimeOfFailure, wasVisibleToUser: nil ) } diff --git a/Riot/Modules/Analytics/DecryptionFailure.swift b/Riot/Modules/Analytics/DecryptionFailure.swift index 9e0ca5785..6d3f6c1a8 100644 --- a/Riot/Modules/Analytics/DecryptionFailure.swift +++ b/Riot/Modules/Analytics/DecryptionFailure.swift @@ -47,6 +47,11 @@ import AnalyticsEvents /// UTDs can be permanent or temporary. If temporary, this field will contain the time it took to decrypt the message in milliseconds. If permanent should be nil var timeToDecrypt: TimeInterval? + /// Was the current cross-signing identity trusted at the time of decryption + var trustOwnIdentityAtTimeOfFailure: Bool? + + var eventLocalAgeMillis: Int? + init(failedEventId: String, reason: DecryptionFailureReason, context: String, ts: TimeInterval) { self.failedEventId = failedEventId self.reason = reason diff --git a/Riot/Modules/Analytics/DecryptionFailureTracker.swift b/Riot/Modules/Analytics/DecryptionFailureTracker.swift index 19b8afb19..503c733ba 100644 --- a/Riot/Modules/Analytics/DecryptionFailureTracker.swift +++ b/Riot/Modules/Analytics/DecryptionFailureTracker.swift @@ -62,14 +62,14 @@ class DecryptionFailureTracker: NSObject { selector: #selector(eventDidDecrypt(_:)), name: .mxEventDidDecrypt, object: nil) - } @objc - func reportUnableToDecryptError(forEvent event: MXEvent, withRoomState roomState: MXRoomState, myUser userId: String) { + func reportUnableToDecryptError(forEvent event: MXEvent, withRoomState roomState: MXRoomState, mySession: MXSession) { if reportedFailures[event.eventId] != nil || trackedEvents.contains(event.eventId) { return } + guard let userId = mySession.myUserId else { return } // Filter out "expected" UTDs // We cannot decrypt messages sent before the user joined the room @@ -82,6 +82,12 @@ class DecryptionFailureTracker: NSObject { guard let error = event.decryptionError as? NSError else { return } + let eventOrigin = event.originServerTs + let deviceTimestamp = mySession.crypto.deviceCreationTs + // If negative it's an historical event relative to the current session + let eventRelativeAgeMillis = Int(eventOrigin) - Int(deviceTimestamp) + let isSessionVerified = mySession.crypto.crossSigning.canTrustCrossSigning + var reason = DecryptionFailureReason.unspecified if error.code == MXDecryptingErrorUnknownInboundSessionIdCode.rawValue { @@ -92,7 +98,13 @@ class DecryptionFailureTracker: NSObject { let context = String(format: "code: %ld, description: %@", error.code, event.decryptionError.localizedDescription) - reportedFailures[failedEventId] = DecryptionFailure(failedEventId: failedEventId, reason: reason, context: context, ts: self.timeProvider.nowTs()) + let failure = DecryptionFailure(failedEventId: failedEventId, reason: reason, context: context, ts: self.timeProvider.nowTs()) + + failure.eventLocalAgeMillis = Int(exactly: eventRelativeAgeMillis) + failure.trustOwnIdentityAtTimeOfFailure = isSessionVerified + + reportedFailures[failedEventId] = failure + // Start the ticker if needed. There is no need to have a ticker if no failures are tracked if checkFailuresTimer == nil { diff --git a/Riot/Utils/EventFormatter.m b/Riot/Utils/EventFormatter.m index 4494bdbb2..d53a3e19a 100644 --- a/Riot/Utils/EventFormatter.m +++ b/Riot/Utils/EventFormatter.m @@ -334,7 +334,7 @@ static NSString *const kEventFormatterTimeFormat = @"HH:mm"; { // Track e2e failures dispatch_async(dispatch_get_main_queue(), ^{ - [[DecryptionFailureTracker sharedInstance] reportUnableToDecryptErrorForEvent:event withRoomState:roomState myUser:self->mxSession.myUser.userId]; + [[DecryptionFailureTracker sharedInstance] reportUnableToDecryptErrorForEvent:event withRoomState:roomState mySession:self->mxSession]; }); if (event.decryptionError.code == MXDecryptingErrorUnknownInboundSessionIdCode) diff --git a/RiotTests/DecryptionFailureTrackerTests.swift b/RiotTests/DecryptionFailureTrackerTests.swift index 7cd9bf480..c142514cb 100644 --- a/RiotTests/DecryptionFailureTrackerTests.swift +++ b/RiotTests/DecryptionFailureTrackerTests.swift @@ -41,10 +41,23 @@ class DecryptionFailureTrackerTests: XCTestCase { } let timeShifter = TimeShifter() + var fakeCrypto: FakeCrypto! + var fakeSession: FakeSession! + var fakeCrossSigning: FakeCrossSigning! + + override func setUp() { + super.setUp() + self.fakeCrypto = FakeCrypto() + self.fakeCrossSigning = FakeCrossSigning() + self.fakeCrypto.crossSigning = self.fakeCrossSigning + self.fakeSession = FakeSession(mockCrypto: self.fakeCrypto) + } + func test_grace_period() { let myUser = "test@example.com"; + fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); decryptionFailureTracker.timeProvider = timeShifter; @@ -61,7 +74,7 @@ class DecryptionFailureTrackerTests: XCTestCase { let fakeRoomState = FakeRoomState(); fakeRoomState.mockMembers = FakeRoomMembers(joined: [myUser]) - decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, myUser: myUser); + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); timeShifter.timestamp = TimeInterval(2) @@ -83,6 +96,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_report_ratcheted_key_utd() { let myUser = "test@example.com"; + fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); decryptionFailureTracker.timeProvider = timeShifter; @@ -99,7 +113,7 @@ class DecryptionFailureTrackerTests: XCTestCase { let fakeRoomState = FakeRoomState(); fakeRoomState.mockMembers = FakeRoomMembers(joined: [myUser]) - decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, myUser: myUser); + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); // Pass the max period timeShifter.timestamp = TimeInterval(70) @@ -112,6 +126,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_report_unspecified_error() { let myUser = "test@example.com"; + fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); decryptionFailureTracker.timeProvider = timeShifter; @@ -128,7 +143,7 @@ class DecryptionFailureTrackerTests: XCTestCase { let fakeRoomState = FakeRoomState(); fakeRoomState.mockMembers = FakeRoomMembers(joined: [myUser]) - decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, myUser: myUser); + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); // Pass the max period timeShifter.timestamp = TimeInterval(70) @@ -143,6 +158,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_do_not_double_report() { let myUser = "test@example.com"; + fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); decryptionFailureTracker.timeProvider = timeShifter; @@ -160,7 +176,7 @@ class DecryptionFailureTrackerTests: XCTestCase { let fakeRoomState = FakeRoomState(); fakeRoomState.mockMembers = FakeRoomMembers(joined: [myUser]) - decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, myUser: myUser); + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); // Pass the max period timeShifter.timestamp = TimeInterval(70) @@ -171,7 +187,7 @@ class DecryptionFailureTrackerTests: XCTestCase { // Try to report again the same event testDelegate.reportedFailure = nil - decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, myUser: myUser); + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); // Pass the grace period timeShifter.timestamp = TimeInterval(10) @@ -184,6 +200,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_ignore_not_member() { let myUser = "test@example.com"; + fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); decryptionFailureTracker.timeProvider = timeShifter; @@ -203,7 +220,7 @@ class DecryptionFailureTrackerTests: XCTestCase { fakeMembers.mockMembers[myUser] = MXMembership.ban fakeRoomState.mockMembers = fakeMembers - decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, myUser: myUser); + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); // Pass the grace period timeShifter.timestamp = TimeInterval(5) @@ -218,6 +235,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_notification_center() { let myUser = "test@example.com"; + fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); decryptionFailureTracker.timeProvider = timeShifter; @@ -235,7 +253,7 @@ class DecryptionFailureTrackerTests: XCTestCase { let fakeRoomState = FakeRoomState(); fakeRoomState.mockMembers = FakeRoomMembers(joined: [myUser]) - decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, myUser: myUser); + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); // Shift time below GRACE_PERIOD timeShifter.timestamp = TimeInterval(2) @@ -258,6 +276,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_should_report_late_decrypt() { let myUser = "test@example.com"; + fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); decryptionFailureTracker.timeProvider = timeShifter; @@ -275,7 +294,7 @@ class DecryptionFailureTrackerTests: XCTestCase { let fakeRoomState = FakeRoomState(); fakeRoomState.mockMembers = FakeRoomMembers(joined: [myUser]) - decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, myUser: myUser); + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); // Simulate succesful decryption after grace period but before max wait timeShifter.timestamp = TimeInterval(20) @@ -302,6 +321,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_should_report_permanent_decryption_error() { let myUser = "test@example.com"; + fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); decryptionFailureTracker.timeProvider = timeShifter; @@ -319,7 +339,7 @@ class DecryptionFailureTrackerTests: XCTestCase { let fakeRoomState = FakeRoomState(); fakeRoomState.mockMembers = FakeRoomMembers(joined: [myUser]) - decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, myUser: myUser); + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); // Simulate succesful decryption after max wait timeShifter.timestamp = TimeInterval(70) @@ -337,5 +357,177 @@ class DecryptionFailureTrackerTests: XCTestCase { XCTAssertEqual(analyticsError.timeToDecryptMillis, -1) } + + + func test_should_report_trust_status_at_decryption_time() { + + let myUser = "test@example.com"; + fakeSession.mockUserId = myUser; + + let decryptionFailureTracker = DecryptionFailureTracker(); + decryptionFailureTracker.timeProvider = timeShifter; + + let testDelegate = AnalyticsDelegate(); + + decryptionFailureTracker.delegate = testDelegate; + + timeShifter.timestamp = TimeInterval(0) + + let fakeEvent = FakeEvent(id: "$0000"); + fakeEvent.decryptionError = NSError(domain: MXDecryptingErrorDomain, code: Int(MXDecryptingErrorUnknownInboundSessionIdCode.rawValue)) + + // set session as not yet verified + fakeCrossSigning.canTrustCrossSigning = false + + let fakeRoomState = FakeRoomState(); + fakeRoomState.mockMembers = FakeRoomMembers(joined: [myUser]) + + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); + + // set verified now + fakeCrossSigning.canTrustCrossSigning = true + + // Simulate succesful decryption after max wait + timeShifter.timestamp = TimeInterval(70) + + decryptionFailureTracker.checkFailures(); + + // Event should have been reported as a late decrypt + XCTAssertEqual(testDelegate.reportedFailure?.trustOwnIdentityAtTimeOfFailure, false); + + // Assert that it's converted to -1 for reporting + let analyticsError = testDelegate.reportedFailure!.toAnalyticsEvent() + + XCTAssertEqual(analyticsError.userTrustsOwnIdentity, false) + + // Report a new error now that session is verified + + let fakeEvent2 = FakeEvent(id: "$0001"); + fakeEvent2.decryptionError = NSError(domain: MXDecryptingErrorDomain, code: Int(MXDecryptingErrorUnknownInboundSessionIdCode.rawValue)) + + + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent2, withRoomState: fakeRoomState, mySession: fakeSession); + + // Simulate permanent UTD + timeShifter.timestamp = TimeInterval(140) + + decryptionFailureTracker.checkFailures(); + + XCTAssertEqual(testDelegate.reportedFailure?.failedEventId, "$0001"); + XCTAssertEqual(testDelegate.reportedFailure?.trustOwnIdentityAtTimeOfFailure, true); + + let analyticsError2 = testDelegate.reportedFailure!.toAnalyticsEvent() + + XCTAssertEqual(analyticsError2.userTrustsOwnIdentity, true) + + } + + + func test_should_report_event_age() { + + let myUser = "test@example.com"; + fakeSession.mockUserId = myUser; + + let format = DateFormatter() + format.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" + + let sessionCreationTimeMillis = format.date(from: "2024-03-09T10:00:00Z")!.timeIntervalSince1970 * 1000 + + let now = format.date(from: "2024-03-09T10:02:00Z")!.timeIntervalSince1970 + + // 5mn after session was created + let postCreationMessageTs = UInt64(format.date(from: "2024-03-09T10:05:00Z")!.timeIntervalSince1970 * 1000) + + let decryptionFailureTracker = DecryptionFailureTracker(); + decryptionFailureTracker.timeProvider = timeShifter; + + let testDelegate = AnalyticsDelegate(); + + decryptionFailureTracker.delegate = testDelegate; + + timeShifter.timestamp = now + + let fakeEvent = FakeEvent(id: "$0000"); + fakeEvent.mockOrigineServerTs = postCreationMessageTs; + fakeEvent.decryptionError = NSError(domain: MXDecryptingErrorDomain, code: Int(MXDecryptingErrorUnknownInboundSessionIdCode.rawValue)) + + fakeCrypto.deviceCreationTs = UInt64(sessionCreationTimeMillis) + + let fakeRoomState = FakeRoomState(); + fakeRoomState.mockMembers = FakeRoomMembers(joined: [myUser]) + + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); + + // set verified now + fakeCrossSigning.canTrustCrossSigning = true + + // Simulate permanent UTD + timeShifter.timestamp = now + TimeInterval(70) + + decryptionFailureTracker.checkFailures(); + + XCTAssertEqual(testDelegate.reportedFailure?.eventLocalAgeMillis, 5 * 60 * 1000); + + let analyticsError = testDelegate.reportedFailure!.toAnalyticsEvent() + + XCTAssertEqual(analyticsError.eventLocalAgeMillis, 5 * 60 * 1000) + + } + + + func test_should_report_expected_utds() { + + let myUser = "test@example.com"; + fakeSession.mockUserId = myUser; + + let format = DateFormatter() + format.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" + + let sessionCreationTimeMillis = format.date(from: "2024-03-09T10:00:00Z")!.timeIntervalSince1970 * 1000 + + let now = format.date(from: "2024-03-09T10:02:00Z")!.timeIntervalSince1970 + + // 1 day before session was created + let historicalMessageTs = UInt64(format.date(from: "2024-03-08T10:00:00Z")!.timeIntervalSince1970 * 1000) + + let decryptionFailureTracker = DecryptionFailureTracker(); + decryptionFailureTracker.timeProvider = timeShifter; + + let testDelegate = AnalyticsDelegate(); + + decryptionFailureTracker.delegate = testDelegate; + + timeShifter.timestamp = now + + let fakeEvent = FakeEvent(id: "$0000"); + fakeEvent.mockOrigineServerTs = historicalMessageTs; + fakeEvent.decryptionError = NSError(domain: MXDecryptingErrorDomain, code: Int(MXDecryptingErrorUnknownInboundSessionIdCode.rawValue)) + + fakeCrypto.deviceCreationTs = UInt64(sessionCreationTimeMillis) + + let fakeRoomState = FakeRoomState(); + fakeRoomState.mockMembers = FakeRoomMembers(joined: [myUser]) + + fakeCrossSigning.canTrustCrossSigning = false + + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); + + // set verified now + fakeCrossSigning.canTrustCrossSigning = true + + // Simulate permanent UTD + timeShifter.timestamp = now + TimeInterval(70) + + decryptionFailureTracker.checkFailures(); + + // Event should have been reported as a late decrypt + XCTAssertEqual(testDelegate.reportedFailure?.eventLocalAgeMillis, -24 * 60 * 60 * 1000); + + let analyticsError = testDelegate.reportedFailure!.toAnalyticsEvent() + + XCTAssertEqual(analyticsError.name, .HistoricalMessage) + + } + } diff --git a/RiotTests/FakeUtils.swift b/RiotTests/FakeUtils.swift index 7bd350e4b..f6b1fe477 100644 --- a/RiotTests/FakeUtils.swift +++ b/RiotTests/FakeUtils.swift @@ -1,4 +1,4 @@ -// +// // Copyright 2024 New Vector Ltd // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,6 +22,7 @@ class FakeEvent: MXEvent { var mockEventId: String; var mockSender: String!; var mockDecryptionError: Error? + var mockOrigineServerTs: UInt64 = 0 init(id: String) { mockEventId = id @@ -31,7 +32,7 @@ class FakeEvent: MXEvent { required init?(coder: NSCoder) { fatalError() } - + override var sender: String! { get { return mockSender } set { mockSender = newValue } @@ -47,6 +48,12 @@ class FakeEvent: MXEvent { set { mockDecryptionError = newValue } } + override var originServerTs: UInt64 { + get { return mockOrigineServerTs } + set { mockOrigineServerTs = newValue } + + } + } @@ -80,7 +87,7 @@ class FakeRoomMember: MXRoomMember { get { return mockUserId } set { mockUserId = newValue } } - + } @@ -107,3 +114,232 @@ class FakeRoomMembers: MXRoomMembers { } } + +class FakeSession: MXSession { + + var mockCrypto: MXCrypto? = FakeCrypto() + + var mockUserId: String = "@alice:localhost" + + init(mockCrypto: MXCrypto? = nil) { + self.mockCrypto = mockCrypto + super.init() + } + + override var crypto: MXCrypto? { + get { + return mockCrypto + } + set { + // nothing + } + } + + override var myUserId: String! { + get { + return mockUserId + } + set { + mockUserId = newValue + } + } +} + +class FakeCrypto: NSObject, MXCrypto { + + + var version: String = "" + + var deviceCurve25519Key: String? + + var deviceEd25519Key: String? + + var deviceCreationTs: UInt64 = 0 + + var backup: MXKeyBackup? + + var keyVerificationManager: MXKeyVerificationManager = FakeKeyVerificationManager() + + var crossSigning: MXCrossSigning = FakeCrossSigning() + + var recoveryService: MXRecoveryService! = nil + + var dehydrationService: MatrixSDK.DehydrationService! = nil + + override init() { + super.init() + } + + func start(_ onComplete: (() -> Void)?, failure: ((Swift.Error) -> Void)? = nil) { + + } + + func close(_ deleteStore: Bool) { + + } + + func isRoomEncrypted(_ roomId: String) -> Bool { + return true + } + + func encryptEventContent(_ eventContent: [AnyHashable : Any], withType eventType: String, in room: MXRoom, success: (([AnyHashable : Any], String) -> Void)?, failure: ((Swift.Error) -> Void)? = nil) -> MXHTTPOperation? { + return nil + } + + func decryptEvents(_ events: [MXEvent], inTimeline timeline: String?, onComplete: (([MXEventDecryptionResult]) -> Void)? = nil) { + + } + + func ensureEncryption(inRoom roomId: String, success: (() -> Void)?, failure: ((Swift.Error) -> Void)? = nil) -> MXHTTPOperation? { + return nil + } + + func eventDeviceInfo(_ event: MXEvent) -> MXDeviceInfo? { + return nil + } + + func discardOutboundGroupSessionForRoom(withRoomId roomId: String, onComplete: (() -> Void)? = nil) { + + } + + func handle(_ syncResponse: MXSyncResponse, onComplete: @escaping () -> Void) { + + } + + func setDeviceVerification(_ verificationStatus: MXDeviceVerification, forDevice deviceId: String, ofUser userId: String, success: (() -> Void)?, failure: ((Swift.Error) -> Void)? = nil) { + + } + + func setUserVerification(_ verificationStatus: Bool, forUser userId: String, success: (() -> Void)?, failure: ((Swift.Error) -> Void)? = nil) { + + } + + func trustLevel(forUser userId: String) -> MXUserTrustLevel { + return MXUserTrustLevel.init(crossSigningVerified: true, locallyVerified: true) + } + + func deviceTrustLevel(forDevice deviceId: String, ofUser userId: String) -> MXDeviceTrustLevel? { + return nil + } + + func trustLevelSummary(forUserIds userIds: [String], forceDownload: Bool, success: ((MXUsersTrustLevelSummary?) -> Void)?, failure: ((Swift.Error) -> Void)? = nil) { + + } + + func downloadKeys(_ userIds: [String], forceDownload: Bool, success: ((MXUsersDevicesMap?, [String : MXCrossSigningInfo]?) -> Void)?, failure: ((Swift.Error) -> Void)? = nil) -> MXHTTPOperation? { + return nil + } + + func devices(forUser userId: String) -> [String : MXDeviceInfo] { + return [:]; + } + + func device(withDeviceId deviceId: String, ofUser userId: String) -> MXDeviceInfo? { + return nil + } + + func exportRoomKeys(withPassword password: String, success: ((Data) -> Void)?, failure: ((Swift.Error) -> Void)? = nil) { + + } + + func importRoomKeys(_ keyFile: Data, withPassword password: String, success: ((UInt, UInt) -> Void)?, failure: ((Swift.Error) -> Void)? = nil) { + + } + + func reRequestRoomKey(for event: MXEvent) { + + } + + var globalBlacklistUnverifiedDevices: Bool = false + + func isBlacklistUnverifiedDevices(inRoom roomId: String) -> Bool { + return false + } + + func setBlacklistUnverifiedDevicesInRoom(_ roomId: String, blacklist: Bool) { + + } + +} + + +class FakeCrossSigning: NSObject, MXCrossSigning { + + + override init() { + super.init() + } + + var state: MXCrossSigningState = MXCrossSigningState.trustCrossSigning + + var myUserCrossSigningKeys: MXCrossSigningInfo? = nil + + var canTrustCrossSigning: Bool = true + + var canCrossSign: Bool = true + + var hasAllPrivateKeys: Bool = true + + func refreshState(success: ((Bool) -> Void)?, failure: ((Swift.Error) -> Void)? = nil) { + + } + + func setup(withPassword password: String, success: @escaping () -> Void, failure: @escaping (Swift.Error) -> Void) { + + } + + func setup(withAuthParams authParams: [AnyHashable : Any], success: @escaping () -> Void, failure: @escaping (Swift.Error) -> Void) { + + } + + func crossSignDevice(withDeviceId deviceId: String, userId: String, success: @escaping () -> Void, failure: @escaping (Swift.Error) -> Void) { + + } + + func signUser(withUserId userId: String, success: @escaping () -> Void, failure: @escaping (Swift.Error) -> Void) { + + } + + func crossSigningKeys(forUser userId: String) -> MXCrossSigningInfo? { + return nil + } + +} + +class FakeKeyVerificationManager: NSObject, MXKeyVerificationManager { + + override init() { + super.init() + } + + func requestVerificationByToDevice(withUserId userId: String, deviceIds: [String]?, methods: [String], success: @escaping (MXKeyVerificationRequest) -> Void, failure: @escaping (Swift.Error) -> Void) { + + } + + func requestVerificationByDM(withUserId userId: String, roomId: String?, fallbackText: String, methods: [String], success: @escaping (MXKeyVerificationRequest) -> Void, failure: @escaping (Swift.Error) -> Void) { + + } + + var pendingRequests: [MXKeyVerificationRequest] = [] + + func beginKeyVerification(from request: MXKeyVerificationRequest, method: String, success: @escaping (MXKeyVerificationTransaction) -> Void, failure: @escaping (Swift.Error) -> Void) { + + } + + func transactions(_ complete: @escaping ([MXKeyVerificationTransaction]) -> Void) { + + } + + func keyVerification(fromKeyVerificationEvent event: MXEvent, roomId: String, success: @escaping (MXKeyVerification) -> Void, failure: @escaping (Swift.Error) -> Void) -> MXHTTPOperation? { + return nil + } + + func qrCodeTransaction(withTransactionId transactionId: String) -> MXQRCodeTransaction? { + return nil + } + + func removeQRCodeTransaction(withTransactionId transactionId: String) { + + } + +} From e216c1bbf592c2b61291ccf6c198646864ded26a Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 5 Apr 2024 09:53:07 +0200 Subject: [PATCH 03/79] Telemetry | Add more properties to posthog utd errors --- .../DecryptionFailure+Analytics.swift | 7 +- .../Modules/Analytics/DecryptionFailure.swift | 8 ++ .../Analytics/DecryptionFailureTracker.swift | 11 +++ RiotTests/DecryptionFailureTrackerTests.swift | 91 ++++++++++++++++--- 4 files changed, 102 insertions(+), 15 deletions(-) diff --git a/Riot/Modules/Analytics/DecryptionFailure+Analytics.swift b/Riot/Modules/Analytics/DecryptionFailure+Analytics.swift index 5ed3c36c2..119366a66 100644 --- a/Riot/Modules/Analytics/DecryptionFailure+Analytics.swift +++ b/Riot/Modules/Analytics/DecryptionFailure+Analytics.swift @@ -42,14 +42,13 @@ extension DecryptionFailure { cryptoModule: .Rust, cryptoSDK: .Rust, domain: .E2EE, - eventLocalAgeMillis: self.eventLocalAgeMillis, - isFederated: nil, - isMatrixDotOrg: nil, + isFederated: self.isFederated, + isMatrixDotOrg: self.isMatrixOrg, name: errorName, timeToDecryptMillis: timeToDecryptMillis, userTrustsOwnIdentity: self.trustOwnIdentityAtTimeOfFailure, - wasVisibleToUser: nil + wasVisibleToUser: self.wasVisibleToUser ) } } diff --git a/Riot/Modules/Analytics/DecryptionFailure.swift b/Riot/Modules/Analytics/DecryptionFailure.swift index 6d3f6c1a8..179509087 100644 --- a/Riot/Modules/Analytics/DecryptionFailure.swift +++ b/Riot/Modules/Analytics/DecryptionFailure.swift @@ -52,6 +52,14 @@ import AnalyticsEvents var eventLocalAgeMillis: Int? + /// Is the current user on matrix org + var isMatrixOrg: Bool? + /// Are the sender and recipient on the same homeserver + var isFederated: Bool? + + /// As for now the ios App only reports UTDs visible to user (error are reported from EventFormatter + var wasVisibleToUser: Bool = true + init(failedEventId: String, reason: DecryptionFailureReason, context: String, ts: TimeInterval) { self.failedEventId = failedEventId self.reason = reason diff --git a/Riot/Modules/Analytics/DecryptionFailureTracker.swift b/Riot/Modules/Analytics/DecryptionFailureTracker.swift index 503c733ba..0832476ff 100644 --- a/Riot/Modules/Analytics/DecryptionFailureTracker.swift +++ b/Riot/Modules/Analytics/DecryptionFailureTracker.swift @@ -103,6 +103,17 @@ class DecryptionFailureTracker: NSObject { failure.eventLocalAgeMillis = Int(exactly: eventRelativeAgeMillis) failure.trustOwnIdentityAtTimeOfFailure = isSessionVerified + let myDomain = userId.components(separatedBy: ":")[1] + failure.isMatrixOrg = myDomain == "matrix.org" + + if MXTools.isMatrixUserIdentifier(event.sender) { + let senderDomain = event.sender.components(separatedBy: ":")[1] + failure.isFederated = senderDomain != myDomain + } + + /// XXX for future work, as for now only the event formatter reports UTDs. That means that it's only UTD ~visible to users + failure.wasVisibleToUser = true + reportedFailures[failedEventId] = failure diff --git a/RiotTests/DecryptionFailureTrackerTests.swift b/RiotTests/DecryptionFailureTrackerTests.swift index c142514cb..d37b96f08 100644 --- a/RiotTests/DecryptionFailureTrackerTests.swift +++ b/RiotTests/DecryptionFailureTrackerTests.swift @@ -56,7 +56,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_grace_period() { - let myUser = "test@example.com"; + let myUser = "@test:example.com"; fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); @@ -95,7 +95,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_report_ratcheted_key_utd() { - let myUser = "test@example.com"; + let myUser = "@test:example.com"; fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); @@ -125,7 +125,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_report_unspecified_error() { - let myUser = "test@example.com"; + let myUser = "@test:example.com"; fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); @@ -157,7 +157,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_do_not_double_report() { - let myUser = "test@example.com"; + let myUser = "@test:example.com"; fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); @@ -199,7 +199,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_ignore_not_member() { - let myUser = "test@example.com"; + let myUser = "@test:example.com"; fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); @@ -234,7 +234,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_notification_center() { - let myUser = "test@example.com"; + let myUser = "@test:example.com"; fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); @@ -275,7 +275,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_should_report_late_decrypt() { - let myUser = "test@example.com"; + let myUser = "@test:example.com"; fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); @@ -320,7 +320,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_should_report_permanent_decryption_error() { - let myUser = "test@example.com"; + let myUser = "@test:example.com"; fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); @@ -361,7 +361,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_should_report_trust_status_at_decryption_time() { - let myUser = "test@example.com"; + let myUser = "@test:example.com"; fakeSession.mockUserId = myUser; let decryptionFailureTracker = DecryptionFailureTracker(); @@ -425,7 +425,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_should_report_event_age() { - let myUser = "test@example.com"; + let myUser = "@test:example.com"; fakeSession.mockUserId = myUser; let format = DateFormatter() @@ -477,7 +477,7 @@ class DecryptionFailureTrackerTests: XCTestCase { func test_should_report_expected_utds() { - let myUser = "test@example.com"; + let myUser = "@test:example.com"; fakeSession.mockUserId = myUser; let format = DateFormatter() @@ -529,5 +529,74 @@ class DecryptionFailureTrackerTests: XCTestCase { } + + func test_should_report_is_matrix_org_and_is_federated() { + + let myUser = "@test:example.com"; + fakeSession.mockUserId = myUser; + + let decryptionFailureTracker = DecryptionFailureTracker(); + decryptionFailureTracker.timeProvider = timeShifter; + + let testDelegate = AnalyticsDelegate(); + + decryptionFailureTracker.delegate = testDelegate; + + timeShifter.timestamp = TimeInterval(0) + + let fakeEvent = FakeEvent(id: "$0000"); + fakeEvent.sender = "@bob:example.com" + fakeEvent.decryptionError = NSError(domain: MXDecryptingErrorDomain, code: Int(MXDecryptingErrorUnknownInboundSessionIdCode.rawValue)) + + // set session as not yet verified + fakeCrossSigning.canTrustCrossSigning = false + + let fakeRoomState = FakeRoomState(); + fakeRoomState.mockMembers = FakeRoomMembers(joined: [myUser]) + + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent, withRoomState: fakeRoomState, mySession: fakeSession); + + // Simulate succesful decryption after max wait + timeShifter.timestamp = TimeInterval(70) + + decryptionFailureTracker.checkFailures(); + + XCTAssertEqual(testDelegate.reportedFailure?.isMatrixOrg, false); + XCTAssertEqual(testDelegate.reportedFailure?.isFederated, false); + + + let analyticsError = testDelegate.reportedFailure!.toAnalyticsEvent() + + XCTAssertEqual(analyticsError.isMatrixDotOrg, false) + XCTAssertEqual(analyticsError.isFederated, false) + + // Report a new error now that session is verified + + let fakeEvent2 = FakeEvent(id: "$0001"); + fakeEvent2.sender = "@bob:example.com" + fakeEvent2.decryptionError = NSError(domain: MXDecryptingErrorDomain, code: Int(MXDecryptingErrorUnknownInboundSessionIdCode.rawValue)) + + fakeSession.mockUserId = "@test:matrix.org"; + fakeRoomState.mockMembers = FakeRoomMembers(joined: [fakeSession.mockUserId]) + + decryptionFailureTracker.reportUnableToDecryptError(forEvent: fakeEvent2, withRoomState: fakeRoomState, mySession: fakeSession); + + // Simulate permanent UTD + timeShifter.timestamp = TimeInterval(140) + + decryptionFailureTracker.checkFailures(); + + XCTAssertEqual(testDelegate.reportedFailure?.failedEventId, "$0001"); + XCTAssertEqual(testDelegate.reportedFailure?.isMatrixOrg, true); + XCTAssertEqual(testDelegate.reportedFailure?.isFederated, true); + + let analyticsError2 = testDelegate.reportedFailure!.toAnalyticsEvent() + + XCTAssertEqual(analyticsError2.isMatrixDotOrg, true) + XCTAssertEqual(analyticsError2.isFederated, true) + + } + + } From a93d776fefa26bf0d86ce9c22f90beb1b8db99b8 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 15 Apr 2024 10:00:19 +0200 Subject: [PATCH 04/79] review use array last for safety --- Riot/Modules/Analytics/DecryptionFailureTracker.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Riot/Modules/Analytics/DecryptionFailureTracker.swift b/Riot/Modules/Analytics/DecryptionFailureTracker.swift index 0832476ff..d76a38ca5 100644 --- a/Riot/Modules/Analytics/DecryptionFailureTracker.swift +++ b/Riot/Modules/Analytics/DecryptionFailureTracker.swift @@ -103,12 +103,12 @@ class DecryptionFailureTracker: NSObject { failure.eventLocalAgeMillis = Int(exactly: eventRelativeAgeMillis) failure.trustOwnIdentityAtTimeOfFailure = isSessionVerified - let myDomain = userId.components(separatedBy: ":")[1] + let myDomain = userId.components(separatedBy: ":").last failure.isMatrixOrg = myDomain == "matrix.org" if MXTools.isMatrixUserIdentifier(event.sender) { - let senderDomain = event.sender.components(separatedBy: ":")[1] - failure.isFederated = senderDomain != myDomain + let senderDomain = event.sender.components(separatedBy: ":").last + failure.isFederated = senderDomain != nil && senderDomain != myDomain } /// XXX for future work, as for now only the event formatter reports UTDs. That means that it's only UTD ~visible to users From fe6dcd7e0a1e4238f4341f605a5bb6e5c34af1b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Mesk=C3=B3?= Date: Tue, 2 Apr 2024 15:52:22 +0000 Subject: [PATCH 05/79] Translated using Weblate (Hungarian) Currently translated at 98.9% (2390 of 2416 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ --- Riot/Assets/hu.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index 274042639..cc1a8dc8b 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -2740,3 +2740,4 @@ "key_verification_self_verify_security_upgrade_alert_title" = "Alkalmazás frissítve"; "settings_acceptable_use" = "Elfogadható felhasználói feltételek"; +"room_creation_user_not_found_prompt_title" = "Megerősítés"; From 419cc9cecc2b3a06b0b12dd5ef80b197f49655c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Mesk=C3=B3?= Date: Wed, 3 Apr 2024 11:27:03 +0000 Subject: [PATCH 06/79] Translated using Weblate (Hungarian) Currently translated at 99.2% (2399 of 2416 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ --- Riot/Assets/hu.lproj/Vector.strings | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index cc1a8dc8b..21632cfec 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -2741,3 +2741,14 @@ "key_verification_self_verify_security_upgrade_alert_title" = "Alkalmazás frissítve"; "settings_acceptable_use" = "Elfogadható felhasználói feltételek"; "room_creation_user_not_found_prompt_title" = "Megerősítés"; +"room_creation_user_not_found_prompt_message" = "Nem található profil ehhez a Matrix-azonosítóhoz. Mindenképp elindítja a privát csevegést?"; +"room_creation_user_not_found_prompt_invite_action" = "Privát csevegés mindenképp"; +"room_participants_invite_unknown_participant_prompt_to_msg" = "Nem található profil ehhez a Matrix-azonosítóhoz. Mindenképp meghívja %@ felhasználót a(z) %@ szobába?"; +"room_participants_invite_anyway" = "Meghívás mindenképp"; + +// Room commands descriptions +"room_command_change_display_name_description" = "Megváltoztatja a megjelenítendő becenevét"; +"room_command_emote_description" = "Megjeleníti a műveletet"; +"room_command_join_room_description" = "Csatlakozik a megadott című szobához"; +"room_command_part_room_description" = "Elhagyja a szobát"; +"room_command_invite_user_description" = "Meghívja az adott azonosítójú felhasználót a jelenlegi szobába"; From ef84f4cd784706f59eac3213bdfecd7992b5d6c1 Mon Sep 17 00:00:00 2001 From: Danial Behzadi Date: Sat, 13 Apr 2024 16:26:53 +0000 Subject: [PATCH 07/79] Translated using Weblate (Persian) Currently translated at 45.6% (1103 of 2416 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/fa/ --- Riot/Assets/fa.lproj/Vector.strings | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Riot/Assets/fa.lproj/Vector.strings b/Riot/Assets/fa.lproj/Vector.strings index a7f7b720c..489c8540d 100644 --- a/Riot/Assets/fa.lproj/Vector.strings +++ b/Riot/Assets/fa.lproj/Vector.strings @@ -97,7 +97,7 @@ "contacts_address_book_matrix_users_toggle" = "فقط کاربران ماتریس"; "directory_search_results_more_than" = ">%tu نتیجه برای %@ یافت شد"; "directory_search_results" = "%tu نتیجه برای %@ یافت شد"; -"search_in_progress" = "در حال جست وجو"; +"search_in_progress" = "جوییدن…"; "search_no_result" = "نتیچه ای یافت نشد"; "search_people_placeholder" = "جستجو بر اساس شناسه کاربری، نام یا آدرس ایمیل"; "search_default_placeholder" = "جست و جو"; @@ -246,7 +246,7 @@ "room_accessibility_search" = "جستجو"; "room_message_edits_history_title" = "ویرایش های پیام"; "room_resource_usage_limit_reached_message_2" = "برخی از کاربران نمی توانند وارد سیستم شوند."; -"room_resource_limit_exceeded_message_contact_3" = " برای ادامه استفاده از این سرویس"; +"room_resource_limit_exceeded_message_contact_3" = " برای ادامه استفاده از این خدمت."; "room_resource_limit_exceeded_message_contact_2_link" = "با سرپرست سرویس خود تماس بگیرید"; "room_resource_limit_exceeded_message_contact_1" = " لطفا "; "room_predecessor_link" = "برای دیدن پیام‌های قدیمی‌تر به اینجاضربه بزنید."; @@ -416,7 +416,7 @@ "event_formatter_call_retry" = "تلاش مجدد"; "event_formatter_call_answer" = "پاسخ"; "event_formatter_call_decline" = "رد تماس"; -"event_formatter_call_back" = "تماس"; +"event_formatter_call_back" = "پاسخ تماس"; "event_formatter_call_connection_failed" = "ارتباط ناموفق بود"; "event_formatter_call_missed_video" = "تماس ویدیویی از دست رفته"; "event_formatter_call_missed_voice" = "تماس صوتی از دست رفته"; @@ -464,7 +464,7 @@ "group_participants_invited_section" = "دعوت شده"; "group_participants_invite_malformed_id_title" = "خطای دعوت"; "group_participants_invite_another_user" = "جستجو / دعوت با شناسه کاربری یا نام"; -"group_participants_filter_members" = "اعضای انجمن را فیلتر کنید"; +"group_participants_filter_members" = "پالایش اعضای اجتماع"; "group_participants_invite_prompt_msg" = "آیا مطمئنید که می خواهید %@ را به این گروه دعوت کنید؟"; "group_participants_invite_prompt_title" = "تایید"; "group_participants_remove_prompt_msg" = "آیا مطمئنید که می خواهید %@ را از این گروه حذف کنید؟"; @@ -570,7 +570,7 @@ "room_details_files" = "بارگذاری شده ها"; "room_details_people" = "اعضا"; "room_details_title_for_dm" = "جزییات"; -"identity_server_settings_alert_disconnect_still_sharing_3pid_button" = "به هر حال قطع کن"; +"identity_server_settings_alert_disconnect_still_sharing_3pid_button" = "قطع شدن به هر روی"; "identity_server_settings_alert_disconnect_button" = "قطع کردن"; "identity_server_settings_disconnect" = "قطع کردن"; "identity_server_settings_change" = "تغییر دادن"; @@ -652,7 +652,7 @@ "settings_confirm_password" = "تایید رمز"; "settings_new_password" = "رمز جدید"; "settings_old_password" = "رمز قدیمی"; -"settings_third_party_notices" = "اعلامیه های شخص ثالث"; +"settings_third_party_notices" = "یادآوری‌های سوم‌شخص"; "settings_privacy_policy" = "سیاست حفظ حریم خصوصی"; "settings_term_conditions" = "شرایط و ضوابط"; "settings_copyright" = "کپی رایت"; @@ -684,7 +684,7 @@ "settings_room_upgrades" = "ارتقاء اتاق"; "settings_messages_by_a_bot" = "پیام های ربات"; "settings_call_invitations" = "دعوت نامه های تماس"; -"settings_room_invitations" = "دعوت نامه های اتاق"; +"settings_room_invitations" = "دعوت‌های اتاق"; "settings_messages_containing_keywords" = "کلمات کلیدی"; "settings_messages_containing_at_room" = "@ اتاق"; "settings_messages_containing_user_name" = "نام کاربری من"; @@ -694,13 +694,13 @@ "settings_encrypted_direct_messages" = "پیام های مستقیم رمزگذاری شده"; "settings_direct_messages" = "پیام مستقیم"; "settings_notify_me_for" = "به من اطلاع بده برای"; -"settings_mentions_and_keywords" = "ذکر و کلمات کلیدی"; +"settings_mentions_and_keywords" = "نام‌بری و کلیدواژگان"; "settings_default" = "اعلان های پیش فرض"; "settings_notifications_disabled_alert_message" = "برای فعال کردن اعلان‌ها، به تنظیمات دستگاه خود بروید."; "settings_notifications_disabled_alert_title" = "غیر فعال کردن اعلان ها"; "settings_pin_rooms_with_missed_notif" = "پین کردن اتاق هایی با اعلان های از دست رفته"; "settings_pin_rooms_with_unread" = "پین کردن اتاق هایی با پیام های خوانده نشده"; -"settings_global_settings_info" = "تنظیمات اعلان جهانی در سرویس گیرنده وب %@ شما موجود است"; +"settings_global_settings_info" = "تنظیمات آگاهی عمومی در کارخواه وب %@تان موجود است"; "settings_show_decrypted_content" = "نمایش محتوای رمزگشایی شده"; "settings_device_notifications" = "اعلان های دستگاه"; "settings_enable_push_notif" = "اعلان ها در این دستگاه"; @@ -1346,3 +1346,5 @@ "onboarding_splash_page_2_title" = "تحت کنترل شماست."; "onboarding_splash_page_1_message" = "یک ارتباط امن و مستقل که سطح حریم شخصی آن دقیقا مشابه ارتباط رو در رو در منزل شماست."; "accessibility_selected" = "انتخاب شده"; +"room_multiple_typing_notification" = "٪@ و دیگران"; +"room_title_members" = "%@ عضو"; From 48f2b7bb694ca4ec1cc2300f456cc836aed0458f Mon Sep 17 00:00:00 2001 From: r2d2sq13 Date: Mon, 22 Apr 2024 13:57:57 +0000 Subject: [PATCH 08/79] Translated using Weblate (Georgian) Currently translated at 2.7% (66 of 2416 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/ka/ --- Riot/Assets/ka.lproj/Vector.strings | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/Riot/Assets/ka.lproj/Vector.strings b/Riot/Assets/ka.lproj/Vector.strings index 8b1378917..8c20e5dc3 100644 --- a/Riot/Assets/ka.lproj/Vector.strings +++ b/Riot/Assets/ka.lproj/Vector.strings @@ -1 +1,77 @@ + +// String for App Store +"store_short_description" = "უსაფრთხო დეცენტრალიზებული ჩატი/ვოიპი"; + +// Titles +"title_home" = "მთავარი"; +"title_favourites" = "ფავორიტები"; +"title_people" = "ხალხი"; +"title_rooms" = "ოთახები"; +"title_groups" = "თემები"; +"warning" = "გაფრთხილება"; + +// Actions +"view" = "ხედი"; +"next" = "შემდეგი"; +"back" = "უკან"; +"continue" = "გაგრძელება"; +"create" = "შექმნა"; +"start" = "აწყება"; +"leave" = "დატოვება"; +"remove" = "წაშლა"; +"retry" = "გამეორება"; +"on" = "ჩართული"; +"off" = "გამორთული"; +"enable" = "ჩართვა"; +"save" = "შენახვა"; +"join" = "შეუერთდება"; +"decline" = "უარყოფა"; +"accept" = "მიღება"; +"camera" = "კამერა"; +"voice" = "ხმა"; +"video" = "ვიდეო"; +"active_call" = "აქტიური ზარი"; +"later" = "შემდეგ"; +"rename" = "გადარქმევა"; +"collapse" = "ჩაკეცვა"; +"send_to" = "გაგზავნა %@-ს"; +"close" = "დახურვა"; +"skip" = "გამოტოვება"; +"joined" = "შეუერთდა"; +"switch" = "გადართვა"; +"more" = "მეტი"; +"less" = "ნაკლები"; +"open" = "გახსნა"; +"private" = "ირადი"; +"public" = "საჯარო"; +"stop" = "შეჩერება"; +"new_word" = "ახალი"; +"existing" = "არსებული"; +"add" = "დამატება"; +"ok" = "კარგი"; +"error" = "შეცდომა"; +"suggest" = "შესთავაზება"; +"confirm" = "დადასტურება"; +"invite_to" = "მიწვევა %@-ში"; + +// Activities +"loading" = "ჩატვირთვა"; +"sending" = "გაგზავნა"; +"callbar_active_and_single_paused" = "1 აქტიური ზარი (%@) · 1 შეჩერებული ზარი"; +"callbar_active_and_multiple_paused" = "1 აქტიური ზარი (%@) · %@ შეჩერებული ზარები"; +"callbar_only_single_paused" = "შეჩერებული ზარი"; +"callbar_return" = "დაბრუნება"; +"store_promotional_text" = "კონფიდენციალობის დაცვით ჩატისა და თანამშრომლობის აპლიკაცია, ღია ქსელზე. დეცენტრალიზებული, რათა მართვა გადაგიცემათ. არაა დათამაინინგი, არაა უკანა კარები და არაა მესამე მხარის წვდომა."; +"invite" = "მიწვევა"; +"cancel" = "გაუქმება"; +"preview" = "წინასწარი ხილვა"; +"active_call_details" = "აქტიური ზარი (%@)"; +"joining" = "შეერთება"; +"done" = "დასრულებული"; +"edit" = "რედაქტირება"; +"saving" = "შენახვა"; + +// Call Bar +"callbar_only_single_active" = "შეეხეთ, რომ დაბრუნდეთ ზარში (%@)"; +"callbar_only_multiple_paused" = "%@ შეჩერებული ზარები"; From d9c795a503f21067ceaa0d35e8086487c1e6a5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Mesk=C3=B3?= Date: Thu, 25 Apr 2024 10:57:49 +0000 Subject: [PATCH 09/79] Translated using Weblate (Hungarian) Currently translated at 99.4% (2402 of 2416 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ --- Riot/Assets/hu.lproj/Vector.strings | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index 21632cfec..c965d650c 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -2752,3 +2752,6 @@ "room_command_join_room_description" = "Csatlakozik a megadott című szobához"; "room_command_part_room_description" = "Elhagyja a szobát"; "room_command_invite_user_description" = "Meghívja az adott azonosítójú felhasználót a jelenlegi szobába"; +"room_command_kick_user_description" = "Eltávolítja az adott azonosítójú felhasználót ebből a szobából"; +"room_command_ban_user_description" = "Kitiltja az adott azonosítójú felhasználót"; +"room_command_unban_user_description" = "Feloldja az adott azonosítójú felhasználó kitiltását"; From 09b63052b19ed8521b3d447242f787821c6db61c Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 1 May 2024 09:54:29 +0100 Subject: [PATCH 10/79] Remove invalid string. --- Riot/Assets/fa.lproj/Vector.strings | 1 - 1 file changed, 1 deletion(-) diff --git a/Riot/Assets/fa.lproj/Vector.strings b/Riot/Assets/fa.lproj/Vector.strings index 489c8540d..4948e2e90 100644 --- a/Riot/Assets/fa.lproj/Vector.strings +++ b/Riot/Assets/fa.lproj/Vector.strings @@ -1346,5 +1346,4 @@ "onboarding_splash_page_2_title" = "تحت کنترل شماست."; "onboarding_splash_page_1_message" = "یک ارتباط امن و مستقل که سطح حریم شخصی آن دقیقا مشابه ارتباط رو در رو در منزل شماست."; "accessibility_selected" = "انتخاب شده"; -"room_multiple_typing_notification" = "٪@ و دیگران"; "room_title_members" = "%@ عضو"; From ae1d45ec831eb6943fe96775a200b36f93c0c781 Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 1 May 2024 10:41:03 +0100 Subject: [PATCH 11/79] changelog.d: Upgrade MatrixSDK version ([v0.27.7](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.27.7)). --- Podfile | 2 +- changelog.d/x-nolink-0.change | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/x-nolink-0.change diff --git a/Podfile b/Podfile index 9ad4fefa2..f2df4910e 100644 --- a/Podfile +++ b/Podfile @@ -16,7 +16,7 @@ use_frameworks! # - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI # # Warning: our internal tooling depends on the name of this variable name, so be sure not to change it -$matrixSDKVersion = '= 0.27.6' +$matrixSDKVersion = '= 0.27.7' # $matrixSDKVersion = :local # $matrixSDKVersion = { :branch => 'develop'} # $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } } diff --git a/changelog.d/x-nolink-0.change b/changelog.d/x-nolink-0.change new file mode 100644 index 000000000..ca236cb45 --- /dev/null +++ b/changelog.d/x-nolink-0.change @@ -0,0 +1 @@ +Upgrade MatrixSDK version ([v0.27.7](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.27.7)). \ No newline at end of file From fe83606d442cd66fc3ee6c0a6bf98958771b75ea Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 1 May 2024 10:41:03 +0100 Subject: [PATCH 12/79] version++ --- CHANGES.md | 7 +++++++ changelog.d/x-nolink-0.change | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) delete mode 100644 changelog.d/x-nolink-0.change diff --git a/CHANGES.md b/CHANGES.md index eb5267b66..2c1002292 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,10 @@ +## Changes in 1.11.10 (2024-05-01) + +🙌 Improvements + +- Upgrade MatrixSDK version ([v0.27.7](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.27.7)). + + ## Changes in 1.11.9 (2024-04-02) Others diff --git a/changelog.d/x-nolink-0.change b/changelog.d/x-nolink-0.change deleted file mode 100644 index ca236cb45..000000000 --- a/changelog.d/x-nolink-0.change +++ /dev/null @@ -1 +0,0 @@ -Upgrade MatrixSDK version ([v0.27.7](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.27.7)). \ No newline at end of file From 2a46731b1d5d648da4eb5e71e5e15d4d6e9529d1 Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 1 May 2024 10:46:07 +0100 Subject: [PATCH 13/79] Changelog. --- CHANGES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 2c1002292..0e6621096 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,10 @@ - Upgrade MatrixSDK version ([v0.27.7](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.27.7)). +Others + +- Improvements to reporting of decryption failures. + ## Changes in 1.11.9 (2024-04-02) From 995bc490e47c05621504a718ac4c02507c3e4985 Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 1 May 2024 12:00:08 +0100 Subject: [PATCH 14/79] finish version++ --- Podfile.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index 07f1fb4d9..c8298201a 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -39,9 +39,9 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.27.6): - - MatrixSDK/Core (= 0.27.6) - - MatrixSDK/Core (0.27.6): + - MatrixSDK (0.27.7): + - MatrixSDK/Core (= 0.27.7) + - MatrixSDK/Core (0.27.7): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) @@ -49,7 +49,7 @@ PODS: - OLMKit (~> 3.2.5) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/JingleCallStack (0.27.6): + - MatrixSDK/JingleCallStack (0.27.7): - JitsiMeetSDKLite (= 8.1.2-lite) - MatrixSDK/Core - MatrixSDKCrypto (0.3.13) @@ -102,8 +102,8 @@ DEPENDENCIES: - KeychainAccess (~> 4.2.2) - KTCenterFlowLayout (~> 1.3.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.27.6) - - MatrixSDK/JingleCallStack (= 0.27.6) + - MatrixSDK (= 0.27.7) + - MatrixSDK/JingleCallStack (= 0.27.7) - OLMKit - PostHog (~> 2.0.0) - ReadMoreTextView (~> 3.0.1) @@ -187,7 +187,7 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: 4129ab9c0acda1d0aad50b1c9765bd795b8d70b9 + MatrixSDK: e07b2309f3c6498c1df987441da7006d099c47a4 MatrixSDKCrypto: bf08b72f2cd015d8749420a2b8b92fc0536bedf4 OLMKit: da115f16582e47626616874e20f7bb92222c7a51 PostHog: 660ec6c9d80cec17b685e148f17f6785a88b597d @@ -208,6 +208,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: c87b532985dd755b373732f841e3bcfe616f4e4f +PODFILE CHECKSUM: 1197abec9c5affbef652747dd5cd6aaf00ef3a47 COCOAPODS: 1.14.3 From b06cbaef605050083bfbae97bd3d37f2675cc06c Mon Sep 17 00:00:00 2001 From: Doug Date: Wed, 1 May 2024 12:00:14 +0100 Subject: [PATCH 15/79] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index 5df7a12db..86d2d6377 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.10 -CURRENT_PROJECT_VERSION = 1.11.10 +MARKETING_VERSION = 1.11.11 +CURRENT_PROJECT_VERSION = 1.11.11 From 58a65c68ffedb4a8c676caaac93f5bc861319a5e Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 3 May 2024 14:09:38 +0200 Subject: [PATCH 16/79] added accessbility --- Riot/Assets/en.lproj/Vector.strings | 2 ++ Riot/Generated/Strings.swift | 8 ++++++++ RiotSwiftUI/Modules/Room/Composer/View/Composer.swift | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 6a7f09c6e..924bda31c 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2603,6 +2603,8 @@ To enable access, tap Settings> Location and select Always"; // MARK: - WYSIWYG Composer +"wysiwyg_composer_action_minimise_action" = "Shrink composer"; +"wysiwyg_composer_action_maximise_action" = "Expand composer"; // Send Media Actions "wysiwyg_composer_start_action_media_picker" = "Photo Library"; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index f5cc6ae5b..999f821c3 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -9567,6 +9567,14 @@ public class VectorL10n: NSObject { public static var widgetStickerPickerNoStickerpacksAlertAddNow: String { return VectorL10n.tr("Vector", "widget_sticker_picker_no_stickerpacks_alert_add_now") } + /// Expand composer + public static var wysiwygComposerActionMaximiseAction: String { + return VectorL10n.tr("Vector", "wysiwyg_composer_action_maximise_action") + } + /// Shrink composer + public static var wysiwygComposerActionMinimiseAction: String { + return VectorL10n.tr("Vector", "wysiwyg_composer_action_minimise_action") + } /// Apply bold format public static var wysiwygComposerFormatActionBold: String { return VectorL10n.tr("Vector", "wysiwyg_composer_format_action_bold") diff --git a/RiotSwiftUI/Modules/Room/Composer/View/Composer.swift b/RiotSwiftUI/Modules/Room/Composer/View/Composer.swift index 585098092..54f42cf74 100644 --- a/RiotSwiftUI/Modules/Room/Composer/View/Composer.swift +++ b/RiotSwiftUI/Modules/Room/Composer/View/Composer.swift @@ -82,6 +82,10 @@ struct Composer: View { wysiwygViewModel.maximised ? "minimiseButton" : "maximiseButton" } + private var toggleButtonAccessibilityLabel: String { + wysiwygViewModel.maximised ? VectorL10n.wysiwygComposerActionMinimiseAction : VectorL10n.wysiwygComposerActionMaximiseAction + } + private var toggleButtonImageName: String { wysiwygViewModel.maximised ? Asset.Images.minimiseComposer.name : Asset.Images.maximiseComposer.name } @@ -171,6 +175,7 @@ struct Composer: View { .frame(width: 16, height: 16) } .accessibilityIdentifier(toggleButtonAcccessibilityIdentifier) + .accessibilityLabel(toggleButtonAccessibilityLabel) .padding(.leading, 12) .padding(.trailing, 4) } From 19d431a189f2c6de59fb530176b4f45067a461e6 Mon Sep 17 00:00:00 2001 From: Hugh Nimmo-Smith Date: Wed, 8 May 2024 11:09:30 +0100 Subject: [PATCH 17/79] Add note about MSC3886, MSC3903 and MSC3906 being closed (#7788) --- Riot/Modules/Rendezvous/RendezvousService.swift | 4 ++++ .../QRLogin/Common/Service/MatrixSDK/QRLoginService.swift | 3 +++ 2 files changed, 7 insertions(+) diff --git a/Riot/Modules/Rendezvous/RendezvousService.swift b/Riot/Modules/Rendezvous/RendezvousService.swift index de8f07979..c7bf13bcd 100644 --- a/Riot/Modules/Rendezvous/RendezvousService.swift +++ b/Riot/Modules/Rendezvous/RendezvousService.swift @@ -40,6 +40,10 @@ enum RendezvousFlow: String { case SETUP_ADDITIONAL_DEVICE_V2 = "org.matrix.msc3906.setup.additional_device.v2" } +// n.b MSC3886/MSC3903/MSC3906 that this is based on are now closed. +// However, we want to keep this implementation around for some time. +// TODO: define an end-of-life date for this implementation. + /// Allows communication through a secure channel. Based on MSC3886 and MSC3903 @MainActor class RendezvousService { diff --git a/RiotSwiftUI/Modules/Authentication/QRLogin/Common/Service/MatrixSDK/QRLoginService.swift b/RiotSwiftUI/Modules/Authentication/QRLogin/Common/Service/MatrixSDK/QRLoginService.swift index daf2e93f5..cd645dd94 100644 --- a/RiotSwiftUI/Modules/Authentication/QRLogin/Common/Service/MatrixSDK/QRLoginService.swift +++ b/RiotSwiftUI/Modules/Authentication/QRLogin/Common/Service/MatrixSDK/QRLoginService.swift @@ -23,6 +23,9 @@ import ZXingObjC // MARK: - QRLoginService +// n.b MSC3886/MSC3903/MSC3906 that this is based on are now closed. +// However, we want to keep this implementation around for some time. +// TODO: define an end-of-life date for this implementation. class QRLoginService: NSObject, QRLoginServiceProtocol { private let client: AuthenticationRestClient private let sessionCreator: SessionCreatorProtocol From 6e887ae3183bee77b8b9904269476f712c51ca67 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 29 May 2024 13:39:02 +0300 Subject: [PATCH 18/79] Bump the `matrix-rich-text-editor-swift` to `v2.37.3` --- .../xcshareddata/xcschemes/Riot.xcscheme | 37 ++++++++----------- .../xcshareddata/swiftpm/Package.resolved | 8 ++-- project.yml | 4 +- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme index 52ec9a4e1..9350fef63 100644 --- a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme +++ b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme @@ -1,11 +1,10 @@ + version = "1.3"> + buildImplicitDependencies = "YES"> @@ -35,11 +34,20 @@ + + + + @@ -52,17 +60,6 @@ - - - - - - - - - - diff --git a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved index 511ea29a7..2d8489845 100644 --- a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -46,12 +46,12 @@ } }, { - "identity" : "matrix-wysiwyg-composer-swift", + "identity" : "matrix-rich-text-editor-swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/matrix-org/matrix-wysiwyg-composer-swift", + "location" : "https://github.com/matrix-org/matrix-rich-text-editor-swift", "state" : { - "revision" : "f788fe2482c0b89019f679a1f43dccf9c25a0782", - "version" : "2.29.0" + "revision" : "21c0dd6e9c0b38d19d97af8e3e99fe01df56825d", + "version" : "2.37.3" } }, { diff --git a/project.yml b/project.yml index 72c0ff8d4..c44219382 100644 --- a/project.yml +++ b/project.yml @@ -58,8 +58,8 @@ packages: url: https://github.com/element-hq/swift-ogg branch: 0.0.1 WysiwygComposer: - url: https://github.com/matrix-org/matrix-wysiwyg-composer-swift - version: 2.29.0 + url: https://github.com/matrix-org/matrix-rich-text-editor-swift + version: 2.37.3 DeviceKit: url: https://github.com/devicekit/DeviceKit majorVersion: 4.7.0 From e991b213107e75193f0bf5323333ee03157ecdec Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 29 May 2024 14:34:06 +0300 Subject: [PATCH 19/79] Bump the SDK, fix unit tests --- Podfile | 2 +- Podfile.lock | 24 ++++++++++++------------ RiotTests/FakeUtils.swift | 3 +++ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Podfile b/Podfile index f2df4910e..a2e54f0e9 100644 --- a/Podfile +++ b/Podfile @@ -16,7 +16,7 @@ use_frameworks! # - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI # # Warning: our internal tooling depends on the name of this variable name, so be sure not to change it -$matrixSDKVersion = '= 0.27.7' +$matrixSDKVersion = '= 0.27.8' # $matrixSDKVersion = :local # $matrixSDKVersion = { :branch => 'develop'} # $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } } diff --git a/Podfile.lock b/Podfile.lock index c8298201a..e78aa4b07 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -39,20 +39,20 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.27.7): - - MatrixSDK/Core (= 0.27.7) - - MatrixSDK/Core (0.27.7): + - MatrixSDK (0.27.8): + - MatrixSDK/Core (= 0.27.8) + - MatrixSDK/Core (0.27.8): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) - - MatrixSDKCrypto (= 0.3.13) + - MatrixSDKCrypto (= 0.4.2) - OLMKit (~> 3.2.5) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/JingleCallStack (0.27.7): + - MatrixSDK/JingleCallStack (0.27.8): - JitsiMeetSDKLite (= 8.1.2-lite) - MatrixSDK/Core - - MatrixSDKCrypto (0.3.13) + - MatrixSDKCrypto (0.4.2) - OLMKit (3.2.12): - OLMKit/olmc (= 3.2.12) - OLMKit/olmcpp (= 3.2.12) @@ -102,8 +102,8 @@ DEPENDENCIES: - KeychainAccess (~> 4.2.2) - KTCenterFlowLayout (~> 1.3.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.27.7) - - MatrixSDK/JingleCallStack (= 0.27.7) + - MatrixSDK (= 0.27.8) + - MatrixSDK/JingleCallStack (= 0.27.8) - OLMKit - PostHog (~> 2.0.0) - ReadMoreTextView (~> 3.0.1) @@ -187,8 +187,8 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: e07b2309f3c6498c1df987441da7006d099c47a4 - MatrixSDKCrypto: bf08b72f2cd015d8749420a2b8b92fc0536bedf4 + MatrixSDK: 4c5a8572a481340ab233451ad36c1322d371fae5 + MatrixSDKCrypto: 736069ee0a5ec12852ab3498bf2242acecc443fc OLMKit: da115f16582e47626616874e20f7bb92222c7a51 PostHog: 660ec6c9d80cec17b685e148f17f6785a88b597d ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d @@ -208,6 +208,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: 1197abec9c5affbef652747dd5cd6aaf00ef3a47 +PODFILE CHECKSUM: b6073389caf93d20d47c9e511f4b9c3e1ad6dc5d -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/RiotTests/FakeUtils.swift b/RiotTests/FakeUtils.swift index f6b1fe477..6077a449e 100644 --- a/RiotTests/FakeUtils.swift +++ b/RiotTests/FakeUtils.swift @@ -260,6 +260,9 @@ class FakeCrypto: NSObject, MXCrypto { } + func invalidateCache(_ done: @escaping () -> Void) { + + } } From d02ab09885925dea38f8d87de86ad80dd65f06c5 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 29 May 2024 14:37:54 +0300 Subject: [PATCH 20/79] version++ --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 0e6621096..5d1881ff8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +## Changes in 1.11.11 (2024-05-29) + +No significant changes. + + ## Changes in 1.11.10 (2024-05-01) 🙌 Improvements From 81611c65dc82f6c3b363717deb5b6faecc259a5d Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 29 May 2024 15:17:34 +0300 Subject: [PATCH 21/79] finish version++ --- Podfile.lock | 2 +- .../xcshareddata/xcschemes/Riot.xcscheme | 37 +++++++++++-------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index e78aa4b07..99552b321 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -210,4 +210,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: b6073389caf93d20d47c9e511f4b9c3e1ad6dc5d -COCOAPODS: 1.15.2 +COCOAPODS: 1.14.3 diff --git a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme index 9350fef63..52ec9a4e1 100644 --- a/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme +++ b/Riot.xcodeproj/xcshareddata/xcschemes/Riot.xcscheme @@ -1,10 +1,11 @@ + version = "1.7"> + buildImplicitDependencies = "YES" + runPostActionsOnFailure = "NO"> @@ -34,20 +35,11 @@ - - - - @@ -60,6 +52,17 @@ + + + + + + + + + + From 42f014c521dfe023be656af9e159ae666f720601 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 29 May 2024 15:17:42 +0300 Subject: [PATCH 22/79] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index 86d2d6377..c4af686bf 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.11 -CURRENT_PROJECT_VERSION = 1.11.11 +MARKETING_VERSION = 1.11.12 +CURRENT_PROJECT_VERSION = 1.11.12 From 9ae44659c07b4db4316ccf75dee604f4a313a6ae Mon Sep 17 00:00:00 2001 From: Doug <6060466+pixlwave@users.noreply.github.com> Date: Thu, 30 May 2024 13:11:19 +0100 Subject: [PATCH 23/79] Fix a crash when the user taps play multiple times and the download fails. (#7799) --- .../Room/Attachements/MXKAttachmentsViewController.m | 8 +++++++- changelog.d/7791.bugfix | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changelog.d/7791.bugfix diff --git a/Riot/Modules/Room/Attachements/MXKAttachmentsViewController.m b/Riot/Modules/Room/Attachements/MXKAttachmentsViewController.m index 331121341..48bcc8085 100644 --- a/Riot/Modules/Room/Attachements/MXKAttachmentsViewController.m +++ b/Riot/Modules/Room/Attachements/MXKAttachmentsViewController.m @@ -107,6 +107,8 @@ @property (nonatomic) BOOL customAnimationsEnabled; +@property (nonatomic) BOOL isLoadingVideo; + @end @implementation MXKAttachmentsViewController @@ -969,8 +971,10 @@ navigationBarDisplayTimer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(hideNavigationBar) userInfo:self repeats:NO]; } } - else + else if (!self.isLoadingVideo) { + self.isLoadingVideo = YES; + MXKPieChartView *pieChartView = [[MXKPieChartView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)]; pieChartView.progress = 0; pieChartView.progressColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.25]; @@ -1020,6 +1024,7 @@ [selectedCell.moviePlayer.player play]; [pieChartView removeFromSuperview]; + self.isLoadingVideo = NO; [self hideNavigationBar]; } @@ -1035,6 +1040,7 @@ MXLogDebug(@"[MXKAttachmentsVC] video download failed"); [pieChartView removeFromSuperview]; + self.isLoadingVideo = NO; // Display the navigation bar so that the user can leave this screen self.navigationBarContainer.hidden = NO; diff --git a/changelog.d/7791.bugfix b/changelog.d/7791.bugfix new file mode 100644 index 000000000..9bd6b87db --- /dev/null +++ b/changelog.d/7791.bugfix @@ -0,0 +1 @@ +Fix a crash when the user taps play multiple times and the video download fails. \ No newline at end of file From 08d236fd2de5b1be4b6b9640db2c63b9cdded608 Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 30 May 2024 13:15:25 +0100 Subject: [PATCH 24/79] version++ --- CHANGES.md | 7 +++++++ changelog.d/7791.bugfix | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) delete mode 100644 changelog.d/7791.bugfix diff --git a/CHANGES.md b/CHANGES.md index 5d1881ff8..bf6fc003b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,10 @@ +## Changes in 1.11.12 (2024-05-30) + +🐛 Bugfixes + +- Fix a crash when the user taps play multiple times and the video download fails. ([#7791](https://github.com/element-hq/element-ios/issues/7791)) + + ## Changes in 1.11.11 (2024-05-29) No significant changes. diff --git a/changelog.d/7791.bugfix b/changelog.d/7791.bugfix deleted file mode 100644 index 9bd6b87db..000000000 --- a/changelog.d/7791.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix a crash when the user taps play multiple times and the video download fails. \ No newline at end of file From f417dd530c292eaf3357e7cd8e80de466c78f39b Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 30 May 2024 14:23:14 +0100 Subject: [PATCH 25/79] finish version++ From 36b551a31795924d52aa5ef8043804c235492aab Mon Sep 17 00:00:00 2001 From: Doug Date: Thu, 30 May 2024 14:23:21 +0100 Subject: [PATCH 26/79] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index c4af686bf..281e714ad 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.12 -CURRENT_PROJECT_VERSION = 1.11.12 +MARKETING_VERSION = 1.11.13 +CURRENT_PROJECT_VERSION = 1.11.13 From b9a187c2f5aa1f3af492b0e7a62cc5c2c46f14d9 Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 21 May 2024 16:02:46 +0200 Subject: [PATCH 27/79] Bump posthog version to 3.25 --- Podfile | 2 - Podfile.lock | 6 +-- .../xcshareddata/swiftpm/Package.resolved | 17 ++++++-- Riot/Modules/Analytics/Analytics.swift | 1 - .../Analytics/PHGPostHogConfiguration.swift | 12 +++--- .../Analytics/PostHogAnalyticsClient.swift | 40 ++++++------------- Riot/target.yml | 1 + RiotNSE/target.yml | 1 + RiotTests/AnalyticsTests.swift | 3 +- project.yml | 3 ++ 10 files changed, 41 insertions(+), 45 deletions(-) diff --git a/Podfile b/Podfile index a2e54f0e9..3fb43f417 100644 --- a/Podfile +++ b/Podfile @@ -69,8 +69,6 @@ abstract_target 'RiotPods' do pod 'KeychainAccess', '~> 4.2.2' pod 'WeakDictionary', '~> 2.0' - # PostHog for analytics - pod 'PostHog', '~> 2.0.0' pod 'Sentry', '~> 7.15.0' pod 'OLMKit' diff --git a/Podfile.lock b/Podfile.lock index 99552b321..92be4cf9c 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -58,7 +58,6 @@ PODS: - OLMKit/olmcpp (= 3.2.12) - OLMKit/olmc (3.2.12) - OLMKit/olmcpp (3.2.12) - - PostHog (2.0.0) - ReadMoreTextView (3.0.1) - Realm (10.27.0): - Realm/Headers (= 10.27.0) @@ -105,7 +104,6 @@ DEPENDENCIES: - MatrixSDK (= 0.27.8) - MatrixSDK/JingleCallStack (= 0.27.8) - OLMKit - - PostHog (~> 2.0.0) - ReadMoreTextView (~> 3.0.1) - Reusable (~> 4.1) - Sentry (~> 7.15.0) @@ -147,7 +145,6 @@ SPEC REPOS: - MatrixSDK - MatrixSDKCrypto - OLMKit - - PostHog - ReadMoreTextView - Realm - Reusable @@ -190,7 +187,6 @@ SPEC CHECKSUMS: MatrixSDK: 4c5a8572a481340ab233451ad36c1322d371fae5 MatrixSDKCrypto: 736069ee0a5ec12852ab3498bf2242acecc443fc OLMKit: da115f16582e47626616874e20f7bb92222c7a51 - PostHog: 660ec6c9d80cec17b685e148f17f6785a88b597d ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d Realm: 9ca328bd7e700cc19703799785e37f77d1a130f2 Reusable: 6bae6a5e8aa793c9c441db0213c863a64bce9136 @@ -210,4 +206,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: b6073389caf93d20d47c9e511f4b9c3e1ad6dc5d -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2d8489845..bb13eadb2 100644 --- a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/devicekit/DeviceKit", "state" : { - "revision" : "20e0991f3975916ab0f6d58db84d8bc64f883537", - "version" : "4.7.0" + "revision" : "d37e70cb2646666dcf276d7d3d4a9760a41ff8a6", + "version" : "4.9.0" } }, { @@ -72,13 +72,22 @@ "version" : "0.8.4" } }, + { + "identity" : "posthog-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/PostHog/posthog-ios", + "state" : { + "revision" : "8b2508444962d67aa5f8770074f32d493383dafd", + "version" : "3.2.5" + } + }, { "identity" : "swift-collections", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections", "state" : { - "revision" : "48254824bb4248676bf7ce56014ff57b142b77eb", - "version" : "1.0.2" + "revision" : "94cf62b3ba8d4bed62680a282d4c25f9c63c2efb", + "version" : "1.1.0" } }, { diff --git a/Riot/Modules/Analytics/Analytics.swift b/Riot/Modules/Analytics/Analytics.swift index d9d68e2f8..270f1b3ef 100644 --- a/Riot/Modules/Analytics/Analytics.swift +++ b/Riot/Modules/Analytics/Analytics.swift @@ -14,7 +14,6 @@ // limitations under the License. // -import PostHog import AnalyticsEvents /// A class responsible for managing a variety of analytics clients diff --git a/Riot/Modules/Analytics/PHGPostHogConfiguration.swift b/Riot/Modules/Analytics/PHGPostHogConfiguration.swift index 8bed04920..875de74e4 100644 --- a/Riot/Modules/Analytics/PHGPostHogConfiguration.swift +++ b/Riot/Modules/Analytics/PHGPostHogConfiguration.swift @@ -16,14 +16,16 @@ import PostHog -extension PHGPostHogConfiguration { - static var standard: PHGPostHogConfiguration? { +extension PostHogConfig { + static var standard: PostHogConfig? { let analyticsConfiguration = BuildSettings.analyticsConfiguration guard analyticsConfiguration.isEnabled else { return nil } - let postHogConfiguration = PHGPostHogConfiguration(apiKey: analyticsConfiguration.apiKey, host: analyticsConfiguration.host) - postHogConfiguration.shouldSendDeviceID = false - + let postHogConfiguration = PostHogConfig(apiKey: analyticsConfiguration.apiKey, host: analyticsConfiguration.host) + // We capture screens manually + postHogConfiguration.captureScreenViews = false + + return postHogConfiguration } } diff --git a/Riot/Modules/Analytics/PostHogAnalyticsClient.swift b/Riot/Modules/Analytics/PostHogAnalyticsClient.swift index ec49716be..4df8f5d41 100644 --- a/Riot/Modules/Analytics/PostHogAnalyticsClient.swift +++ b/Riot/Modules/Analytics/PostHogAnalyticsClient.swift @@ -20,30 +20,31 @@ import AnalyticsEvents /// An analytics client that reports events to a PostHog server. class PostHogAnalyticsClient: AnalyticsClientProtocol { /// The PHGPostHog object used to report events. - private var postHog: PHGPostHog? + private var postHog: PostHogSDK? /// Any user properties to be included with the next captured event. private(set) var pendingUserProperties: AnalyticsEvent.UserProperties? static let shared = PostHogAnalyticsClient() - var isRunning: Bool { postHog?.enabled ?? false } + var isRunning: Bool { postHog != nil } func start() { // Only start if analytics have been configured in BuildSettings - guard let configuration = PHGPostHogConfiguration.standard else { return } + guard let configuration = PostHogConfig.standard else { return } if postHog == nil { - postHog = PHGPostHog(configuration: configuration) + PostHogSDK.shared.setup(configuration) + postHog = PostHogSDK.shared } - postHog?.enable() + postHog?.optIn() } func identify(id: String) { if let userProperties = pendingUserProperties { // As user properties overwrite old ones, compactMap the dictionary to avoid resetting any missing properties - postHog?.identify(id, properties: userProperties.properties.compactMapValues { $0 }) + postHog?.identify(id, userProperties: userProperties.properties.compactMapValues { $0 }) pendingUserProperties = nil } else { postHog?.identify(id) @@ -56,10 +57,9 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { } func stop() { - postHog?.disable() + postHog?.optOut() - // As of PostHog 1.4.4, setting the client to nil here doesn't release - // it. Keep it around to avoid having multiple instances if the user re-enables + self.postHog = nil } func flush() { @@ -67,11 +67,13 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { } func capture(_ event: AnalyticsEventProtocol) { - postHog?.capture(event.eventName, properties: attachUserProperties(to: event.properties)) + postHog?.capture(event.eventName, properties: event.properties, userProperties: pendingUserProperties?.properties.compactMapValues { $0 }) + // Pending user properties have been added + self.pendingUserProperties = nil } func screen(_ event: AnalyticsScreenProtocol) { - postHog?.screen(event.screenName.rawValue, properties: attachUserProperties(to: event.properties)) + postHog?.screen(event.screenName.rawValue, properties: event.properties) } func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties) { @@ -87,22 +89,6 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { numSpaces: userProperties.numSpaces ?? pendingUserProperties.numSpaces) } - // MARK: - Private - - /// Given a dictionary containing properties from an event, this method will return those properties - /// with any pending user properties included under the `$set` key. - /// - Parameter properties: A dictionary of properties from an event. - /// - Returns: The `properties` dictionary with any user properties included. - private func attachUserProperties(to properties: [String: Any]) -> [String: Any] { - guard isRunning, let userProperties = pendingUserProperties else { return properties } - - var properties = properties - - // As user properties overwrite old ones via $set, compactMap the dictionary to avoid resetting any missing properties - properties["$set"] = userProperties.properties.compactMapValues { $0 } - pendingUserProperties = nil - return properties - } } extension PostHogAnalyticsClient: RemoteFeaturesClientProtocol { diff --git a/Riot/target.yml b/Riot/target.yml index 352988bf3..c95d3cb3a 100644 --- a/Riot/target.yml +++ b/Riot/target.yml @@ -49,6 +49,7 @@ targets: - package: WysiwygComposer - package: DeviceKit - package: DTCoreText + - package: PostHog configFiles: Debug: Debug.xcconfig diff --git a/RiotNSE/target.yml b/RiotNSE/target.yml index 6bc5a474d..f046bc0fd 100644 --- a/RiotNSE/target.yml +++ b/RiotNSE/target.yml @@ -35,6 +35,7 @@ targets: - package: AnalyticsEvents - package: DeviceKit - package: DTCoreText + - package: PostHog configFiles: Debug: Debug.xcconfig diff --git a/RiotTests/AnalyticsTests.swift b/RiotTests/AnalyticsTests.swift index 33ed28389..73f3f66b1 100644 --- a/RiotTests/AnalyticsTests.swift +++ b/RiotTests/AnalyticsTests.swift @@ -127,7 +127,8 @@ class AnalyticsTests: XCTestCase { XCTAssertEqual(client.pendingUserProperties?.ftueUseCaseSelection, .PersonalMessaging, "The use case selection should match.") // When sending an event (tests run under Debug configuration so this is sent to the development instance) - client.screen(AnalyticsEvent.MobileScreen(durationMs: nil, screenName: .Home)) + let event = AnalyticsEvent.Signup(authenticationType: .Other) + client.capture(event) // Then the properties should be cleared XCTAssertNil(client.pendingUserProperties, "The user properties should be cleared.") diff --git a/project.yml b/project.yml index c44219382..a666fb1b7 100644 --- a/project.yml +++ b/project.yml @@ -66,3 +66,6 @@ packages: DTCoreText: url: https://github.com/Cocoanetics/DTCoreText version: 1.6.26 + PostHog: + url: https://github.com/PostHog/posthog-ios + minorVersion: 3.2.5 From 95b5845c8494961757b43957c74e079baeba6f98 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 27 May 2024 16:06:25 +0200 Subject: [PATCH 28/79] Review: use optout for isrunning --- Riot/Modules/Analytics/PostHogAnalyticsClient.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Modules/Analytics/PostHogAnalyticsClient.swift b/Riot/Modules/Analytics/PostHogAnalyticsClient.swift index 4df8f5d41..ac22db68f 100644 --- a/Riot/Modules/Analytics/PostHogAnalyticsClient.swift +++ b/Riot/Modules/Analytics/PostHogAnalyticsClient.swift @@ -27,7 +27,7 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { static let shared = PostHogAnalyticsClient() - var isRunning: Bool { postHog != nil } + var isRunning: Bool { postHog != nil && !postHog!.isOptOut() } func start() { // Only start if analytics have been configured in BuildSettings From f6116e59d7843e9ea022e5339ef6a9b8228623f6 Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 31 May 2024 15:54:21 +0200 Subject: [PATCH 29/79] post rebase fix --- Podfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Podfile.lock b/Podfile.lock index 92be4cf9c..b830adadb 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -204,6 +204,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: b6073389caf93d20d47c9e511f4b9c3e1ad6dc5d +PODFILE CHECKSUM: 3bbda8faf037705f421dad839d6f5b1aef399f99 COCOAPODS: 1.15.2 From 78498be4ce49ea021295260aee1f172e3b7a384e Mon Sep 17 00:00:00 2001 From: Valere Date: Sat, 1 Jun 2024 13:05:04 +0200 Subject: [PATCH 30/79] Analytics | Add support for super properties and appPlatform --- .../xcshareddata/swiftpm/Package.resolved | 4 +- Riot/Modules/Analytics/Analytics.swift | 17 ++- .../Analytics/AnalyticsClientProtocol.swift | 7 + .../Analytics/PostHogAnalyticsClient.swift | 56 +++++++- Riot/Modules/Analytics/PosthogProtocol.swift | 53 +++++++ RiotTests/AnalyticsTests.swift | 12 +- RiotTests/FakeUtils.swift | 133 ++++++++++++++++++ RiotTests/PostHogAnalyticsClientTests.swift | 113 +++++++++++++++ project.yml | 2 +- 9 files changed, 380 insertions(+), 17 deletions(-) create mode 100644 Riot/Modules/Analytics/PosthogProtocol.swift create mode 100644 RiotTests/PostHogAnalyticsClientTests.swift diff --git a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved index bb13eadb2..c90d47d46 100644 --- a/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Riot.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/matrix-org/matrix-analytics-events", "state" : { - "revision" : "44d5a0e898a71f8abbbe12afe9d73e82d370a9a1", - "version" : "0.15.0" + "revision" : "de0cac487e5e7f607ee17045882204c91585461f", + "version" : "0.23.1" } }, { diff --git a/Riot/Modules/Analytics/Analytics.swift b/Riot/Modules/Analytics/Analytics.swift index 270f1b3ef..f284c2aa4 100644 --- a/Riot/Modules/Analytics/Analytics.swift +++ b/Riot/Modules/Analytics/Analytics.swift @@ -94,6 +94,13 @@ import AnalyticsEvents guard let session = session else { return } useAnalyticsSettings(from: session) + self.client.updateSuperProperties( + AnalyticsEvent.SuperProperties( + appPlatform: .EI, + cryptoSDK: .Rust, + cryptoSDKVersion: session.crypto.version + ) + ) } /// Stops analytics tracking and calls `reset` to clear any IDs and event queues. @@ -148,6 +155,13 @@ import AnalyticsEvents switch result { case .success(let settings): self.identify(with: settings) + self.client.updateSuperProperties( + AnalyticsEvent.SuperProperties( + appPlatform: .EI, + cryptoSDK: .Rust, + cryptoSDKVersion: session.crypto.version + ) + ) self.service = nil case .failure: MXLog.error("[Analytics] Failed to use analytics settings. Will continue to run without analytics ID.") @@ -242,7 +256,8 @@ extension Analytics { let userProperties = AnalyticsEvent.UserProperties(allChatsActiveFilter: allChatsActiveFilter?.analyticsName, ftueUseCaseSelection: ftueUseCase?.analyticsName, numFavouriteRooms: numFavouriteRooms, - numSpaces: numSpaces) + numSpaces: numSpaces, + recoveryState: nil, verificationState: nil) client.updateUserProperties(userProperties) } diff --git a/Riot/Modules/Analytics/AnalyticsClientProtocol.swift b/Riot/Modules/Analytics/AnalyticsClientProtocol.swift index e16b962e5..1e0acc54e 100644 --- a/Riot/Modules/Analytics/AnalyticsClientProtocol.swift +++ b/Riot/Modules/Analytics/AnalyticsClientProtocol.swift @@ -53,4 +53,11 @@ protocol AnalyticsClientProtocol { /// be a delay when updating user properties as these are cached to be included /// as part of the next event that gets captured. func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties) + + + /// Updates the user properties. + /// Super properties added to all captured events and screen. + /// - Parameter superProperties: The properties event to capture. + func updateSuperProperties(_ event: AnalyticsEvent.SuperProperties) + } diff --git a/Riot/Modules/Analytics/PostHogAnalyticsClient.swift b/Riot/Modules/Analytics/PostHogAnalyticsClient.swift index ac22db68f..5a70c5837 100644 --- a/Riot/Modules/Analytics/PostHogAnalyticsClient.swift +++ b/Riot/Modules/Analytics/PostHogAnalyticsClient.swift @@ -19,23 +19,39 @@ import AnalyticsEvents /// An analytics client that reports events to a PostHog server. class PostHogAnalyticsClient: AnalyticsClientProtocol { + + private var posthogFactory: PostHogFactory = DefaultPostHogFactory() + + init(posthogFactory: PostHogFactory? = nil) { + if let factory = posthogFactory { + self.posthogFactory = factory + } + } + /// The PHGPostHog object used to report events. - private var postHog: PostHogSDK? + private var postHog: PostHogProtocol? /// Any user properties to be included with the next captured event. private(set) var pendingUserProperties: AnalyticsEvent.UserProperties? + /// Super Properties are properties associated with events that are set once and then sent with every capture call, be it a $screen, an autocaptured button click, or anything else. + /// It is different from user properties that will be attached to the user and not events. + /// Not persisted for now, should be set on start. + private var superProperties: AnalyticsEvent.SuperProperties? + static let shared = PostHogAnalyticsClient() - var isRunning: Bool { postHog != nil && !postHog!.isOptOut() } + var isRunning: Bool { + guard let postHog else { return false } + return !postHog.isOptOut() + } func start() { // Only start if analytics have been configured in BuildSettings guard let configuration = PostHogConfig.standard else { return } if postHog == nil { - PostHogSDK.shared.setup(configuration) - postHog = PostHogSDK.shared + postHog = posthogFactory.createPostHog(config: configuration) } postHog?.optIn() @@ -67,13 +83,13 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { } func capture(_ event: AnalyticsEventProtocol) { - postHog?.capture(event.eventName, properties: event.properties, userProperties: pendingUserProperties?.properties.compactMapValues { $0 }) + postHog?.capture(event.eventName, properties: attachSuperProperties(to: event.properties), userProperties: pendingUserProperties?.properties.compactMapValues { $0 }) // Pending user properties have been added self.pendingUserProperties = nil } func screen(_ event: AnalyticsScreenProtocol) { - postHog?.screen(event.screenName.rawValue, properties: event.properties) + postHog?.screen(event.screenName.rawValue, properties: attachSuperProperties(to: event.properties)) } func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties) { @@ -86,9 +102,35 @@ class PostHogAnalyticsClient: AnalyticsClientProtocol { self.pendingUserProperties = AnalyticsEvent.UserProperties(allChatsActiveFilter: userProperties.allChatsActiveFilter ?? pendingUserProperties.allChatsActiveFilter, ftueUseCaseSelection: userProperties.ftueUseCaseSelection ?? pendingUserProperties.ftueUseCaseSelection, numFavouriteRooms: userProperties.numFavouriteRooms ?? pendingUserProperties.numFavouriteRooms, - numSpaces: userProperties.numSpaces ?? pendingUserProperties.numSpaces) + numSpaces: userProperties.numSpaces ?? pendingUserProperties.numSpaces, + // Not yet supported + recoveryState: nil, verificationState: nil) } + func updateSuperProperties(_ updatedProperties: AnalyticsEvent.SuperProperties) { + self.superProperties = AnalyticsEvent.SuperProperties( + appPlatform: updatedProperties.appPlatform ?? superProperties?.appPlatform, + cryptoSDK: updatedProperties.cryptoSDK ?? superProperties?.cryptoSDK, + cryptoSDKVersion: updatedProperties.cryptoSDKVersion ?? superProperties?.cryptoSDKVersion + ) + } + + /// Attach super properties to events. + /// If the property is already set on the event, the already set value will be kept. + private func attachSuperProperties(to properties: [String: Any]) -> [String: Any] { + guard isRunning, let superProperties else { return properties } + + var properties = properties + + superProperties.properties.forEach { (key: String, value: Any) in + if properties[key] == nil { + properties[key] = value + } + } + return properties + } + + } extension PostHogAnalyticsClient: RemoteFeaturesClientProtocol { diff --git a/Riot/Modules/Analytics/PosthogProtocol.swift b/Riot/Modules/Analytics/PosthogProtocol.swift new file mode 100644 index 000000000..d24d19e17 --- /dev/null +++ b/Riot/Modules/Analytics/PosthogProtocol.swift @@ -0,0 +1,53 @@ +// +// Copyright 2024 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import PostHog + +protocol PostHogProtocol { + func optIn() + + func optOut() + + func reset() + + func flush() + + func capture(_ event: String, properties: [String: Any]?, userProperties: [String: Any]?) + + func screen(_ screenTitle: String, properties: [String: Any]?) + + func isFeatureEnabled(_ feature: String) -> Bool + + func identify(_ distinctId: String) + + func identify(_ distinctId: String, userProperties: [String: Any]?) + + func isOptOut() -> Bool +} + +protocol PostHogFactory { + func createPostHog(config: PostHogConfig) -> PostHogProtocol +} + +class DefaultPostHogFactory: PostHogFactory { + func createPostHog(config: PostHogConfig) -> PostHogProtocol { + PostHogSDK.shared.setup(config) + return PostHogSDK.shared + } +} + +extension PostHogSDK: PostHogProtocol { } diff --git a/RiotTests/AnalyticsTests.swift b/RiotTests/AnalyticsTests.swift index 73f3f66b1..a8759c017 100644 --- a/RiotTests/AnalyticsTests.swift +++ b/RiotTests/AnalyticsTests.swift @@ -78,7 +78,7 @@ class AnalyticsTests: XCTestCase { XCTAssertNil(client.pendingUserProperties, "No user properties should have been set yet.") // When updating the user properties - client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: nil, ftueUseCaseSelection: .PersonalMessaging, numFavouriteRooms: 4, numSpaces: 5)) + client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: nil, ftueUseCaseSelection: .PersonalMessaging, numFavouriteRooms: 4, numSpaces: 5, recoveryState: nil, verificationState: nil)) // Then the properties should be cached XCTAssertNotNil(client.pendingUserProperties, "The user properties should be cached.") @@ -90,7 +90,7 @@ class AnalyticsTests: XCTestCase { func testMergingUserProperties() { // Given a client with a cached use case user properties let client = PostHogAnalyticsClient() - client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: nil, ftueUseCaseSelection: .PersonalMessaging, numFavouriteRooms: nil, numSpaces: nil)) + client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: nil, ftueUseCaseSelection: .PersonalMessaging, numFavouriteRooms: nil, numSpaces: nil, recoveryState: nil, verificationState: nil)) XCTAssertNotNil(client.pendingUserProperties, "The user properties should be cached.") XCTAssertEqual(client.pendingUserProperties?.ftueUseCaseSelection, .PersonalMessaging, "The use case selection should match.") @@ -98,7 +98,7 @@ class AnalyticsTests: XCTestCase { XCTAssertNil(client.pendingUserProperties?.numSpaces, "The number of spaces should not be set.") // When updating the number of spaces - client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: nil, ftueUseCaseSelection: nil, numFavouriteRooms: 4, numSpaces: 5)) + client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: nil, ftueUseCaseSelection: nil, numFavouriteRooms: 4, numSpaces: 5, recoveryState: nil, verificationState: nil)) // Then the new properties should be updated and the existing properties should remain unchanged XCTAssertNotNil(client.pendingUserProperties, "The user properties should be cached.") @@ -107,7 +107,7 @@ class AnalyticsTests: XCTestCase { XCTAssertEqual(client.pendingUserProperties?.numSpaces, 5, "The number of spaces should have been updated.") // When updating the number of spaces - client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: .Favourites, ftueUseCaseSelection: nil, numFavouriteRooms: nil, numSpaces: nil)) + client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: .Favourites, ftueUseCaseSelection: nil, numFavouriteRooms: nil, numSpaces: nil, recoveryState: nil, verificationState: nil)) // Then the new properties should be updated and the existing properties should remain unchanged XCTAssertNotNil(client.pendingUserProperties, "The user properties should be cached.") @@ -120,7 +120,7 @@ class AnalyticsTests: XCTestCase { func testSendingUserProperties() { // Given a client with user properties set let client = PostHogAnalyticsClient() - client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: nil, ftueUseCaseSelection: .PersonalMessaging, numFavouriteRooms: nil, numSpaces: nil)) + client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: nil, ftueUseCaseSelection: .PersonalMessaging, numFavouriteRooms: nil, numSpaces: nil, recoveryState: nil, verificationState: nil)) client.start() XCTAssertNotNil(client.pendingUserProperties, "The user properties should be cached.") @@ -137,7 +137,7 @@ class AnalyticsTests: XCTestCase { func testSendingUserPropertiesWithIdentify() { // Given a client with user properties set let client = PostHogAnalyticsClient() - client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: nil, ftueUseCaseSelection: .PersonalMessaging, numFavouriteRooms: nil, numSpaces: nil)) + client.updateUserProperties(AnalyticsEvent.UserProperties(allChatsActiveFilter: nil, ftueUseCaseSelection: .PersonalMessaging, numFavouriteRooms: nil, numSpaces: nil, recoveryState: nil, verificationState: nil)) client.start() XCTAssertNotNil(client.pendingUserProperties, "The user properties should be cached.") diff --git a/RiotTests/FakeUtils.swift b/RiotTests/FakeUtils.swift index 6077a449e..2f2ad4e63 100644 --- a/RiotTests/FakeUtils.swift +++ b/RiotTests/FakeUtils.swift @@ -15,6 +15,8 @@ // import Foundation +import PostHog +@testable import Element class FakeEvent: MXEvent { @@ -346,3 +348,134 @@ class FakeKeyVerificationManager: NSObject, MXKeyVerificationManager { } } + +class MockPostHog: PostHogProtocol { + + private var enabled = false + + func optIn() { + enabled = true + } + + func optOut() { + enabled = false + } + + func reset() { + + } + + func flush() { + + } + + var capturePropertiesUserPropertiesUnderlyingCallsCount = 0 + var capturePropertiesUserPropertiesCallsCount: Int { + get { + if Thread.isMainThread { + return capturePropertiesUserPropertiesUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = capturePropertiesUserPropertiesUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + capturePropertiesUserPropertiesUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + capturePropertiesUserPropertiesUnderlyingCallsCount = newValue + } + } + } + } + var capturePropertiesUserPropertiesCalled: Bool { + return capturePropertiesUserPropertiesCallsCount > 0 + } + var capturePropertiesUserPropertiesReceivedArguments: (event: String, properties: [String: Any]?, userProperties: [String: Any]?)? + var capturePropertiesUserPropertiesReceivedInvocations: [(event: String, properties: [String: Any]?, userProperties: [String: Any]?)] = [] + var capturePropertiesUserPropertiesClosure: ((String, [String: Any]?, [String: Any]?) -> Void)? + + func capture(_ event: String, properties: [String: Any]?, userProperties: [String: Any]?) { + if !enabled { return } + capturePropertiesUserPropertiesCallsCount += 1 + capturePropertiesUserPropertiesReceivedArguments = (event: event, properties: properties, userProperties: userProperties) + capturePropertiesUserPropertiesReceivedInvocations.append((event: event, properties: properties, userProperties: userProperties)) + capturePropertiesUserPropertiesClosure?(event, properties, userProperties) + } + + var screenPropertiesUnderlyingCallsCount = 0 + var screenPropertiesCallsCount: Int { + get { + if Thread.isMainThread { + return screenPropertiesUnderlyingCallsCount + } else { + var returnValue: Int? = nil + DispatchQueue.main.sync { + returnValue = screenPropertiesUnderlyingCallsCount + } + + return returnValue! + } + } + set { + if Thread.isMainThread { + screenPropertiesUnderlyingCallsCount = newValue + } else { + DispatchQueue.main.sync { + screenPropertiesUnderlyingCallsCount = newValue + } + } + } + } + + var screenPropertiesCalled: Bool { + return screenPropertiesCallsCount > 0 + } + var screenPropertiesReceivedArguments: (screenTitle: String, properties: [String: Any]?)? + var screenPropertiesReceivedInvocations: [(screenTitle: String, properties: [String: Any]?)] = [] + var screenPropertiesClosure: ((String, [String: Any]?) -> Void)? + + func screen(_ screenTitle: String, properties: [String: Any]?) { + if !enabled { return } + screenPropertiesCallsCount += 1 + screenPropertiesReceivedArguments = (screenTitle: screenTitle, properties: properties) + screenPropertiesReceivedInvocations.append((screenTitle: screenTitle, properties: properties)) + screenPropertiesClosure?(screenTitle, properties) + } + + func isFeatureEnabled(_ feature: String) -> Bool { + return true + } + + func identify(_ distinctId: String) { + + } + + func identify(_ distinctId: String, userProperties: [String : Any]?) { + + } + + func isOptOut() -> Bool { + !enabled + } + + +} + +class MockPostHogFactory: PostHogFactory { + var mock: PostHogProtocol! + + init(mock: PostHogProtocol) { + self.mock = mock + } + + func createPostHog(config: PostHogConfig) -> PostHogProtocol { + mock + } +} + diff --git a/RiotTests/PostHogAnalyticsClientTests.swift b/RiotTests/PostHogAnalyticsClientTests.swift new file mode 100644 index 000000000..081c54688 --- /dev/null +++ b/RiotTests/PostHogAnalyticsClientTests.swift @@ -0,0 +1,113 @@ +// +// Copyright 2024 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import XCTest +@testable import Element +import AnalyticsEvents + +class PostHogAnalyticsClientTests: XCTestCase { + + private var posthogMock: MockPostHog! + + override func setUp() { + posthogMock = MockPostHog() + } + + func testSuperPropertiesAddedToAllCaptured() { + let analyticsClient = PostHogAnalyticsClient(posthogFactory: MockPostHogFactory(mock: posthogMock)) + analyticsClient.start() + + let superProperties = AnalyticsEvent.SuperProperties(appPlatform: .EI, cryptoSDK: .Rust, cryptoSDKVersion: "0.0") + + analyticsClient.updateSuperProperties(superProperties) + // It should be the same for any event + let someEvent = AnalyticsEvent.CallEnded(durationMs: 0, isVideo: false, numParticipants: 1, placed: true) + analyticsClient.capture(someEvent) + + let capturedEvent = posthogMock.capturePropertiesUserPropertiesReceivedArguments + + // All the super properties should have been added + XCTAssertEqual(capturedEvent?.properties?["cryptoSDK"] as? String, AnalyticsEvent.SuperProperties.CryptoSDK.Rust.rawValue) + XCTAssertEqual(capturedEvent?.properties?["appPlatform"] as? String, AnalyticsEvent.SuperProperties.AppPlatform.EI.rawValue) + XCTAssertEqual(capturedEvent?.properties?["cryptoSDKVersion"] as? String, "0.0") + + // Other properties should be there + XCTAssertEqual(capturedEvent?.properties?["isVideo"] as? Bool, false) + + // Should also work for screens + + analyticsClient.screen(AnalyticsEvent.MobileScreen.init(durationMs: 0, screenName: .Home)) + + + let capturedScreen = posthogMock.screenPropertiesReceivedArguments + + + XCTAssertEqual(capturedScreen?.properties?["cryptoSDK"] as? String, AnalyticsEvent.SuperProperties.CryptoSDK.Rust.rawValue) + XCTAssertEqual(capturedScreen?.properties?["appPlatform"] as? String, AnalyticsEvent.SuperProperties.AppPlatform.EI.rawValue) + XCTAssertEqual(capturedScreen?.properties?["cryptoSDKVersion"] as? String, "0.0") + + + XCTAssertEqual(capturedScreen?.screenTitle, AnalyticsEvent.MobileScreen.ScreenName.Home.rawValue) + + + } + + func testSuperPropertiesCanBeUdpated() { + let analyticsClient = PostHogAnalyticsClient(posthogFactory: MockPostHogFactory(mock: posthogMock)) + analyticsClient.start() + + let superProperties = AnalyticsEvent.SuperProperties(appPlatform: .EI, cryptoSDK: .Rust, cryptoSDKVersion: "0.0") + + analyticsClient.updateSuperProperties(superProperties) + // It should be the same for any event + let someEvent = AnalyticsEvent.CallEnded(durationMs: 0, isVideo: false, numParticipants: 1, placed: true) + analyticsClient.capture(someEvent) + + let capturedEvent = posthogMock.capturePropertiesUserPropertiesReceivedArguments + + // + XCTAssertEqual(capturedEvent?.properties?["cryptoSDKVersion"] as? String, "0.0") + + analyticsClient.updateSuperProperties(AnalyticsEvent.SuperProperties(appPlatform: .EI, cryptoSDK: .Rust, cryptoSDKVersion: "1.0")) + + + analyticsClient.capture(someEvent) + + let secondCapturedEvent = posthogMock.capturePropertiesUserPropertiesReceivedArguments + + XCTAssertEqual(secondCapturedEvent?.properties?["cryptoSDKVersion"] as? String, "1.0") + } + + func testSuperPropertiesDontOverrideEventProperties() { + let analyticsClient = PostHogAnalyticsClient(posthogFactory: MockPostHogFactory(mock: posthogMock)) + analyticsClient.start() + + // Super property for cryptoSDK is rust + let superProperties = AnalyticsEvent.SuperProperties(appPlatform: nil, cryptoSDK: .Rust, cryptoSDKVersion: nil) + + analyticsClient.updateSuperProperties(superProperties) + + // This event as a similar named property `cryptoSDK` with Legacy value + let someEvent = AnalyticsEvent.Error(context: nil, cryptoModule: nil, cryptoSDK: .Legacy, domain: .E2EE, eventLocalAgeMillis: nil, isFederated: nil, isMatrixDotOrg: nil, name: .OlmKeysNotSentError, timeToDecryptMillis: nil, userTrustsOwnIdentity: nil, wasVisibleToUser: nil) + + analyticsClient.capture(someEvent) + + let capturedEvent = posthogMock.capturePropertiesUserPropertiesReceivedArguments + + XCTAssertEqual(capturedEvent?.properties?["cryptoSDK"] as? String, AnalyticsEvent.Error.CryptoSDK.Legacy.rawValue) + } + +} diff --git a/project.yml b/project.yml index a666fb1b7..f72c75b5a 100644 --- a/project.yml +++ b/project.yml @@ -45,7 +45,7 @@ include: packages: AnalyticsEvents: url: https://github.com/matrix-org/matrix-analytics-events - exactVersion: 0.15.0 + exactVersion: 0.23.1 Mapbox: url: https://github.com/maplibre/maplibre-gl-native-distribution minVersion: 5.12.2 From 461fed77785f006f66b1f9365fd843c074ae1797 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 3 Jun 2024 10:58:28 +0200 Subject: [PATCH 31/79] Add changelog --- changelog.d/7801.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7801.misc diff --git a/changelog.d/7801.misc b/changelog.d/7801.misc new file mode 100644 index 000000000..5fbecd9d3 --- /dev/null +++ b/changelog.d/7801.misc @@ -0,0 +1 @@ +Analytics | Add support for super properties and appPlatform From 7e9b8d91db125cce46b533872e78b9b0c9a520e1 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 3 Jun 2024 16:09:50 +0200 Subject: [PATCH 32/79] Review: doc fix typo Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> --- Riot/Modules/Analytics/AnalyticsClientProtocol.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Riot/Modules/Analytics/AnalyticsClientProtocol.swift b/Riot/Modules/Analytics/AnalyticsClientProtocol.swift index 1e0acc54e..cfc90fadb 100644 --- a/Riot/Modules/Analytics/AnalyticsClientProtocol.swift +++ b/Riot/Modules/Analytics/AnalyticsClientProtocol.swift @@ -55,7 +55,7 @@ protocol AnalyticsClientProtocol { func updateUserProperties(_ userProperties: AnalyticsEvent.UserProperties) - /// Updates the user properties. + /// Updates the super properties. /// Super properties added to all captured events and screen. /// - Parameter superProperties: The properties event to capture. func updateSuperProperties(_ event: AnalyticsEvent.SuperProperties) From 5c13a0eb76c8cd99ec7f4704c754596fa295b682 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 3 Jun 2024 16:10:09 +0200 Subject: [PATCH 33/79] Review: quick format Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> --- RiotTests/FakeUtils.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/RiotTests/FakeUtils.swift b/RiotTests/FakeUtils.swift index 2f2ad4e63..f4649e9d8 100644 --- a/RiotTests/FakeUtils.swift +++ b/RiotTests/FakeUtils.swift @@ -361,9 +361,7 @@ class MockPostHog: PostHogProtocol { enabled = false } - func reset() { - - } + func reset() { } func flush() { From 54444d8eaba1ff45a409a5c2ea7236dfc7c1c0fc Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 3 Jun 2024 16:10:40 +0200 Subject: [PATCH 34/79] Review: cleaning Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> --- Riot/Modules/Analytics/Analytics.swift | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Riot/Modules/Analytics/Analytics.swift b/Riot/Modules/Analytics/Analytics.swift index f284c2aa4..45a4611a5 100644 --- a/Riot/Modules/Analytics/Analytics.swift +++ b/Riot/Modules/Analytics/Analytics.swift @@ -94,13 +94,9 @@ import AnalyticsEvents guard let session = session else { return } useAnalyticsSettings(from: session) - self.client.updateSuperProperties( - AnalyticsEvent.SuperProperties( - appPlatform: .EI, - cryptoSDK: .Rust, - cryptoSDKVersion: session.crypto.version - ) - ) + client.updateSuperProperties(.init(appPlatform: .EI, + cryptoSDK: .Rust, + cryptoSDKVersion: session.crypto.version)) } /// Stops analytics tracking and calls `reset` to clear any IDs and event queues. From 8cabf8245fbc62c39eb9856d1d61e549839b0f54 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 3 Jun 2024 16:10:51 +0200 Subject: [PATCH 35/79] Review: quick format Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> --- Riot/Modules/Analytics/Analytics.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Riot/Modules/Analytics/Analytics.swift b/Riot/Modules/Analytics/Analytics.swift index 45a4611a5..3b19c9809 100644 --- a/Riot/Modules/Analytics/Analytics.swift +++ b/Riot/Modules/Analytics/Analytics.swift @@ -253,7 +253,8 @@ extension Analytics { ftueUseCaseSelection: ftueUseCase?.analyticsName, numFavouriteRooms: numFavouriteRooms, numSpaces: numSpaces, - recoveryState: nil, verificationState: nil) + recoveryState: nil, + verificationState: nil) client.updateUserProperties(userProperties) } From c1d10f720e1c4b0d82d59047de13f84164aae438 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Mon, 10 Jun 2024 13:35:11 +0300 Subject: [PATCH 36/79] Remove NSFW advanced settings option --- Config/BuildSettings.swift | 1 - Riot/Managers/Settings/RiotSettings.swift | 9 +----- .../Recents/DataSources/RecentsDataSource.m | 1 - .../UnifiedSearchViewController.m | 2 -- .../PublicRoomsDirectoryDataSource.h | 5 ---- .../PublicRoomsDirectoryDataSource.m | 19 +------------ .../Modules/Settings/SettingsViewController.m | 28 ++----------------- 7 files changed, 4 insertions(+), 61 deletions(-) diff --git a/Config/BuildSettings.swift b/Config/BuildSettings.swift index e3e3e55e8..48a4deed8 100644 --- a/Config/BuildSettings.swift +++ b/Config/BuildSettings.swift @@ -297,7 +297,6 @@ final class BuildSettings: NSObject { static let settingsScreenShowChangePassword:Bool = true static let settingsScreenShowEnableStunServerFallback: Bool = true static let settingsScreenShowNotificationDecodedContentOption: Bool = true - static let settingsScreenShowNsfwRoomsOption: Bool = true static let settingsSecurityScreenShowSessions:Bool = true static let settingsSecurityScreenShowSetupBackup:Bool = true static let settingsSecurityScreenShowRestoreBackup:Bool = true diff --git a/Riot/Managers/Settings/RiotSettings.swift b/Riot/Managers/Settings/RiotSettings.swift index 06746801c..4710eba63 100644 --- a/Riot/Managers/Settings/RiotSettings.swift +++ b/Riot/Managers/Settings/RiotSettings.swift @@ -97,10 +97,6 @@ final class RiotSettings: NSObject { @UserDefault(key: UserDefaultsKeys.pinRoomsWithUnreadMessagesOnHome, defaultValue: false, storage: defaults) var pinRoomsWithUnreadMessagesOnHome - /// Indicate to show Not Safe For Work public rooms. - @UserDefault(key: "showNSFWPublicRooms", defaultValue: false, storage: defaults) - var showNSFWPublicRooms - // MARK: User interface @UserDefault(key: "userInterfaceTheme", defaultValue: nil, storage: defaults) @@ -329,10 +325,7 @@ final class RiotSettings: NSObject { @UserDefault(key: "settingsScreenShowNotificationDecodedContentOption", defaultValue: BuildSettings.settingsScreenShowNotificationDecodedContentOption, storage: defaults) var settingsScreenShowNotificationDecodedContentOption - - @UserDefault(key: "settingsScreenShowNsfwRoomsOption", defaultValue: BuildSettings.settingsScreenShowNsfwRoomsOption, storage: defaults) - var settingsScreenShowNsfwRoomsOption - + @UserDefault(key: "settingsSecurityScreenShowSessions", defaultValue: BuildSettings.settingsSecurityScreenShowSessions, storage: defaults) var settingsSecurityScreenShowSessions diff --git a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m index 85393a2d0..edf05bedc 100644 --- a/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m +++ b/Riot/Modules/Common/Recents/DataSources/RecentsDataSource.m @@ -471,7 +471,6 @@ NSString *const kRecentsDataSourceTapOnDirectoryServerChange = @"kRecentsDataSou if (!_publicRoomsDirectoryDataSource) { _publicRoomsDirectoryDataSource = [[PublicRoomsDirectoryDataSource alloc] initWithMatrixSession:mxSession]; - _publicRoomsDirectoryDataSource.showNSFWRooms = RiotSettings.shared.showNSFWPublicRooms; _publicRoomsDirectoryDataSource.delegate = self; } diff --git a/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m b/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m index 8703623bb..94ae50f5a 100644 --- a/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m +++ b/Riot/Modules/GlobalSearch/UnifiedSearchViewController.m @@ -141,8 +141,6 @@ // Reset searches [recentsDataSource searchWithPatterns:nil]; - // TODO: Notify RiotSettings.shared.showNSFWPublicRooms change for iPad as viewWillAppear may not be called - recentsDataSource.publicRoomsDirectoryDataSource.showNSFWRooms = RiotSettings.shared.showNSFWPublicRooms; [self updateSearch]; diff --git a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h index 6fce1d92b..121722ed4 100644 --- a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h +++ b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.h @@ -45,11 +45,6 @@ */ @property (nonatomic) BOOL includeAllNetworks; -/** - Flag to indicate to show Not Safe For Work rooms in the public room list. - */ -@property (nonatomic) BOOL showNSFWRooms; - /** List public rooms from a third party protocol. Default is nil. diff --git a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m index cad856012..257f68d2e 100644 --- a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m +++ b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m @@ -155,16 +155,6 @@ static NSString *const kNSFWKeyword = @"nsfw"; } } -- (void)setShowNSFWRooms:(BOOL)showNSFWRooms -{ - if (showNSFWRooms != _showNSFWRooms) - { - _showNSFWRooms = showNSFWRooms; - - [self resetPagination]; - } -} - - (NSUInteger)roomsCount { return rooms.count; @@ -254,14 +244,7 @@ static NSString *const kNSFWKeyword = @"nsfw"; NSArray *publicRooms; - if (self.showNSFWRooms) - { - publicRooms = publicRoomsResponse.chunk; - } - else - { - publicRooms = [self filterPublicRooms:publicRoomsResponse.chunk containingKeyword:kNSFWKeyword]; - } + publicRooms = [self filterPublicRooms:publicRoomsResponse.chunk containingKeyword:kNSFWKeyword]; [self->rooms addObjectsFromArray:publicRooms]; self->nextBatch = publicRoomsResponse.nextBatch; diff --git a/Riot/Modules/Settings/SettingsViewController.m b/Riot/Modules/Settings/SettingsViewController.m index 39698f765..41372d2e0 100644 --- a/Riot/Modules/Settings/SettingsViewController.m +++ b/Riot/Modules/Settings/SettingsViewController.m @@ -152,8 +152,7 @@ typedef NS_ENUM(NSUInteger, PRESENCE) typedef NS_ENUM(NSUInteger, ADVANCED) { - ADVANCED_SHOW_NSFW_ROOMS_INDEX = 0, - ADVANCED_CRASH_REPORT_INDEX, + ADVANCED_CRASH_REPORT_INDEX = 0, ADVANCED_ENABLE_RAGESHAKE_INDEX, ADVANCED_MARK_ALL_AS_READ_INDEX, ADVANCED_CLEAR_CACHE_INDEX, @@ -567,11 +566,6 @@ SSOAuthenticationPresenterDelegate> Section *sectionAdvanced = [Section sectionWithTag:SECTION_TAG_ADVANCED]; sectionAdvanced.headerTitle = [VectorL10n settingsAdvanced]; - if (RiotSettings.shared.settingsScreenShowNsfwRoomsOption) - { - [sectionAdvanced addRowWithTag:ADVANCED_SHOW_NSFW_ROOMS_INDEX]; - } - if (BuildSettings.settingsScreenAllowChangingCrashUsageDataSettings) { [sectionAdvanced addRowWithTag:ADVANCED_CRASH_REPORT_INDEX]; @@ -2372,20 +2366,7 @@ SSOAuthenticationPresenterDelegate> } else if (section == SECTION_TAG_ADVANCED) { - if (row == ADVANCED_SHOW_NSFW_ROOMS_INDEX) - { - MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; - - labelAndSwitchCell.mxkLabel.text = [VectorL10n settingsShowNSFWPublicRooms]; - - labelAndSwitchCell.mxkSwitch.on = RiotSettings.shared.showNSFWPublicRooms; - labelAndSwitchCell.mxkSwitch.onTintColor = ThemeService.shared.theme.tintColor; - labelAndSwitchCell.mxkSwitch.enabled = YES; - [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleNSFWPublicRoomsFiltering:) forControlEvents:UIControlEventTouchUpInside]; - - cell = labelAndSwitchCell; - } - else if (row == ADVANCED_CRASH_REPORT_INDEX) + if (row == ADVANCED_CRASH_REPORT_INDEX) { MXKTableViewCellWithLabelAndSwitch* sendCrashReportCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; @@ -4082,11 +4063,6 @@ SSOAuthenticationPresenterDelegate> } } -- (void)toggleNSFWPublicRoomsFiltering:(UISwitch *)sender -{ - RiotSettings.shared.showNSFWPublicRooms = sender.isOn; -} - - (void)toggleEnableRoomMessageBubbles:(UISwitch *)sender { RiotSettings.shared.roomScreenEnableMessageBubbles = sender.isOn; From 770b4da16bf5d42ed7dc35e9571480c2923bbe05 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Mon, 10 Jun 2024 14:53:09 +0300 Subject: [PATCH 37/79] Adopt the EXA forbidden terms list when searching for public rooms --- .../PublicRoomsDirectoryDataSource.m | 29 ++++++-- Riot/SupportingFiles/forbidden_terms.txt | 68 +++++++++++++++++++ 2 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 Riot/SupportingFiles/forbidden_terms.txt diff --git a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m index 257f68d2e..5ae737549 100644 --- a/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m +++ b/Riot/Modules/PublicRoomList/DataSources/PublicRoomsDirectoryDataSource.m @@ -46,6 +46,8 @@ static NSString *const kNSFWKeyword = @"nsfw"; NSString *nextBatch; } +@property (nonatomic, strong) NSRegularExpression *forbiddenTermsRegex; + @end @implementation PublicRoomsDirectoryDataSource @@ -57,6 +59,15 @@ static NSString *const kNSFWKeyword = @"nsfw"; { rooms = [NSMutableArray array]; _paginationLimit = 20; + + NSString *path = [[NSBundle mainBundle] pathForResource:@"forbidden_terms" ofType:@"txt"]; + NSString *fileContents = [NSString stringWithContentsOfFile:path encoding: NSUTF8StringEncoding error:nil]; + NSArray *forbiddenTerms = [fileContents componentsSeparatedByCharactersInSet: NSCharacterSet.whitespaceAndNewlineCharacterSet]; + + NSString *pattern = [NSString stringWithFormat:@"\\b(%@)\\b", [forbiddenTerms componentsJoinedByString:@"|"]]; + pattern = [pattern stringByAppendingString:@"|(\\b18\\+)"]; // Special case "18+" + + _forbiddenTermsRegex = [[NSRegularExpression alloc] initWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:nil]; } return self; } @@ -244,7 +255,7 @@ static NSString *const kNSFWKeyword = @"nsfw"; NSArray *publicRooms; - publicRooms = [self filterPublicRooms:publicRoomsResponse.chunk containingKeyword:kNSFWKeyword]; + publicRooms = [self filterPublicRooms:publicRoomsResponse.chunk]; [self->rooms addObjectsFromArray:publicRooms]; self->nextBatch = publicRoomsResponse.nextBatch; @@ -321,15 +332,23 @@ static NSString *const kNSFWKeyword = @"nsfw"; } } -- (NSArray*)filterPublicRooms:(NSArray*)publicRooms containingKeyword:(NSString*)keyword +- (NSArray*)filterPublicRooms:(NSArray*)publicRooms { NSMutableArray *filteredRooms = [NSMutableArray new]; for (MXPublicRoom *publicRoom in publicRooms) { - if (NO == [[publicRoom.name lowercaseString] containsString:keyword] - && NO == [[publicRoom.topic lowercaseString] containsString:keyword]) - { + BOOL shouldAllow = YES; + + if (publicRoom.name != nil) { + shouldAllow &= [self.forbiddenTermsRegex numberOfMatchesInString:publicRoom.name options:0 range:NSMakeRange(0, publicRoom.name.length)] == 0; + } + + if (publicRoom.topic != nil) { + shouldAllow &= [self.forbiddenTermsRegex numberOfMatchesInString:publicRoom.topic options:0 range:NSMakeRange(0, publicRoom.topic.length)] == 0; + } + + if (shouldAllow) { [filteredRooms addObject:publicRoom]; } } diff --git a/Riot/SupportingFiles/forbidden_terms.txt b/Riot/SupportingFiles/forbidden_terms.txt new file mode 100644 index 000000000..ff22aa40f --- /dev/null +++ b/Riot/SupportingFiles/forbidden_terms.txt @@ -0,0 +1,68 @@ +anal +bbw +bdsm +beast +bestiality +blowjob +bondage +boobs +clit +cock +cuck +cum +cunt +daddy +dick +dildo +erotic +exhibitionism +faggot +femboy +fisting +flogging +fmf +foursome +futa +gangbang +gore +h3ntai +handjob +hentai +incest +jizz +kink +loli +m4f +masturbate +masturbation +mfm +milf +moresome +naked +neet +nsfw +nude +nudity +orgy +pedo +pegging +penis +petplay +porn +pussy +rape +rimming +sadism +sadomasochism +sexy +shota +spank +squirt +strap-on +threesome +vagina +vibrator +voyeur +watersports +xxx +zoo \ No newline at end of file From 39d0109c8df9438b17ca96c53a05138aa8a9c06e Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Mon, 10 Jun 2024 15:18:16 +0300 Subject: [PATCH 38/79] Make the `matrix-ios-sdk` a submodule and use it as a local pod instead of a published one. --- .github/workflows/ci-build.yml | 6 +-- .github/workflows/ci-tests.yml | 6 +-- .github/workflows/ci-ui-tests.yml | 6 +-- .github/workflows/release-alpha.yml | 6 +-- .gitmodules | 3 ++ Gemfile.lock | 58 +++++++++++++++-------------- Podfile | 38 +------------------ Podfile.lock | 11 ++++-- matrix-ios-sdk | 1 + 9 files changed, 55 insertions(+), 80 deletions(-) create mode 100644 .gitmodules create mode 160000 matrix-ios-sdk diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 6cac438d5..ccb11123a 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -20,7 +20,9 @@ jobs: # Concurrency group not needed as this workflow only runs on develop which we always want to test. steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + with: + submodules: 'true' # Common cache # Note: GH actions do not support yaml anchor yet. We need to duplicate this for every job @@ -49,8 +51,6 @@ jobs: run: | bundle config path vendor/bundle bundle install --jobs 4 --retry 3 - - name: Use right MatrixSDK versions - run: bundle exec fastlane point_dependencies_to_related_branches # Main step - name: Build iOS simulator diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index f78a5aba9..e71d7b99b 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -25,7 +25,9 @@ jobs: cancel-in-progress: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + with: + submodules: 'true' # Common cache # Note: GH actions do not support yaml anchor yet. We need to duplicate this for every job @@ -54,8 +56,6 @@ jobs: run: | bundle config path vendor/bundle bundle install --jobs 4 --retry 3 - - name: Use right MatrixSDK versions - run: bundle exec fastlane point_dependencies_to_related_branches # Main step - name: Unit tests diff --git a/.github/workflows/ci-ui-tests.yml b/.github/workflows/ci-ui-tests.yml index b13272947..322323739 100644 --- a/.github/workflows/ci-ui-tests.yml +++ b/.github/workflows/ci-ui-tests.yml @@ -20,7 +20,9 @@ jobs: cancel-in-progress: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + with: + submodules: 'true' # Common cache # Note: GH actions do not support yaml anchor yet. We need to duplicate this for every job @@ -49,8 +51,6 @@ jobs: run: | bundle config path vendor/bundle bundle install --jobs 4 --retry 3 - - name: Use right MatrixSDK versions - run: bundle exec fastlane point_dependencies_to_related_branches # Main step - name: UI tests diff --git a/.github/workflows/release-alpha.yml b/.github/workflows/release-alpha.yml index e610628b4..aa90ef5ba 100644 --- a/.github/workflows/release-alpha.yml +++ b/.github/workflows/release-alpha.yml @@ -25,7 +25,9 @@ jobs: cancel-in-progress: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 + with: + submodules: 'true' # Common cache # Note: GH actions do not support yaml anchor yet. We need to duplicate this for every job @@ -57,8 +59,6 @@ jobs: run: | bundle config path vendor/bundle bundle install --jobs 4 --retry 3 - - name: Use right MatrixSDK versions - run: bundle exec fastlane point_dependencies_to_related_branches # Import alpha release private signing certificate - name: Import signing certificate diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..90f7f83cb --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "matrix-ios-sdk"] + path = matrix-ios-sdk + url = git@github.com:matrix-org/matrix-ios-sdk.git diff --git a/Gemfile.lock b/Gemfile.lock index 519e1f087..bacf716b3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -11,7 +11,7 @@ GEM base64 nkf rexml - activesupport (7.1.3.2) + activesupport (7.1.3.4) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -29,24 +29,24 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.899.0) - aws-sdk-core (3.191.4) + aws-partitions (1.941.0) + aws-sdk-core (3.197.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.78.0) - aws-sdk-core (~> 3, >= 3.191.0) + aws-sdk-kms (1.83.0) + aws-sdk-core (~> 3, >= 3.197.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.146.0) - aws-sdk-core (~> 3, >= 3.191.0) + aws-sdk-s3 (1.152.0) + aws-sdk-core (~> 3, >= 3.197.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) aws-sigv4 (1.8.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) base64 (0.2.0) - bigdecimal (3.1.7) + bigdecimal (3.1.8) claide (1.1.0) clamp (1.3.2) cocoapods (1.14.3) @@ -90,7 +90,7 @@ GEM colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.3) connection_pool (2.4.1) declarative (0.0.20) digest-crc (0.6.5) @@ -131,15 +131,15 @@ GEM faraday-retry (1.0.3) faraday_middleware (1.2.0) faraday (~> 1.0) - fastimage (2.3.0) - fastlane (2.219.0) + fastimage (2.3.1) + fastlane (2.220.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) aws-sdk-s3 (~> 1.0) babosa (>= 1.0.3, < 2.0.0) bundler (>= 1.12.0, < 3.0.0) - colored + colored (~> 1.2) commander (~> 4.6) dotenv (>= 2.1.1, < 3.0.0) emoji_regex (>= 0.1, < 4.0) @@ -160,10 +160,10 @@ GEM mini_magick (>= 4.9.4, < 5.0.0) multipart-post (>= 2.0.0, < 3.0.0) naturally (~> 2.2) - optparse (>= 0.1.1) + optparse (>= 0.1.1, < 1.0.0) plist (>= 3.1.0, < 4.0.0) rubyzip (>= 2.0.0, < 3.0.0) - security (= 0.1.3) + security (= 0.1.5) simctl (~> 1.6.3) terminal-notifier (>= 2.0.0, < 3.0.0) terminal-table (~> 3) @@ -172,14 +172,14 @@ GEM word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) - xcpretty-travis-formatter (>= 0.0.3) + xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) fastlane-plugin-brew (0.1.1) - fastlane-plugin-sentry (1.20.0) + fastlane-plugin-sentry (1.23.0) os (~> 1.1, >= 1.1.4) fastlane-plugin-versioning (0.5.2) fastlane-plugin-xcodegen (1.1.0) fastlane-plugin-brew (~> 0.1.1) - ffi (1.16.3) + ffi (1.17.0) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) @@ -220,22 +220,22 @@ GEM os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.5) + http-cookie (1.0.6) domain_name (~> 0.5) httpclient (2.8.3) - i18n (1.14.4) + i18n (1.14.5) concurrent-ruby (~> 1.0) jmespath (1.6.2) - json (2.7.1) + json (2.7.2) jwt (2.8.1) base64 mini_magick (4.12.0) mini_mime (1.1.5) - mini_portile2 (2.8.5) - minitest (5.22.3) + mini_portile2 (2.8.7) + minitest (5.23.1) molinillo (0.8.0) multi_json (1.15.0) - multipart-post (2.4.0) + multipart-post (2.4.1) mutex_m (0.2.0) nanaimo (0.3.0) nap (1.1.0) @@ -245,23 +245,24 @@ GEM nokogiri (1.15.6) mini_portile2 (~> 2.8.2) racc (~> 1.4) - optparse (0.4.0) + optparse (0.5.0) os (1.1.4) plist (3.7.1) public_suffix (4.0.7) - racc (1.7.3) - rake (13.1.0) + racc (1.8.0) + rake (13.2.1) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.6) + rexml (3.2.9) + strscan rouge (2.0.7) ruby-macho (2.5.1) ruby2_keywords (0.0.5) rubyzip (2.3.2) - security (0.1.3) + security (0.1.5) signet (0.19.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) @@ -276,6 +277,7 @@ GEM clamp (~> 1.3) nokogiri (>= 1.14.3) xcodeproj (~> 1.21) + strscan (3.1.0) terminal-notifier (2.0.0) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) diff --git a/Podfile b/Podfile index 3fb43f417..f6f26f61c 100644 --- a/Podfile +++ b/Podfile @@ -9,44 +9,10 @@ inhibit_all_warnings! # Use frameworks to allow usage of pods written in Swift use_frameworks! -# Different flavours of pods to MatrixSDK. Can be one of: -# - a String indicating an official MatrixSDK released version number -# - `:local` (to use Development Pods) -# - `{ :branch => 'sdk branch name'}` to depend on specific branch of MatrixSDK repo -# - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI -# -# Warning: our internal tooling depends on the name of this variable name, so be sure not to change it -$matrixSDKVersion = '= 0.27.8' -# $matrixSDKVersion = :local -# $matrixSDKVersion = { :branch => 'develop'} -# $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } } - -######################################## - -case $matrixSDKVersion -when :local -$matrixSDKVersionSpec = { :path => '../matrix-ios-sdk/MatrixSDK.podspec' } -when Hash -spec_mode, sdk_spec = $matrixSDKVersion.first # extract first and only key/value pair; key is spec_mode, value is sdk_spec - - case spec_mode - when :branch - # :branch => sdk branch name - sdk_spec = { :git => 'https://github.com/matrix-org/matrix-ios-sdk.git', :branch => sdk_spec.to_s } unless sdk_spec.is_a?(Hash) - when :specHash - # :specHash => {sdk spec Hash} - sdk_spec = sdk_spec - end - -$matrixSDKVersionSpec = sdk_spec -when String # specific MatrixSDK released version -$matrixSDKVersionSpec = $matrixSDKVersion -end - # Method to import the MatrixSDK def import_MatrixSDK - pod 'MatrixSDK', $matrixSDKVersionSpec, :inhibit_warnings => false - pod 'MatrixSDK/JingleCallStack', $matrixSDKVersionSpec, :inhibit_warnings => false + pod 'MatrixSDK', :path => 'matrix-ios-sdk/MatrixSDK.podspec', :inhibit_warnings => false + pod 'MatrixSDK/JingleCallStack', :path => 'matrix-ios-sdk/MatrixSDK.podspec', :inhibit_warnings => false end ######################################## diff --git a/Podfile.lock b/Podfile.lock index b830adadb..673d4ecc0 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -101,8 +101,8 @@ DEPENDENCIES: - KeychainAccess (~> 4.2.2) - KTCenterFlowLayout (~> 1.3.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.27.8) - - MatrixSDK/JingleCallStack (= 0.27.8) + - MatrixSDK (from `matrix-ios-sdk/MatrixSDK.podspec`) + - MatrixSDK/JingleCallStack (from `matrix-ios-sdk/MatrixSDK.podspec`) - OLMKit - ReadMoreTextView (~> 3.0.1) - Reusable (~> 4.1) @@ -142,7 +142,6 @@ SPEC REPOS: - libPhoneNumber-iOS - LoggerAPI - Logging - - MatrixSDK - MatrixSDKCrypto - OLMKit - ReadMoreTextView @@ -162,6 +161,10 @@ SPEC REPOS: - zxcvbn-ios - ZXingObjC +EXTERNAL SOURCES: + MatrixSDK: + :path: matrix-ios-sdk/MatrixSDK.podspec + SPEC CHECKSUMS: AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58 BlueCryptor: b0aee3d9b8f367b49b30de11cda90e1735571c24 @@ -204,6 +207,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: 3bbda8faf037705f421dad839d6f5b1aef399f99 +PODFILE CHECKSUM: b622ffadc1a0fe5442787bd9023ca3d110384814 COCOAPODS: 1.15.2 diff --git a/matrix-ios-sdk b/matrix-ios-sdk new file mode 160000 index 000000000..f03778fdd --- /dev/null +++ b/matrix-ios-sdk @@ -0,0 +1 @@ +Subproject commit f03778fddbaf682173706649ee1412b0143f0449 From 87577f569242c2cd1adec863e6eca9396502380a Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 12 Jun 2024 12:43:25 +0300 Subject: [PATCH 39/79] Add support for reporting rooms on the room preview screen --- Riot/Modules/Room/RoomViewController.m | 48 ++++++++++++++ .../Title/Preview/PreviewRoomTitleView.h | 1 + .../Title/Preview/PreviewRoomTitleView.m | 12 ++++ .../Title/Preview/PreviewRoomTitleView.xib | 64 +++++++++++-------- matrix-ios-sdk | 2 +- 5 files changed, 101 insertions(+), 26 deletions(-) diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index 37cc5a766..b511bade2 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -5372,6 +5372,50 @@ static CGSize kThreadListBarButtonItemImageSize; } } +- (void)handleReportRoomButtonPress +{ + // Prompt user to enter a description of the problem content. + UIAlertController *reportReasonAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomEventActionReportPromptReason] + message:nil + preferredStyle:UIAlertControllerStyleAlert]; + + [reportReasonAlert addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.secureTextEntry = NO; + textField.placeholder = nil; + textField.keyboardType = UIKeyboardTypeDefault; + }]; + + MXWeakify(self); + [reportReasonAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n ok] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + MXStrongifyAndReturnIfNil(self); + + NSString *text = [self->currentAlert textFields].firstObject.text; + self->currentAlert = nil; + + [self startActivityIndicator]; + + [self.roomDataSource.mxSession.matrixRestClient reportRoom:self.roomDataSource.roomId reason:text success:^{ + MXStrongifyAndReturnIfNil(self); + [self stopActivityIndicator]; + } failure:^(NSError *error) { + MXStrongifyAndReturnIfNil(self); + [self stopActivityIndicator]; + + MXLogDebug(@"[RoomVC] Report room (%@) failed", self.roomDataSource.roomId); + //Alert user + [self showError:error]; + }]; + }]]; + + [reportReasonAlert addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel] style:UIAlertActionStyleCancel handler:^(UIAlertAction * action) { + MXStrongifyAndReturnIfNil(self); + self->currentAlert = nil; + }]]; + + [self presentViewController:reportReasonAlert animated:YES completion:nil]; + self->currentAlert = reportReasonAlert; +} + #pragma mark - UITableViewDelegate - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath @@ -5617,6 +5661,10 @@ static CGSize kThreadListBarButtonItemImageSize; { [self presentDeclineOptionsFromView:tappedView]; } + else if (tappedView == previewHeader.reportButton) + { + [self handleReportRoomButtonPress]; + } } - (void)presentDeclineOptionsFromView:(UIView *)view diff --git a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.h b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.h index 79fdde1bb..d8bcfb086 100644 --- a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.h +++ b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.h @@ -32,6 +32,7 @@ @property (weak, nonatomic) IBOutlet UIView *buttonsContainer; @property (weak, nonatomic) IBOutlet UIButton *leftButton; @property (weak, nonatomic) IBOutlet UIButton *rightButton; +@property (weak, nonatomic) IBOutlet UIButton *reportButton; @property (weak, nonatomic) IBOutlet UILabel *subNoticeLabel; @property (weak, nonatomic) IBOutlet UIView *bottomBorderView; diff --git a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m index 7e8456a5b..48b7d1abf 100644 --- a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m +++ b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m @@ -51,12 +51,22 @@ [self.rightButton setTitle:[VectorL10n join] forState:UIControlStateNormal]; [self.rightButton setTitle:[VectorL10n join] forState:UIControlStateHighlighted]; + [self.reportButton setTitle:[VectorL10n roomEventActionReport] forState:UIControlStateNormal]; + [self.reportButton setTitle:[VectorL10n roomEventActionReport] forState:UIControlStateHighlighted]; + tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reportTapGesture:)]; [tap setNumberOfTouchesRequired:1]; [tap setNumberOfTapsRequired:1]; [tap setDelegate:self]; [self.rightButton addGestureRecognizer:tap]; self.rightButton.userInteractionEnabled = YES; + + tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reportTapGesture:)]; + [tap setNumberOfTouchesRequired:1]; + [tap setNumberOfTapsRequired:1]; + [tap setDelegate:self]; + [self.reportButton addGestureRecognizer:tap]; + self.reportButton.userInteractionEnabled = YES; } -(void)customizeViewRendering @@ -86,6 +96,8 @@ [self.rightButton.layer setCornerRadius:5]; self.rightButton.clipsToBounds = YES; self.rightButton.backgroundColor = ThemeService.shared.theme.tintColor; + + [self.reportButton setTitleColor:ThemeService.shared.theme.warningColor forState:UIControlStateNormal]; } - (void)refreshDisplay diff --git a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.xib b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.xib index 31fcca273..873ff88e2 100644 --- a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.xib +++ b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.xib @@ -1,25 +1,21 @@ - - - - + + - - - + - + - + @@ -38,7 +34,7 @@ - + @@ -48,9 +44,9 @@ - + - + @@ -58,11 +54,11 @@ - + - - - + @@ -154,15 +158,17 @@ - + + + @@ -187,6 +193,7 @@ + @@ -194,9 +201,16 @@ + - + + + + + + + diff --git a/matrix-ios-sdk b/matrix-ios-sdk index f03778fdd..eea06ab5f 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit f03778fddbaf682173706649ee1412b0143f0449 +Subproject commit eea06ab5f2b68223f557abaf04674df7f952ede8 From b691d02a20914e157be489281c935e92da4c2d48 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 12 Jun 2024 17:43:35 +0300 Subject: [PATCH 40/79] Add support for reporting rooms on the room details screen too --- Riot/Assets/en.lproj/Vector.strings | 2 ++ Riot/Generated/Strings.swift | 8 ++++++++ Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift | 3 +++ .../RoomInfo/RoomInfoCoordinatorBridgePresenter.swift | 6 ++++++ .../Room/RoomInfo/RoomInfoCoordinatorType.swift | 1 + .../RoomInfoList/RoomInfoListCoordinator.swift | 3 +++ .../RoomInfoList/RoomInfoListCoordinatorType.swift | 1 + .../RoomInfoList/RoomInfoListViewAction.swift | 1 + .../RoomInfoList/RoomInfoListViewController.swift | 8 ++++++++ .../RoomInfo/RoomInfoList/RoomInfoListViewModel.swift | 2 ++ .../RoomInfoList/RoomInfoListViewModelType.swift | 1 + Riot/Modules/Room/RoomViewController.m | 11 ++++++++--- .../Room/Views/Title/Preview/PreviewRoomTitleView.m | 4 ++-- .../Spaces/SpaceRoomList/ExploreRoomCoordinator.swift | 4 ++++ matrix-ios-sdk | 2 +- 15 files changed, 51 insertions(+), 6 deletions(-) diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 924bda31c..00fc9a6d1 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -592,6 +592,8 @@ Tap the + to start adding people."; "room_action_send_sticker" = "Send sticker"; "room_action_send_file" = "Send file"; "room_action_reply" = "Reply"; +"room_action_report" = "Report room"; +"room_action_report_prompt_reason" = "Reason for reporting this room"; "room_replacement_information" = "This room has been replaced and is no longer active."; "room_replacement_link" = "The conversation continues here."; "room_predecessor_information" = "This room is a continuation of another conversation."; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 999f821c3..7826653b2 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -5207,6 +5207,14 @@ public class VectorL10n: NSObject { public static var roomActionReply: String { return VectorL10n.tr("Vector", "room_action_reply") } + /// Report room + public static var roomActionReport: String { + return VectorL10n.tr("Vector", "room_action_report") + } + /// Reason for reporting this room + public static var roomActionReportPromptReason: String { + return VectorL10n.tr("Vector", "room_action_report_prompt_reason") + } /// Send file public static var roomActionSendFile: String { return VectorL10n.tr("Vector", "room_action_send_file") diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift index badc66490..ea2853c62 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinator.swift @@ -224,6 +224,9 @@ extension RoomInfoCoordinator: RoomInfoListCoordinatorDelegate { self.delegate?.roomInfoCoordinatorDidLeaveRoom(self) } + func roomInfoListCoordinatorDidRequestReportRoom(_ coordinator: RoomInfoListCoordinatorType) { + self.delegate?.roomInfoCoordinatorDidRequestReportRoom(self) + } } extension RoomInfoCoordinator: RoomParticipantsViewControllerDelegate { diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorBridgePresenter.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorBridgePresenter.swift index 39e740bfc..4484bd0d6 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorBridgePresenter.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorBridgePresenter.swift @@ -25,6 +25,7 @@ import MatrixSDK func roomInfoCoordinatorBridgePresenterDelegateDidLeaveRoom(_ coordinatorBridgePresenter: RoomInfoCoordinatorBridgePresenter) func roomInfoCoordinatorBridgePresenter(_ coordinatorBridgePresenter: RoomInfoCoordinatorBridgePresenter, didReplaceRoomWithReplacementId roomId: String) func roomInfoCoordinatorBridgePresenter(_ coordinator: RoomInfoCoordinatorBridgePresenter, viewEventInTimeline event: MXEvent) + func roomInfoCoordinatorBridgePresenterDidRequestReportRoom(_ coordinatorBridgePresenter: RoomInfoCoordinatorBridgePresenter) } /// RoomInfoCoordinatorBridgePresenter enables to start RoomInfoCoordinator from a view controller. @@ -131,9 +132,14 @@ extension RoomInfoCoordinatorBridgePresenter: RoomInfoCoordinatorDelegate { func roomInfoCoordinator(_ coordinator: RoomInfoCoordinatorType, didReplaceRoomWithReplacementId roomId: String) { self.delegate?.roomInfoCoordinatorBridgePresenter(self, didReplaceRoomWithReplacementId: roomId) } + func roomInfoCoordinator(_ coordinator: RoomInfoCoordinatorType, viewEventInTimeline event: MXEvent) { self.delegate?.roomInfoCoordinatorBridgePresenter(self, viewEventInTimeline: event) } + + func roomInfoCoordinatorDidRequestReportRoom(_ coordinator: RoomInfoCoordinatorType) { + self.delegate?.roomInfoCoordinatorBridgePresenterDidRequestReportRoom(self) + } } // MARK: - UIAdaptivePresentationControllerDelegate diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorType.swift b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorType.swift index 2122ddf1d..077ef7b52 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorType.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoCoordinatorType.swift @@ -25,6 +25,7 @@ protocol RoomInfoCoordinatorDelegate: AnyObject { func roomInfoCoordinatorDidLeaveRoom(_ coordinator: RoomInfoCoordinatorType) func roomInfoCoordinator(_ coordinator: RoomInfoCoordinatorType, didReplaceRoomWithReplacementId roomId: String) func roomInfoCoordinator(_ coordinator: RoomInfoCoordinatorType, viewEventInTimeline event: MXEvent) + func roomInfoCoordinatorDidRequestReportRoom(_ coordinator: RoomInfoCoordinatorType) } /// `RoomInfoCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow. diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinator.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinator.swift index 6da79ca32..25131222b 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinator.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinator.swift @@ -75,4 +75,7 @@ extension RoomInfoListCoordinator: RoomInfoListViewModelCoordinatorDelegate { self.delegate?.roomInfoListCoordinatorDidLeaveRoom(self) } + func roomInfoListViewModelDidRequestReportRoom(_ viewModel: RoomInfoListViewModelType) { + self.delegate?.roomInfoListCoordinatorDidRequestReportRoom(self) + } } diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinatorType.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinatorType.swift index 592acd67b..f17102c1e 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinatorType.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListCoordinatorType.swift @@ -22,6 +22,7 @@ protocol RoomInfoListCoordinatorDelegate: AnyObject { func roomInfoListCoordinator(_ coordinator: RoomInfoListCoordinatorType, wantsToNavigateTo target: RoomInfoListTarget) func roomInfoListCoordinatorDidCancel(_ coordinator: RoomInfoListCoordinatorType) func roomInfoListCoordinatorDidLeaveRoom(_ coordinator: RoomInfoListCoordinatorType) + func roomInfoListCoordinatorDidRequestReportRoom(_ coordinator: RoomInfoListCoordinatorType) } /// `RoomInfoListCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow. diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift index 6383d4fb5..e01bfeefc 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewAction.swift @@ -48,4 +48,5 @@ enum RoomInfoListViewAction { case navigate(target: RoomInfoListTarget) case leave case cancel + case report } diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift index a879eeed0..383beac30 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewController.swift @@ -222,8 +222,16 @@ final class RoomInfoListViewController: UIViewController { rows: [rowLeave], footer: nil) + let rowReport = Row(type: .destructive, icon: Asset.Images.error.image, text: VectorL10n.roomEventActionReport, accessoryType: .disclosureIndicator) { + self.viewModel.process(viewAction: .report) + } + let sectionReport = Section(header: nil, + rows: [rowReport], + footer: nil) + tmpSections.append(sectionSettings) tmpSections.append(sectionLeave) + tmpSections.append(sectionReport) sections = tmpSections } diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift index 572754251..bf2c82e9b 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModel.swift @@ -79,6 +79,8 @@ final class RoomInfoListViewModel: NSObject, RoomInfoListViewModelType { self.leave() case .cancel: self.coordinatorDelegate?.roomInfoListViewModelDidCancel(self) + case .report: + self.coordinatorDelegate?.roomInfoListViewModelDidRequestReportRoom(self) } } diff --git a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift index 8a5a1b411..460c33d51 100644 --- a/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift +++ b/Riot/Modules/Room/RoomInfo/RoomInfoList/RoomInfoListViewModelType.swift @@ -26,6 +26,7 @@ protocol RoomInfoListViewModelCoordinatorDelegate: AnyObject { func roomInfoListViewModelDidCancel(_ viewModel: RoomInfoListViewModelType) func roomInfoListViewModelDidLeaveRoom(_ viewModel: RoomInfoListViewModelType) func roomInfoListViewModel(_ viewModel: RoomInfoListViewModelType, wantsToNavigateTo target: RoomInfoListTarget) + func roomInfoListViewModelDidRequestReportRoom(_ viewModel: RoomInfoListViewModelType) } /// Protocol describing the view model used by `RoomInfoListViewController` diff --git a/Riot/Modules/Room/RoomViewController.m b/Riot/Modules/Room/RoomViewController.m index b511bade2..2eec3ea3d 100644 --- a/Riot/Modules/Room/RoomViewController.m +++ b/Riot/Modules/Room/RoomViewController.m @@ -5372,10 +5372,10 @@ static CGSize kThreadListBarButtonItemImageSize; } } -- (void)handleReportRoomButtonPress +- (void)handleReportRoom { // Prompt user to enter a description of the problem content. - UIAlertController *reportReasonAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomEventActionReportPromptReason] + UIAlertController *reportReasonAlert = [UIAlertController alertControllerWithTitle:[VectorL10n roomActionReportPromptReason] message:nil preferredStyle:UIAlertControllerStyleAlert]; @@ -5663,7 +5663,7 @@ static CGSize kThreadListBarButtonItemImageSize; } else if (tappedView == previewHeader.reportButton) { - [self handleReportRoomButtonPress]; + [self handleReportRoom]; } } @@ -8032,6 +8032,11 @@ static CGSize kThreadListBarButtonItemImageSize; [self reloadRoomWihtEventId:event.eventId threadId:event.threadId forceUpdateRoomMarker:NO]; } +- (void)roomInfoCoordinatorBridgePresenterDidRequestReportRoom:(RoomInfoCoordinatorBridgePresenter *)coordinatorBridgePresenter +{ + [self handleReportRoom]; +} + -(void)reloadRoomWihtEventId:(NSString *)eventId threadId:(NSString *)threadId forceUpdateRoomMarker:(BOOL)forceUpdateRoomMarker diff --git a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m index 48b7d1abf..35fdbab12 100644 --- a/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m +++ b/Riot/Modules/Room/Views/Title/Preview/PreviewRoomTitleView.m @@ -51,8 +51,8 @@ [self.rightButton setTitle:[VectorL10n join] forState:UIControlStateNormal]; [self.rightButton setTitle:[VectorL10n join] forState:UIControlStateHighlighted]; - [self.reportButton setTitle:[VectorL10n roomEventActionReport] forState:UIControlStateNormal]; - [self.reportButton setTitle:[VectorL10n roomEventActionReport] forState:UIControlStateHighlighted]; + [self.reportButton setTitle:[VectorL10n roomActionReport] forState:UIControlStateNormal]; + [self.reportButton setTitle:[VectorL10n roomActionReport] forState:UIControlStateHighlighted]; tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reportTapGesture:)]; [tap setNumberOfTouchesRequired:1]; diff --git a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift index d445f29af..86e1cd5ee 100644 --- a/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift +++ b/Riot/Modules/Spaces/SpaceRoomList/ExploreRoomCoordinator.swift @@ -520,8 +520,12 @@ extension ExploreRoomCoordinator: RoomInfoCoordinatorDelegate { self.remove(childCoordinator: coordinator) } } + func roomInfoCoordinator(_ coordinator: RoomInfoCoordinatorType, viewEventInTimeline event: MXEvent) { } + func roomInfoCoordinatorDidRequestReportRoom(_ coordinator: RoomInfoCoordinatorType) { + + } } diff --git a/matrix-ios-sdk b/matrix-ios-sdk index eea06ab5f..3052a396b 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit eea06ab5f2b68223f557abaf04674df7f952ede8 +Subproject commit 3052a396b88095cbcfe1b4f488127f69e3280cda From b252e024581a235ea15cba1167a78e0e82090285 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Wed, 12 Jun 2024 18:36:35 +0300 Subject: [PATCH 41/79] version++ --- CHANGES.md | 7 +++++++ changelog.d/7801.misc | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) delete mode 100644 changelog.d/7801.misc diff --git a/CHANGES.md b/CHANGES.md index bf6fc003b..27abf6350 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,10 @@ +## Changes in 1.11.13 (2024-06-12) + +Others + +- Analytics | Add support for super properties and appPlatform ([#7801](https://github.com/element-hq/element-ios/issues/7801)) + + ## Changes in 1.11.12 (2024-05-30) 🐛 Bugfixes diff --git a/changelog.d/7801.misc b/changelog.d/7801.misc deleted file mode 100644 index 5fbecd9d3..000000000 --- a/changelog.d/7801.misc +++ /dev/null @@ -1 +0,0 @@ -Analytics | Add support for super properties and appPlatform From 5db3eabb882f1521cdbc988a38293e173a7b4ee4 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Thu, 13 Jun 2024 08:33:18 +0300 Subject: [PATCH 42/79] finish version++ From 71b37368d00d43fb03c09b84a8cb9271708dab5a Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Thu, 13 Jun 2024 08:33:26 +0300 Subject: [PATCH 43/79] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index 281e714ad..e53ee7842 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.13 -CURRENT_PROJECT_VERSION = 1.11.13 +MARKETING_VERSION = 1.11.14 +CURRENT_PROJECT_VERSION = 1.11.14 From fd6a2e381eeb742fd9edac25889019b97bb2ef90 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Thu, 13 Jun 2024 09:25:07 +0300 Subject: [PATCH 44/79] Fix the release script after making the SDK a submodule --- Tools/Release/buildRelease.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Tools/Release/buildRelease.sh b/Tools/Release/buildRelease.sh index 583b00b62..0f925efc1 100755 --- a/Tools/Release/buildRelease.sh +++ b/Tools/Release/buildRelease.sh @@ -42,7 +42,7 @@ cp -R ../../../.. /tmp/$REPO_NAME mv /tmp/$REPO_NAME . else echo "Git clone $REPO_URL with branch/tag $TAG..." -git clone $REPO_URL --depth=1 --branch $TAG +git clone --recursive $REPO_URL --depth=1 --branch $TAG fi cd $REPO_NAME @@ -55,11 +55,6 @@ bundle update # Update fastlane plugins bundle exec fastlane update_plugins -# Use appropriated dependencies according to the current branch -if [ "$LOCAL_SOURCE" != true ]; then -bundle exec fastlane point_dependencies_to_same_feature -fi - # Build bundle exec fastlane app_store build_number:$BUILD_NUMBER git_tag:$TAG From b880ae5496e159bfdbea384442cd369b72deafa9 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 14 Jun 2024 15:18:57 +0200 Subject: [PATCH 45/79] added functions to remove messages --- Riot/Categories/MXRoomSummary.swift | 57 +++++++++++++++++++++++++++++ Riot/Categories/MXSession.swift | 15 ++++++++ Riot/Utils/Tools.h | 13 +++++++ Riot/Utils/Tools.m | 12 ++++++ 4 files changed, 97 insertions(+) create mode 100644 Riot/Categories/MXRoomSummary.swift diff --git a/Riot/Categories/MXRoomSummary.swift b/Riot/Categories/MXRoomSummary.swift new file mode 100644 index 000000000..691f534d0 --- /dev/null +++ b/Riot/Categories/MXRoomSummary.swift @@ -0,0 +1,57 @@ +// +// Copyright 2024 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +extension Notification.Name { + static let roomSummaryDidRemoveExpiredDataFromStore = Notification.Name(MXRoomSummary.roomSummaryDidRemoveExpiredDataFromStore) +} + +@objc extension MXRoomSummary { + static let roomSummaryDidRemoveExpiredDataFromStore = "roomSummaryDidRemoveExpiredDataFromStore" + + private enum Constants { + static let roomRetentionInDaysKey = "roomRetentionInDays" + } + /// Get the room messages retention period in days + func roomRetentionPeriodInDays() -> uint { + if let period = self.others[Constants.roomRetentionInDaysKey] as? uint { + return period + } else { + return 365 + } + } + + /// Get the timestamp below which the received messages must be removed from the store, and the display + func mininumTimestamp() -> UInt64 { + let periodInMs = Tools.durationInMs(fromDays: self.roomRetentionPeriodInDays()) + let currentTs = (UInt64)(Date().timeIntervalSince1970 * 1000) + return (currentTs - periodInMs) + } + + /// Remove the expired messages from the store. + /// If some data are removed, this operation posts the notification: roomSummaryDidRemoveExpiredDataFromStore. + /// This operation does not commit the potential change. We let the caller trigger the commit when this is the more suitable. + /// + /// Provide a boolean telling whether some data have been removed. + func removeExpiredRoomContentsFromStore() -> Bool { + let ret = self.mxSession.store.removeAllMessagesSent(before: self.mininumTimestamp(), inRoom: roomId) + if ret { + NotificationCenter.default.post(name: .roomSummaryDidRemoveExpiredDataFromStore, object: self) + } + return ret + } +} diff --git a/Riot/Categories/MXSession.swift b/Riot/Categories/MXSession.swift index 10df98141..5300c1ec3 100644 --- a/Riot/Categories/MXSession.swift +++ b/Riot/Categories/MXSession.swift @@ -26,3 +26,18 @@ extension MXSession { displayName: user?.displayname) } } + +@objc extension MXSession { + + /// Clean the storage of a session by removing the expired contents. + func removeExpiredMessages() { + var hasStoreChanged = false + for room in self.rooms { + hasStoreChanged = hasStoreChanged || room.summary.removeExpiredRoomContentsFromStore() + } + + if hasStoreChanged { + self.store.commit?() + } + } +} diff --git a/Riot/Utils/Tools.h b/Riot/Utils/Tools.h index 57eacbcdb..8d54e06b1 100644 --- a/Riot/Utils/Tools.h +++ b/Riot/Utils/Tools.h @@ -48,4 +48,17 @@ */ + (NSURL*)fixURLWithSeveralHashKeys:(NSURL*)url; +#pragma mark - Time utilities + +/** + * Convert a number of days to a duration in ms. + */ ++ (uint64_t)durationInMsFromDays:(uint)days; + +/** + * Convert a duration in ms to a number of days. + */ ++ (uint)numberOfDaysFromDurationInMs:(uint64_t)duration; + + @end diff --git a/Riot/Utils/Tools.m b/Riot/Utils/Tools.m index 128fe3694..5866273ac 100644 --- a/Riot/Utils/Tools.m +++ b/Riot/Utils/Tools.m @@ -117,4 +117,16 @@ return fixedURL; } +#pragma mark - Time utilities + ++ (uint64_t)durationInMsFromDays:(uint)days +{ + return days * (uint64_t)(86400000); +} + ++ (uint)numberOfDaysFromDurationInMs:(uint64_t)duration +{ + return (uint)(duration / 86400000); +} + @end From db192ee81a642d326c66f720128b5b0b6deaad0a Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 14 Jun 2024 15:27:08 +0200 Subject: [PATCH 46/79] Revert "added functions to remove messages" This reverts commit 80147d43453c2422949bede3888cffe397a83f69. --- Riot/Categories/MXRoomSummary.swift | 57 ----------------------------- Riot/Categories/MXSession.swift | 15 -------- Riot/Utils/Tools.h | 13 ------- Riot/Utils/Tools.m | 12 ------ 4 files changed, 97 deletions(-) delete mode 100644 Riot/Categories/MXRoomSummary.swift diff --git a/Riot/Categories/MXRoomSummary.swift b/Riot/Categories/MXRoomSummary.swift deleted file mode 100644 index 691f534d0..000000000 --- a/Riot/Categories/MXRoomSummary.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright 2024 New Vector Ltd -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -extension Notification.Name { - static let roomSummaryDidRemoveExpiredDataFromStore = Notification.Name(MXRoomSummary.roomSummaryDidRemoveExpiredDataFromStore) -} - -@objc extension MXRoomSummary { - static let roomSummaryDidRemoveExpiredDataFromStore = "roomSummaryDidRemoveExpiredDataFromStore" - - private enum Constants { - static let roomRetentionInDaysKey = "roomRetentionInDays" - } - /// Get the room messages retention period in days - func roomRetentionPeriodInDays() -> uint { - if let period = self.others[Constants.roomRetentionInDaysKey] as? uint { - return period - } else { - return 365 - } - } - - /// Get the timestamp below which the received messages must be removed from the store, and the display - func mininumTimestamp() -> UInt64 { - let periodInMs = Tools.durationInMs(fromDays: self.roomRetentionPeriodInDays()) - let currentTs = (UInt64)(Date().timeIntervalSince1970 * 1000) - return (currentTs - periodInMs) - } - - /// Remove the expired messages from the store. - /// If some data are removed, this operation posts the notification: roomSummaryDidRemoveExpiredDataFromStore. - /// This operation does not commit the potential change. We let the caller trigger the commit when this is the more suitable. - /// - /// Provide a boolean telling whether some data have been removed. - func removeExpiredRoomContentsFromStore() -> Bool { - let ret = self.mxSession.store.removeAllMessagesSent(before: self.mininumTimestamp(), inRoom: roomId) - if ret { - NotificationCenter.default.post(name: .roomSummaryDidRemoveExpiredDataFromStore, object: self) - } - return ret - } -} diff --git a/Riot/Categories/MXSession.swift b/Riot/Categories/MXSession.swift index 5300c1ec3..10df98141 100644 --- a/Riot/Categories/MXSession.swift +++ b/Riot/Categories/MXSession.swift @@ -26,18 +26,3 @@ extension MXSession { displayName: user?.displayname) } } - -@objc extension MXSession { - - /// Clean the storage of a session by removing the expired contents. - func removeExpiredMessages() { - var hasStoreChanged = false - for room in self.rooms { - hasStoreChanged = hasStoreChanged || room.summary.removeExpiredRoomContentsFromStore() - } - - if hasStoreChanged { - self.store.commit?() - } - } -} diff --git a/Riot/Utils/Tools.h b/Riot/Utils/Tools.h index 8d54e06b1..57eacbcdb 100644 --- a/Riot/Utils/Tools.h +++ b/Riot/Utils/Tools.h @@ -48,17 +48,4 @@ */ + (NSURL*)fixURLWithSeveralHashKeys:(NSURL*)url; -#pragma mark - Time utilities - -/** - * Convert a number of days to a duration in ms. - */ -+ (uint64_t)durationInMsFromDays:(uint)days; - -/** - * Convert a duration in ms to a number of days. - */ -+ (uint)numberOfDaysFromDurationInMs:(uint64_t)duration; - - @end diff --git a/Riot/Utils/Tools.m b/Riot/Utils/Tools.m index 5866273ac..128fe3694 100644 --- a/Riot/Utils/Tools.m +++ b/Riot/Utils/Tools.m @@ -117,16 +117,4 @@ return fixedURL; } -#pragma mark - Time utilities - -+ (uint64_t)durationInMsFromDays:(uint)days -{ - return days * (uint64_t)(86400000); -} - -+ (uint)numberOfDaysFromDurationInMs:(uint64_t)duration -{ - return (uint)(duration / 86400000); -} - @end From 32a80292dbbe914e50810027ddec87a5cc8b9f10 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 14 Jun 2024 15:18:57 +0200 Subject: [PATCH 47/79] added functions to remove messages --- Riot/Categories/MXRoomSummary.swift | 57 +++++++++++++++++++++++++++++ Riot/Categories/MXSession.swift | 15 ++++++++ Riot/Utils/Tools.h | 13 +++++++ Riot/Utils/Tools.m | 12 ++++++ 4 files changed, 97 insertions(+) create mode 100644 Riot/Categories/MXRoomSummary.swift diff --git a/Riot/Categories/MXRoomSummary.swift b/Riot/Categories/MXRoomSummary.swift new file mode 100644 index 000000000..691f534d0 --- /dev/null +++ b/Riot/Categories/MXRoomSummary.swift @@ -0,0 +1,57 @@ +// +// Copyright 2024 New Vector Ltd +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation + +extension Notification.Name { + static let roomSummaryDidRemoveExpiredDataFromStore = Notification.Name(MXRoomSummary.roomSummaryDidRemoveExpiredDataFromStore) +} + +@objc extension MXRoomSummary { + static let roomSummaryDidRemoveExpiredDataFromStore = "roomSummaryDidRemoveExpiredDataFromStore" + + private enum Constants { + static let roomRetentionInDaysKey = "roomRetentionInDays" + } + /// Get the room messages retention period in days + func roomRetentionPeriodInDays() -> uint { + if let period = self.others[Constants.roomRetentionInDaysKey] as? uint { + return period + } else { + return 365 + } + } + + /// Get the timestamp below which the received messages must be removed from the store, and the display + func mininumTimestamp() -> UInt64 { + let periodInMs = Tools.durationInMs(fromDays: self.roomRetentionPeriodInDays()) + let currentTs = (UInt64)(Date().timeIntervalSince1970 * 1000) + return (currentTs - periodInMs) + } + + /// Remove the expired messages from the store. + /// If some data are removed, this operation posts the notification: roomSummaryDidRemoveExpiredDataFromStore. + /// This operation does not commit the potential change. We let the caller trigger the commit when this is the more suitable. + /// + /// Provide a boolean telling whether some data have been removed. + func removeExpiredRoomContentsFromStore() -> Bool { + let ret = self.mxSession.store.removeAllMessagesSent(before: self.mininumTimestamp(), inRoom: roomId) + if ret { + NotificationCenter.default.post(name: .roomSummaryDidRemoveExpiredDataFromStore, object: self) + } + return ret + } +} diff --git a/Riot/Categories/MXSession.swift b/Riot/Categories/MXSession.swift index 10df98141..5300c1ec3 100644 --- a/Riot/Categories/MXSession.swift +++ b/Riot/Categories/MXSession.swift @@ -26,3 +26,18 @@ extension MXSession { displayName: user?.displayname) } } + +@objc extension MXSession { + + /// Clean the storage of a session by removing the expired contents. + func removeExpiredMessages() { + var hasStoreChanged = false + for room in self.rooms { + hasStoreChanged = hasStoreChanged || room.summary.removeExpiredRoomContentsFromStore() + } + + if hasStoreChanged { + self.store.commit?() + } + } +} diff --git a/Riot/Utils/Tools.h b/Riot/Utils/Tools.h index 57eacbcdb..8d54e06b1 100644 --- a/Riot/Utils/Tools.h +++ b/Riot/Utils/Tools.h @@ -48,4 +48,17 @@ */ + (NSURL*)fixURLWithSeveralHashKeys:(NSURL*)url; +#pragma mark - Time utilities + +/** + * Convert a number of days to a duration in ms. + */ ++ (uint64_t)durationInMsFromDays:(uint)days; + +/** + * Convert a duration in ms to a number of days. + */ ++ (uint)numberOfDaysFromDurationInMs:(uint64_t)duration; + + @end diff --git a/Riot/Utils/Tools.m b/Riot/Utils/Tools.m index 128fe3694..5866273ac 100644 --- a/Riot/Utils/Tools.m +++ b/Riot/Utils/Tools.m @@ -117,4 +117,16 @@ return fixedURL; } +#pragma mark - Time utilities + ++ (uint64_t)durationInMsFromDays:(uint)days +{ + return days * (uint64_t)(86400000); +} + ++ (uint)numberOfDaysFromDurationInMs:(uint64_t)duration +{ + return (uint)(duration / 86400000); +} + @end From 567683445c8a54f696aebbb602e09e31ad3707b7 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 14 Jun 2024 15:58:00 +0200 Subject: [PATCH 48/79] added functions to listen to the event and redact the room accordingly --- Riot/Categories/MXRoomSummary.swift | 11 +- Riot/Categories/MXSession.swift | 7 +- Riot/Modules/Application/LegacyAppDelegate.m | 3 + .../Modules/Room/DataSources/RoomDataSource.m | 106 ++++++++++++++++++ 4 files changed, 117 insertions(+), 10 deletions(-) diff --git a/Riot/Categories/MXRoomSummary.swift b/Riot/Categories/MXRoomSummary.swift index 691f534d0..b48f1a70f 100644 --- a/Riot/Categories/MXRoomSummary.swift +++ b/Riot/Categories/MXRoomSummary.swift @@ -20,8 +20,9 @@ extension Notification.Name { static let roomSummaryDidRemoveExpiredDataFromStore = Notification.Name(MXRoomSummary.roomSummaryDidRemoveExpiredDataFromStore) } -@objc extension MXRoomSummary { - static let roomSummaryDidRemoveExpiredDataFromStore = "roomSummaryDidRemoveExpiredDataFromStore" +extension MXRoomSummary { + @objc static let roomSummaryDidRemoveExpiredDataFromStore = "roomSummaryDidRemoveExpiredDataFromStore" + @objc static let roomRetentionStateEventType = "m.room.retention" private enum Constants { static let roomRetentionInDaysKey = "roomRetentionInDays" @@ -36,7 +37,7 @@ extension Notification.Name { } /// Get the timestamp below which the received messages must be removed from the store, and the display - func mininumTimestamp() -> UInt64 { + @objc func minimumTimestamp() -> UInt64 { let periodInMs = Tools.durationInMs(fromDays: self.roomRetentionPeriodInDays()) let currentTs = (UInt64)(Date().timeIntervalSince1970 * 1000) return (currentTs - periodInMs) @@ -47,8 +48,8 @@ extension Notification.Name { /// This operation does not commit the potential change. We let the caller trigger the commit when this is the more suitable. /// /// Provide a boolean telling whether some data have been removed. - func removeExpiredRoomContentsFromStore() -> Bool { - let ret = self.mxSession.store.removeAllMessagesSent(before: self.mininumTimestamp(), inRoom: roomId) + @objc func removeExpiredRoomContentsFromStore() -> Bool { + let ret = self.mxSession.store.removeAllMessagesSent(before: self.minimumTimestamp(), inRoom: roomId) if ret { NotificationCenter.default.post(name: .roomSummaryDidRemoveExpiredDataFromStore, object: self) } diff --git a/Riot/Categories/MXSession.swift b/Riot/Categories/MXSession.swift index 5300c1ec3..4d7256b62 100644 --- a/Riot/Categories/MXSession.swift +++ b/Riot/Categories/MXSession.swift @@ -25,12 +25,9 @@ extension MXSession { matrixItemId: userId, displayName: user?.displayname) } -} - -@objc extension MXSession { - + /// Clean the storage of a session by removing the expired contents. - func removeExpiredMessages() { + @objc func removeExpiredMessages() { var hasStoreChanged = false for room in self.rooms { hasStoreChanged = hasStoreChanged || room.summary.removeExpiredRoomContentsFromStore() diff --git a/Riot/Modules/Application/LegacyAppDelegate.m b/Riot/Modules/Application/LegacyAppDelegate.m index 79d263cef..c5030714d 100644 --- a/Riot/Modules/Application/LegacyAppDelegate.m +++ b/Riot/Modules/Application/LegacyAppDelegate.m @@ -1826,6 +1826,9 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni [self registerNewRequestNotificationForSession:mxSession]; [self.pushNotificationService checkPushKitPushersInSession:mxSession]; + + // Clean the storage by removing expired data + [mxSession removeExpiredMessages]; } else if (mxSession.state == MXSessionStateRunning) { diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index 16e05c423..55ef184f1 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -33,6 +33,9 @@ const CGFloat kTypingCellHeight = 24; { // Observe kThemeServiceDidChangeThemeNotification to handle user interface theme change. id kThemeServiceDidChangeThemeNotificationObserver; + + // The listener to the room retention changes. + id retentionListener; } // Observe key verification request changes @@ -167,6 +170,31 @@ const CGFloat kTypingCellHeight = 24; self.eventFormatter.eventTypesFilterForMessages = [MXKAppSettings standardAppSettings].eventsFilterForMessages; } +- (void)setDelegate:(id)delegate +{ + [self unregisterRoomSummaryDidRemoveExpiredDataFromStoreNotifications]; + [self removeRoomRetentionEventListener]; + + if (delegate && self.isLive) + { + if (self.room) + { + // Remove the potential expired messages from the store + if ([self.room.summary removeExpiredRoomContentsFromStore]) + { + [self.mxSession.store commit]; + } + [self addRoomRetentionEventListener]; + } + + // Observe room history flush (expired content data) + [self registerRoomSummaryDidRemoveExpiredDataFromStoreNotifications]; + [self roomSummaryDidRemoveExpiredDataFromStore]; + } + + [super setDelegate:delegate]; +} + - (void)destroy { if (kThemeServiceDidChangeThemeNotificationObserver) @@ -197,6 +225,9 @@ const CGFloat kTypingCellHeight = 24; [self.mxSession.aggregations.beaconAggregations removeListener:self.beaconInfoSummaryDeletionListener]; } + [self unregisterRoomSummaryDidRemoveExpiredDataFromStoreNotifications]; + [self removeRoomRetentionEventListener]; + [super destroy]; } @@ -1242,4 +1273,79 @@ const CGFloat kTypingCellHeight = 24; } } +#pragma mark - roomSummaryDidRemoveExpiredDataFromStore notifications + +- (void)registerRoomSummaryDidRemoveExpiredDataFromStoreNotifications +{ + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(roomSummaryDidRemoveExpiredDataFromStore:) name:MXRoomSummary.roomSummaryDidRemoveExpiredDataFromStore object:nil]; +} + +- (void)unregisterRoomSummaryDidRemoveExpiredDataFromStoreNotifications +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:MXRoomSummary.roomSummaryDidRemoveExpiredDataFromStore object:nil]; +} + +- (void)roomSummaryDidRemoveExpiredDataFromStore:(NSNotification*)notification +{ + MXRoomSummary *roomSummary = notification.object; + if (self.mxSession == roomSummary.mxSession && [self.roomId isEqualToString:roomSummary.roomId]) + { + [self roomSummaryDidRemoveExpiredDataFromStore]; + } +} + +- (void)roomSummaryDidRemoveExpiredDataFromStore +{ + // Check whether the first cell data refers to an expired event (this may be a state event + MXEvent *firstMessageEvent; + for (id cellData in bubbles) + { + for (MXEvent *event in cellData.events) + { + if (!event.isState) { + firstMessageEvent = event; + break; + } + } + + if (firstMessageEvent) + { + break; + } + } + + if (firstMessageEvent && firstMessageEvent.originServerTs < self.room.summary.minimumTimestamp) + { + [self reload]; + } +} + +#pragma mark - room retention event listener + +- (void)addRoomRetentionEventListener +{ + // Register a listener to handle the room retention in live timelines + retentionListener = [self.timeline listenToEventsOfTypes:@[MXRoomSummary.roomRetentionStateEventType] onEvent:^(MXEvent *redactionEvent, MXTimelineDirection direction, MXRoomState *roomState) { + + // Consider only live events + if (direction == MXTimelineDirectionForwards) + { + // Remove the potential expired messages from the store + if ([self.room.summary removeExpiredRoomContentsFromStore]) + { + [self.mxSession.store commit]; + } + } + }]; +} + +- (void)removeRoomRetentionEventListener +{ + if (retentionListener) + { + [self.timeline removeListener:retentionListener]; + retentionListener = nil; + } +} + @end From 292cbb292e39a15c935f82e4c3de97a7925a0e42 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 14 Jun 2024 17:08:07 +0200 Subject: [PATCH 49/79] updating SDK --- Podfile.lock | 12 ++++++------ matrix-ios-sdk | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index 673d4ecc0..979f760d9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -39,9 +39,9 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.27.8): - - MatrixSDK/Core (= 0.27.8) - - MatrixSDK/Core (0.27.8): + - MatrixSDK (0.27.9): + - MatrixSDK/Core (= 0.27.9) + - MatrixSDK/Core (0.27.9): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) @@ -49,7 +49,7 @@ PODS: - OLMKit (~> 3.2.5) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/JingleCallStack (0.27.8): + - MatrixSDK/JingleCallStack (0.27.9): - JitsiMeetSDKLite (= 8.1.2-lite) - MatrixSDK/Core - MatrixSDKCrypto (0.4.2) @@ -187,7 +187,7 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: 4c5a8572a481340ab233451ad36c1322d371fae5 + MatrixSDK: 246fd1d3620afcbf8cb76794e9343ebf3cbf881b MatrixSDKCrypto: 736069ee0a5ec12852ab3498bf2242acecc443fc OLMKit: da115f16582e47626616874e20f7bb92222c7a51 ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d @@ -209,4 +209,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: b622ffadc1a0fe5442787bd9023ca3d110384814 -COCOAPODS: 1.15.2 +COCOAPODS: 1.14.3 diff --git a/matrix-ios-sdk b/matrix-ios-sdk index 3052a396b..fcfbb6718 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit 3052a396b88095cbcfe1b4f488127f69e3280cda +Subproject commit fcfbb6718224e9819105b93fa9e86a9db1cf04a6 From 18bfbbb4f2eede552124c2d790f7cd7d1ea4452c Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 10 May 2024 22:54:12 +0000 Subject: [PATCH 50/79] Translated using Weblate (Portuguese (Brazil)) Currently translated at 97.3% (2351 of 2416 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/pt_BR/ --- Riot/Assets/pt_BR.lproj/Vector.strings | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/Riot/Assets/pt_BR.lproj/Vector.strings b/Riot/Assets/pt_BR.lproj/Vector.strings index 991716cd9..edd2cf70e 100644 --- a/Riot/Assets/pt_BR.lproj/Vector.strings +++ b/Riot/Assets/pt_BR.lproj/Vector.strings @@ -1226,7 +1226,7 @@ "secrets_recovery_reset_action_part_2" = "Resettar tudo"; "secrets_setup_recovery_passphrase_summary_information" = "Lembre-se de sua Frase de Segurança. Ela pode ser usada para destrancar suas mensagens & dados encriptados."; "secrets_setup_recovery_passphrase_summary_title" = "Salvar sua Frase de Segurança"; -"home_empty_view_information" = "O app de chat seguro tudo-em-um para equipes, amigas(os) e organizações. Toque no botão + abaixo para adicionar pessoas e salas."; +"home_empty_view_information" = "O app de chat seguro tudo-em-um para equipes, amigos e organizações. Toque no botão + abaixo para adicionar pessoas e salas."; // MARK: - Home @@ -1244,7 +1244,7 @@ // MARK: - Invite friends -"invite_friends_action" = "Convidar amigas(os) para %@"; +"invite_friends_action" = "Convidar amigos para %@"; "pin_protection_settings_change_pin" = "Mudar PIN"; "pin_protection_confirm_pin_to_change" = "Confirme PIN para mudar PIN"; "bug_report_background_mode" = "Continuar em background"; @@ -1348,7 +1348,7 @@ "side_menu_action_feedback" = "Feedback"; "side_menu_action_help" = "Ajuda"; "side_menu_action_settings" = "Ajustes"; -"side_menu_action_invite_friends" = "Convidar amigas(os)"; +"side_menu_action_invite_friends" = "Convidar amigos"; // Mark: - Side menu @@ -1632,7 +1632,7 @@ "onboarding_use_case_not_sure_yet" = "Não tem certeza ainda? %@"; "onboarding_use_case_community_messaging" = "Comunidades"; "onboarding_use_case_work_messaging" = "Times"; -"onboarding_use_case_personal_messaging" = "Amigas(os) e família"; +"onboarding_use_case_personal_messaging" = "Amigos e família"; "onboarding_use_case_message" = "Nós vamos ajudá-la(o) a ficar conectada(o)"; "onboarding_use_case_title" = "Com quem você vai fazer chat mais?"; @@ -2654,3 +2654,20 @@ "user_other_session_security_recommendation_title" = "Outras sessões"; "room_creation_only_one_email_invite" = "Você só pode convidar um e-mail de cada vez"; "accessibility_selected" = "selecionado"; +"room_creation_user_not_found_prompt_title" = "Confirmação"; +"room_creation_user_not_found_prompt_message" = "Não foi possível encontrar perfis para este ID do Matrix. Quer começar uma conversa mesmo assim?"; +"room_creation_user_not_found_prompt_invite_action" = "Começar conversa mesmo assim"; +"room_participants_invite_anyway" = "Convidar mesmo assim"; +"room_command_part_room_description" = "Sair da sala"; +"room_command_kick_user_description" = "Remove o usuário com o ID fornecido desta sala"; +"room_command_unban_user_description" = "Desbane o usuário com o ID fornecido"; +"room_command_set_user_power_level_description" = "Define o nível de poder de um usuário"; +"room_participants_invite_unknown_participant_prompt_to_msg" = "Não foi possível encontrar perfis para este ID do Matrix. Tem certeza que deseja convidar %@ para %@?"; +"room_command_ban_user_description" = "Bane o usuário com o ID fornecido"; + +// Room commands descriptions +"room_command_change_display_name_description" = "Altera o seu nome de exibição"; +"room_command_emote_description" = "Exibe ação"; +"room_command_join_room_description" = "Entra na sala com o endereço fornecido"; +"room_command_invite_user_description" = "Convida o usuário com o ID fornecido para a sala atual"; +"authentication_qr_login_failure_device_not_supported" = "Vincular com este dispositivo não é suportado."; From a0578ca73e28b257ddb6fc7e98ad12f700a56bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Mesk=C3=B3?= Date: Mon, 13 May 2024 13:55:58 +0000 Subject: [PATCH 51/79] Translated using Weblate (Hungarian) Currently translated at 99.8% (2412 of 2416 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ --- Riot/Assets/hu.lproj/Vector.strings | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index c965d650c..216ab88fd 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -1352,7 +1352,7 @@ "event_formatter_call_ringing" = "Hívás…"; "event_formatter_call_connecting" = "Kapcsolás…"; "settings_labs_enable_ringing_for_group_calls" = "Csengetés csoportos hívásokhoz"; -"room_no_privileges_to_create_group_call" = "Adminisztrátornak vagy moderátornak kell lenned a hívás indításához."; +"room_no_privileges_to_create_group_call" = "Adminisztrátornak vagy moderátornak kell lennie a hívás indításához."; "room_join_group_call" = "Csatlakozás"; // Chat @@ -2501,8 +2501,8 @@ "room_first_message_placeholder" = "Küld el az első üzenetedet…"; "authentication_qr_login_confirm_title" = "Biztonságos kapcsolat beállítva"; "room_event_encryption_info_key_authenticity_not_guaranteed" = "A titkosított üzenetek valódiságát ezen az eszközön nem lehet garantálni."; -"wysiwyg_composer_format_action_underline" = "Aláhúzott"; -"wysiwyg_composer_format_action_strikethrough" = "Áthúzott"; +"wysiwyg_composer_format_action_underline" = "Aláhúzott formázás alkalmazása"; +"wysiwyg_composer_format_action_strikethrough" = "Áthúzott formázás alkalmazása"; "wysiwyg_composer_format_action_italic" = "Dőlt"; // Formatting Actions @@ -2755,3 +2755,11 @@ "room_command_kick_user_description" = "Eltávolítja az adott azonosítójú felhasználót ebből a szobából"; "room_command_ban_user_description" = "Kitiltja az adott azonosítójú felhasználót"; "room_command_unban_user_description" = "Feloldja az adott azonosítójú felhasználó kitiltását"; +"notice_display_name_changed_to" = "%@ erre módosította a megjelenítendő nevét: %@"; +"poll_timeline_loading" = "Betöltés..."; +"manage_session_redirect" = "Át lesz irányítva a kiszolgálója hitelesítési szolgáltatójához, hogy befejezze a kijelentkezést."; +"manage_session_redirect_error" = "A funkcionalitás jelenleg nem érhető el. Lépjen kapcsolatba a Matrix-kiszolgáló rendszergazdájával."; +"settings_manage_account_title" = "Fiók"; +"settings_manage_account_action" = "Fiók kezelése"; +"settings_manage_account_description" = "A fiókja kezelése itt: %@"; +"room_command_change_room_topic_description" = "Beállítja a szoba témáját"; From 7a8010bc1c5834343c296becd857123201b52593 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20I=2ESvindseth?= Date: Wed, 29 May 2024 21:07:58 +0000 Subject: [PATCH 52/79] Translated using Weblate (Norwegian Nynorsk) Currently translated at 2.2% (54 of 2416 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/nn/ --- Riot/Assets/nn.lproj/Vector.strings | 58 +++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/Riot/Assets/nn.lproj/Vector.strings b/Riot/Assets/nn.lproj/Vector.strings index 1eec1c558..f1775b985 100644 --- a/Riot/Assets/nn.lproj/Vector.strings +++ b/Riot/Assets/nn.lproj/Vector.strings @@ -9,3 +9,61 @@ "warning" = "Åtvaring"; // String for App Store "store_short_description" = "Sikker desentralisert chat/IP-telefoni"; +"ok" = "OK"; +"callbar_only_single_paused" = "Samtale sett på pause"; +"cancel" = "Avbryt"; +"save" = "Lagra"; +"join" = "Ver med"; +"decline" = "Avslå"; +"accept" = "Godta"; +"preview" = "Førehandsvising"; +"camera" = "Kamera"; +"voice" = "Røyst"; +"video" = "Video"; +"active_call" = "Aktiv samtale"; +"active_call_details" = "Aktiv samtale (%@)"; +"joined" = "Vart med"; +"later" = "Seinare"; +"rename" = "Endre namn"; +"collapse" = "Skjul"; +"send_to" = "Send til %@"; +"sending" = "Sender"; +"close" = "Lat att"; +"skip" = "Hopp over"; +"switch" = "Byt"; +"more" = "Meir"; +"less" = "Mindre"; +"open" = "Opne"; +"done" = "Ferdig"; + +// Call Bar +"callbar_only_single_active" = "Trykk for å gå tilbake til samtalen (%@)"; +"callbar_only_multiple_paused" = "%@ samtalar sett på pause"; +"callbar_return" = "Gå tilbake"; +"callbar_only_single_active_group" = "Trykk for å bli med i konferansesamtalen (%@)"; + +// Accessibility +"accessibility_checkbox_label" = "avkryssingsboks"; +"accessibility_button_label" = "knapp"; +"error" = "Feil"; +"invite_to" = "Inviter til %@"; + +// MARK: Onboarding +"onboarding_splash_register_button_title" = "Opprett konto"; +"accessibility_selected" = "vald"; +"private" = "Privat"; +"public" = "Offentleg"; +"stop" = "Stopp"; +"new_word" = "Ny"; +"existing" = "Eksisterande"; +"add" = "Legg til"; +"suggest" = "Føreslå"; +"edit" = "Rediger"; + +// Activities +"loading" = "Lastar"; +"saving" = "Lagrar"; +"callbar_active_and_single_paused" = "1 aktiv samtale (%@) · 1 samtale sett i pause"; +"callbar_active_and_multiple_paused" = "1 aktiv samtale (%@) · %@ samtalar sett på pause"; +"confirm" = "Stadfest"; +"onboarding_splash_login_button_title" = "Eg har allereie ein konto"; From 94acce621acbaec2d9938b420cc7857a591d0018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20I=2ESvindseth?= Date: Wed, 12 Jun 2024 03:12:09 +0000 Subject: [PATCH 53/79] Translated using Weblate (Norwegian Nynorsk) Currently translated at 2.7% (67 of 2416 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/nn/ --- Riot/Assets/nn.lproj/Vector.strings | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Riot/Assets/nn.lproj/Vector.strings b/Riot/Assets/nn.lproj/Vector.strings index f1775b985..533975c2f 100644 --- a/Riot/Assets/nn.lproj/Vector.strings +++ b/Riot/Assets/nn.lproj/Vector.strings @@ -67,3 +67,16 @@ "callbar_active_and_multiple_paused" = "1 aktiv samtale (%@) · %@ samtalar sett på pause"; "confirm" = "Stadfest"; "onboarding_splash_login_button_title" = "Eg har allereie ein konto"; +"authentication_forgot_password_text_field_placeholder" = "E-postadresse"; +"next" = "Neste"; +"back" = "Tilbake"; +"continue" = "Fortset"; +"create" = "Lag"; +"remove" = "Fjern"; +"invite" = "Inviter"; +"retry" = "Prøv på nytt"; +"on" = "På"; +"off" = "Av"; +"authentication_login_username" = "Brukarnamn / e-postadresse / telefonnummer"; +"onboarding_display_name_placeholder" = "Visingsnamn"; +"authentication_login_with_qr" = "Logg inn med QR-kode"; From 10477fb4335db56bd3595a7146f5aeb4261e39f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20I=2ESvindseth?= Date: Wed, 12 Jun 2024 02:57:35 +0000 Subject: [PATCH 54/79] Added translation using Weblate (Norwegian Nynorsk) --- Riot/Assets/nn.lproj/InfoPlist.strings | 1 + 1 file changed, 1 insertion(+) create mode 100644 Riot/Assets/nn.lproj/InfoPlist.strings diff --git a/Riot/Assets/nn.lproj/InfoPlist.strings b/Riot/Assets/nn.lproj/InfoPlist.strings new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Riot/Assets/nn.lproj/InfoPlist.strings @@ -0,0 +1 @@ + From 7eb936567cdc4a441a8f6c8fd179cdfa8b3dfd3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20I=2ESvindseth?= Date: Wed, 12 Jun 2024 03:06:31 +0000 Subject: [PATCH 55/79] Translated using Weblate (Norwegian Nynorsk) Currently translated at 50.0% (4 of 8 strings) Translation: Element iOS/Element iOS (Dialogs) Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios-dialogs/nn/ --- Riot/Assets/nn.lproj/InfoPlist.strings | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Riot/Assets/nn.lproj/InfoPlist.strings b/Riot/Assets/nn.lproj/InfoPlist.strings index 8b1378917..c1f10e5b0 100644 --- a/Riot/Assets/nn.lproj/InfoPlist.strings +++ b/Riot/Assets/nn.lproj/InfoPlist.strings @@ -1 +1,7 @@ + +"NSCalendarsUsageDescription" = "Sjå dei planlagde møta dine i appen."; +"NSFaceIDUsageDescription" = "Face ID vert brukt til å få tilgang til appen din."; +// Permissions usage explanations +"NSCameraUsageDescription" = "Kameraet vert brukt til videosamtalar, og til å ta og laste opp bilde og videoar."; +"NSMicrophoneUsageDescription" = "Appen treng tilgang til mikrofonen for samtalar, og for å spele inn video og lydmeldingar."; From d3baf5d76dda1867caa02e1bf892da573673c43b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20I=2ESvindseth?= Date: Wed, 29 May 2024 20:59:17 +0000 Subject: [PATCH 56/79] Added translation using Weblate (Norwegian Nynorsk) --- Riot/Assets/nn.lproj/Localizable.strings | 1 + 1 file changed, 1 insertion(+) create mode 100644 Riot/Assets/nn.lproj/Localizable.strings diff --git a/Riot/Assets/nn.lproj/Localizable.strings b/Riot/Assets/nn.lproj/Localizable.strings new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/Riot/Assets/nn.lproj/Localizable.strings @@ -0,0 +1 @@ + From 8f0e86d65522e83dcb319a315f9bb4b67772b1ed Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 17 Jun 2024 11:13:53 +0100 Subject: [PATCH 57/79] version++ --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 27abf6350..19854177c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +## Changes in 1.11.14 (2024-06-17) + +No significant changes. + + ## Changes in 1.11.13 (2024-06-12) Others From d82f2f7bc46c66229a0fabb88655ffc619488eda Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 17 Jun 2024 12:28:51 +0100 Subject: [PATCH 58/79] finish version++ From 5da2dd3eaf0c592bd359bf4582e1f7b5c476c971 Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 17 Jun 2024 12:28:58 +0100 Subject: [PATCH 59/79] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index e53ee7842..716ff33d7 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.14 -CURRENT_PROJECT_VERSION = 1.11.14 +MARKETING_VERSION = 1.11.15 +CURRENT_PROJECT_VERSION = 1.11.15 From 5cb401d594f6b902e3da78a58f19754b7750525f Mon Sep 17 00:00:00 2001 From: Doug Date: Mon, 17 Jun 2024 12:31:30 +0100 Subject: [PATCH 60/79] Changelog. --- CHANGES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 19854177c..93a8b1580 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ ## Changes in 1.11.14 (2024-06-17) -No significant changes. +🙌 Improvements + +- Room retention event implementation ([#7809](https://github.com/element-hq/element-ios/pull/7809)) ## Changes in 1.11.13 (2024-06-12) From f7535f5d87b4af1343cf62c3d6462d9f77347c7c Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 18 Jun 2024 15:49:14 +0200 Subject: [PATCH 61/79] fix --- Podfile.lock | 10 +++++----- Riot/Categories/MXRoomSummary.swift | 13 ++++++------- Riot/Utils/EventFormatter.m | 17 +++++++++++++++-- Riot/Utils/Tools.h | 6 ------ Riot/Utils/Tools.m | 5 ----- matrix-ios-sdk | 2 +- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index 979f760d9..ce0165a2b 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -39,9 +39,9 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.27.9): - - MatrixSDK/Core (= 0.27.9) - - MatrixSDK/Core (0.27.9): + - MatrixSDK (0.27.10): + - MatrixSDK/Core (= 0.27.10) + - MatrixSDK/Core (0.27.10): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) @@ -49,7 +49,7 @@ PODS: - OLMKit (~> 3.2.5) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/JingleCallStack (0.27.9): + - MatrixSDK/JingleCallStack (0.27.10): - JitsiMeetSDKLite (= 8.1.2-lite) - MatrixSDK/Core - MatrixSDKCrypto (0.4.2) @@ -187,7 +187,7 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: 246fd1d3620afcbf8cb76794e9343ebf3cbf881b + MatrixSDK: c805f9306d60955215f4b15043ed0f96fd4867b3 MatrixSDKCrypto: 736069ee0a5ec12852ab3498bf2242acecc443fc OLMKit: da115f16582e47626616874e20f7bb92222c7a51 ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d diff --git a/Riot/Categories/MXRoomSummary.swift b/Riot/Categories/MXRoomSummary.swift index b48f1a70f..4cf55ff6a 100644 --- a/Riot/Categories/MXRoomSummary.swift +++ b/Riot/Categories/MXRoomSummary.swift @@ -23,22 +23,21 @@ extension Notification.Name { extension MXRoomSummary { @objc static let roomSummaryDidRemoveExpiredDataFromStore = "roomSummaryDidRemoveExpiredDataFromStore" @objc static let roomRetentionStateEventType = "m.room.retention" + @objc static let roomRetentionEventMaxLifetimeKey = "max_lifetime" + @objc static let roomRetentionMaxLifetime = "roomRetentionMaxLifetime" - private enum Constants { - static let roomRetentionInDaysKey = "roomRetentionInDays" - } /// Get the room messages retention period in days - func roomRetentionPeriodInDays() -> uint { - if let period = self.others[Constants.roomRetentionInDaysKey] as? uint { + private func roomRetentionPeriodInMillis() -> UInt64 { + if let period = self.others[MXRoomSummary.roomRetentionMaxLifetime] as? UInt64 { return period } else { - return 365 + return Tools.durationInMs(fromDays: 365) } } /// Get the timestamp below which the received messages must be removed from the store, and the display @objc func minimumTimestamp() -> UInt64 { - let periodInMs = Tools.durationInMs(fromDays: self.roomRetentionPeriodInDays()) + let periodInMs = self.roomRetentionPeriodInMillis() let currentTs = (UInt64)(Date().timeIntervalSince1970 * 1000) return (currentTs - periodInMs) } diff --git a/Riot/Utils/EventFormatter.m b/Riot/Utils/EventFormatter.m index d53a3e19a..2a1b15140 100644 --- a/Riot/Utils/EventFormatter.m +++ b/Riot/Utils/EventFormatter.m @@ -632,7 +632,14 @@ withVoiceBroadcastInfoStateEvent:lastVoiceBroadcastInfoEvent - (BOOL)session:(MXSession *)session updateRoomSummary:(MXRoomSummary *)summary withStateEvents:(NSArray *)stateEvents roomState:(MXRoomState *)roomState { BOOL updated = [super session:session updateRoomSummary:summary withStateEvents:stateEvents roomState:roomState]; - + + MXEvent* lastRoomRetentionEvent = [self roomRetentionEventFromStateEvents:stateEvents]; + if (lastRoomRetentionEvent) + { + summary.others[MXRoomSummary.roomRetentionMaxLifetime] = lastRoomRetentionEvent.content[MXRoomSummary.roomRetentionEventMaxLifetimeKey]; + updated = YES; + } + // Customisation for EMS Functional Members in direct rooms if (BuildSettings.supportFunctionalMembers && summary.room.isDirect) { @@ -645,7 +652,7 @@ withVoiceBroadcastInfoStateEvent:lastVoiceBroadcastInfoEvent // room name which we'll do twice more in updateRoomSummary:withServerRoomSummary:roomState: anyway. // // So return YES and let that happen there. - return YES; + updated = YES; } } @@ -801,6 +808,12 @@ withVoiceBroadcastInfoStateEvent:lastVoiceBroadcastInfoEvent return [stateEvents filteredArrayUsingPredicate:functionalMembersPredicate].lastObject; } +- (MXEvent *)roomRetentionEventFromStateEvents:(NSArray *)stateEvents +{ + NSPredicate *functionalMembersPredicate = [NSPredicate predicateWithFormat:@"type == %@", kMXEventTypeStringRoomRetention]; + return [stateEvents filteredArrayUsingPredicate:functionalMembersPredicate].lastObject; +} + #pragma mark - Timestamp formatting - (NSString*)dateStringFromDate:(NSDate *)date withTime:(BOOL)time diff --git a/Riot/Utils/Tools.h b/Riot/Utils/Tools.h index 8d54e06b1..f114167b3 100644 --- a/Riot/Utils/Tools.h +++ b/Riot/Utils/Tools.h @@ -55,10 +55,4 @@ */ + (uint64_t)durationInMsFromDays:(uint)days; -/** - * Convert a duration in ms to a number of days. - */ -+ (uint)numberOfDaysFromDurationInMs:(uint64_t)duration; - - @end diff --git a/Riot/Utils/Tools.m b/Riot/Utils/Tools.m index 5866273ac..4094d0223 100644 --- a/Riot/Utils/Tools.m +++ b/Riot/Utils/Tools.m @@ -124,9 +124,4 @@ return days * (uint64_t)(86400000); } -+ (uint)numberOfDaysFromDurationInMs:(uint64_t)duration -{ - return (uint)(duration / 86400000); -} - @end diff --git a/matrix-ios-sdk b/matrix-ios-sdk index fcfbb6718..ff2b2a402 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit fcfbb6718224e9819105b93fa9e86a9db1cf04a6 +Subproject commit ff2b2a4024b48dbeba5d4157d2622161b3034ba4 From 28d53622cd5d1e1072ba2b8b1c99bcd72e779708 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 18 Jun 2024 16:52:09 +0200 Subject: [PATCH 62/79] version++ --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 93a8b1580..907d69b54 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +## Changes in 1.11.15 (2024-06-18) + +No significant changes. + + ## Changes in 1.11.14 (2024-06-17) 🙌 Improvements From 53a6a5476f33ac97cacad0effec1165400c17f77 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 18 Jun 2024 16:54:46 +0200 Subject: [PATCH 63/79] finish version++ From b357794162144d2facae458889d77ec3e4946272 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 18 Jun 2024 16:54:53 +0200 Subject: [PATCH 64/79] Prepare for new sprint --- Config/AppVersion.xcconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index 716ff33d7..084508c89 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.11.15 -CURRENT_PROJECT_VERSION = 1.11.15 +MARKETING_VERSION = 1.11.16 +CURRENT_PROJECT_VERSION = 1.11.16 From a35e06cddab694e61c5ecdd3d4978e67151576d4 Mon Sep 17 00:00:00 2001 From: Doug <6060466+pixlwave@users.noreply.github.com> Date: Mon, 24 Jun 2024 17:33:50 +0100 Subject: [PATCH 65/79] Update the SDK. (#7819) * Update the SDK. * Run pod install. --- Podfile.lock | 10 +++++----- matrix-ios-sdk | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Podfile.lock b/Podfile.lock index ce0165a2b..6e3ce20f9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -39,9 +39,9 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.27.10): - - MatrixSDK/Core (= 0.27.10) - - MatrixSDK/Core (0.27.10): + - MatrixSDK (0.27.11): + - MatrixSDK/Core (= 0.27.11) + - MatrixSDK/Core (0.27.11): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) @@ -49,7 +49,7 @@ PODS: - OLMKit (~> 3.2.5) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/JingleCallStack (0.27.10): + - MatrixSDK/JingleCallStack (0.27.11): - JitsiMeetSDKLite (= 8.1.2-lite) - MatrixSDK/Core - MatrixSDKCrypto (0.4.2) @@ -187,7 +187,7 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: c805f9306d60955215f4b15043ed0f96fd4867b3 + MatrixSDK: 7c29e5cc8934cfc1f81f83fcfa17cd652612086d MatrixSDKCrypto: 736069ee0a5ec12852ab3498bf2242acecc443fc OLMKit: da115f16582e47626616874e20f7bb92222c7a51 ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d diff --git a/matrix-ios-sdk b/matrix-ios-sdk index ff2b2a402..04e422e1f 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit ff2b2a4024b48dbeba5d4157d2622161b3034ba4 +Subproject commit 04e422e1f70eb3c32b9d0067cf9721bdc295caa0 From 390eeb1a61d0a9eaf7390ca85916bf021795af3f Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 5 Jul 2024 16:11:47 +0200 Subject: [PATCH 66/79] updated SDK and added a fix for the discover server table view cell --- .../Views/DirectoryServerTableViewCell.m | 10 ++++++++++ matrix-ios-sdk | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Riot/Modules/Rooms/DirectoryPicker/Views/DirectoryServerTableViewCell.m b/Riot/Modules/Rooms/DirectoryPicker/Views/DirectoryServerTableViewCell.m index 6ec9484e6..3daadd924 100644 --- a/Riot/Modules/Rooms/DirectoryPicker/Views/DirectoryServerTableViewCell.m +++ b/Riot/Modules/Rooms/DirectoryPicker/Views/DirectoryServerTableViewCell.m @@ -60,6 +60,16 @@ { iconURL = [NSString stringWithFormat:@"%@%@", kMXContentUriScheme, [iconURL substringFromIndex:range.location + range.length]]; } + // Check also if we are using the authenticated endpoint + else + { + mxMediaPrefix = [NSString stringWithFormat:@"/%@/download/", kMXAuthenticatedContentPrefixPath]; + range = [iconURL rangeOfString:mxMediaPrefix]; + if (range.location != NSNotFound) + { + iconURL = [NSString stringWithFormat:@"%@%@", kMXContentUriScheme, [iconURL substringFromIndex:range.location + range.length]]; + } + } [self.iconImageView setImageURI:iconURL withType:nil andImageOrientation:UIImageOrientationUp diff --git a/matrix-ios-sdk b/matrix-ios-sdk index 04e422e1f..66f05d046 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit 04e422e1f70eb3c32b9d0067cf9721bdc295caa0 +Subproject commit 66f05d0468390bdddf838b73135353408fa5390c From 42a067586dddb742bb060f8265172e2580d47e59 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Fri, 5 Jul 2024 18:08:38 +0200 Subject: [PATCH 67/79] updated the submodule --- matrix-ios-sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-ios-sdk b/matrix-ios-sdk index 66f05d046..1c4b3f5c3 160000 --- a/matrix-ios-sdk +++ b/matrix-ios-sdk @@ -1 +1 @@ -Subproject commit 66f05d0468390bdddf838b73135353408fa5390c +Subproject commit 1c4b3f5c32ed3bcf27d3404c770e000a50417352 From 5799976675e714336193f447979bfdac2ab3da96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Mon, 17 Jun 2024 10:55:06 +0000 Subject: [PATCH 68/79] Translated using Weblate (Estonian) Currently translated at 99.9% (2418 of 2420 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ --- Riot/Assets/et.lproj/Vector.strings | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index 22e9f3419..8311104ce 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -2719,3 +2719,5 @@ "settings_manage_account_description" = "Halda kasutajakontot koduserveris %@"; "manage_session_redirect" = "Järgmiseks suuname sind sinu serveriteenuse autentijale ning seal saad sa väljalogimise lõpuni viia."; "manage_session_redirect_error" = "See funktsionaalsus pole hetkel saadaval. Lisateavet saad oma koduserveri haldajalt"; +"room_action_report" = "Teata jututoast"; +"room_action_report_prompt_reason" = "Jututoast teatamise põhjus"; From 3507534c703ba0b4a77233fcfb3a9fdc7d8db330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Priit=20J=C3=B5er=C3=BC=C3=BCt?= Date: Mon, 17 Jun 2024 19:41:28 +0000 Subject: [PATCH 69/79] Translated using Weblate (Estonian) Currently translated at 100.0% (2420 of 2420 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/et/ --- Riot/Assets/et.lproj/Vector.strings | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Riot/Assets/et.lproj/Vector.strings b/Riot/Assets/et.lproj/Vector.strings index 8311104ce..c21f0ba26 100644 --- a/Riot/Assets/et.lproj/Vector.strings +++ b/Riot/Assets/et.lproj/Vector.strings @@ -2721,3 +2721,8 @@ "manage_session_redirect_error" = "See funktsionaalsus pole hetkel saadaval. Lisateavet saad oma koduserveri haldajalt"; "room_action_report" = "Teata jututoast"; "room_action_report_prompt_reason" = "Jututoast teatamise põhjus"; + + +// MARK: - WYSIWYG Composer +"wysiwyg_composer_action_minimise_action" = "Peida tekstitoimeti"; +"wysiwyg_composer_action_maximise_action" = "Ava tekstitoimeti"; From 250cbd3e5664b476e10058af8051cf177ab883d2 Mon Sep 17 00:00:00 2001 From: Besnik Bleta Date: Tue, 18 Jun 2024 08:52:46 +0000 Subject: [PATCH 70/79] Translated using Weblate (Albanian) Currently translated at 99.6% (2411 of 2420 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sq/ --- Riot/Assets/sq.lproj/Vector.strings | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Riot/Assets/sq.lproj/Vector.strings b/Riot/Assets/sq.lproj/Vector.strings index cd338d626..b1158c152 100644 --- a/Riot/Assets/sq.lproj/Vector.strings +++ b/Riot/Assets/sq.lproj/Vector.strings @@ -14,7 +14,7 @@ "leave" = "Dilni"; "remove" = "Hiqe"; "invite" = "Ftoje"; -"retry" = "Riprovo"; +"retry" = "Riprovoni"; "off" = "Off"; "cancel" = "Anuloje"; "save" = "Ruaje"; @@ -2757,3 +2757,10 @@ "settings_manage_account_title" = "Llogari"; "settings_manage_account_action" = "Administroni llogari"; "manage_session_redirect" = "Do të ridrejtoheni te shërbimi i mirëfilltësimit të shërbyesit tuaj, për të plotësuar daljen nga llogaria."; +"room_action_report" = "Raportojeni dhomën"; +"room_action_report_prompt_reason" = "Arsye për raportimin e kësaj dhome"; + + +// MARK: - WYSIWYG Composer +"wysiwyg_composer_action_minimise_action" = "Tkurre hartuesin"; +"wysiwyg_composer_action_maximise_action" = "Zgjeroje hartuesin"; From ba178f44179fdec19fb6272254681cff7c3eca3a Mon Sep 17 00:00:00 2001 From: Linerly Date: Tue, 18 Jun 2024 12:17:47 +0000 Subject: [PATCH 71/79] Translated using Weblate (Indonesian) Currently translated at 100.0% (2420 of 2420 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/id/ --- Riot/Assets/id.lproj/Vector.strings | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Assets/id.lproj/Vector.strings b/Riot/Assets/id.lproj/Vector.strings index 5e8e1c027..a27d04098 100644 --- a/Riot/Assets/id.lproj/Vector.strings +++ b/Riot/Assets/id.lproj/Vector.strings @@ -2974,3 +2974,10 @@ "settings_manage_account_description" = "Kelola akun Anda di %@"; "manage_session_redirect" = "Anda akan dialihkan ke penyedia autentikasi server Anda untuk menyelesaikan proses keluar."; "manage_session_redirect_error" = "Fungsi saat ini tidak tersedia. Silakan hubungi admin homeserver Anda"; +"room_action_report_prompt_reason" = "Alasan melaporkan ruangan ini"; + + +// MARK: - WYSIWYG Composer +"wysiwyg_composer_action_minimise_action" = "Kecilkan komposer"; +"wysiwyg_composer_action_maximise_action" = "Luaskan komposer"; +"room_action_report" = "Laporkan ruangan"; From d8d292d6b251f7279e69a5280d565b2f68e9530d Mon Sep 17 00:00:00 2001 From: LinAGKar Date: Thu, 20 Jun 2024 18:47:02 +0000 Subject: [PATCH 72/79] Translated using Weblate (Swedish) Currently translated at 100.0% (2420 of 2420 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sv/ --- Riot/Assets/sv.lproj/Vector.strings | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Assets/sv.lproj/Vector.strings b/Riot/Assets/sv.lproj/Vector.strings index 85662f029..4ba032603 100644 --- a/Riot/Assets/sv.lproj/Vector.strings +++ b/Riot/Assets/sv.lproj/Vector.strings @@ -2714,3 +2714,10 @@ "settings_manage_account_description" = "Hantera ditt konto på %@"; "manage_session_redirect" = "Du kommer att omdirigeras till din servers autentiseringsleverantör för att fortsätta utloggning."; "manage_session_redirect_error" = "Funktion för närvarande otillgänglig. Vänligen kontakta din hemserveradministratör"; +"room_action_report" = "Rapportera rum"; +"room_action_report_prompt_reason" = "Anledning att rapportera det här rummet"; +"wysiwyg_composer_action_maximise_action" = "Expandera redigerare"; + + +// MARK: - WYSIWYG Composer +"wysiwyg_composer_action_minimise_action" = "Krymp redigerare"; From 6ed51f564d3ff77101dca9bd894483fea742e8eb Mon Sep 17 00:00:00 2001 From: Jozef Gaal Date: Wed, 26 Jun 2024 10:56:37 +0000 Subject: [PATCH 73/79] Translated using Weblate (Slovak) Currently translated at 100.0% (2420 of 2420 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/sk/ --- Riot/Assets/sk.lproj/Vector.strings | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Assets/sk.lproj/Vector.strings b/Riot/Assets/sk.lproj/Vector.strings index a18873e4d..5ad14f43f 100644 --- a/Riot/Assets/sk.lproj/Vector.strings +++ b/Riot/Assets/sk.lproj/Vector.strings @@ -2970,3 +2970,10 @@ "settings_manage_account_description" = "Spravujte svoj účet na %@"; "manage_session_redirect" = "Budete presmerovaní na poskytovateľa overovania vášho servera, aby ste dokončili odhlásenie."; "manage_session_redirect_error" = "Funkcia aktuálne nie je dostupná. Obráťte sa na správcu vášho domovského servera"; +"room_action_report_prompt_reason" = "Dôvod nahlásenia tejto miestnosti"; +"wysiwyg_composer_action_maximise_action" = "Rozšíriť editor"; +"room_action_report" = "Nahlásiť miestnosť"; + + +// MARK: - WYSIWYG Composer +"wysiwyg_composer_action_minimise_action" = "Zmenšiť editor"; From 1b0530141ed0006f244db854e8ed804c3927f41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Mesk=C3=B3?= Date: Fri, 28 Jun 2024 09:37:34 +0000 Subject: [PATCH 74/79] Translated using Weblate (Hungarian) Currently translated at 99.9% (2419 of 2420 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ --- Riot/Assets/hu.lproj/Vector.strings | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index 216ab88fd..bac644244 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -2478,9 +2478,9 @@ "user_sessions_settings" = "Munkamenetek kezelése"; "invite_to" = "Meghívó ide: %@"; "device_name_unknown" = "Ismeretlen kliens"; -"device_name_mobile" = "%@ Mobil"; -"device_name_desktop" = "%@ Alkalmazás"; -"device_name_web" = "%@ Web"; +"device_name_mobile" = "Mobilos %@"; +"device_name_desktop" = "Asztali %@"; +"device_name_web" = "Webes %@"; "user_session_item_details" = "%1$@ · %2$@"; // First item is client name and second item is session display name @@ -2528,19 +2528,19 @@ "user_session_details_device_os" = "Operációs rendszer"; "user_session_details_device_browser" = "Böngésző"; "user_session_details_device_model" = "Modell"; -"user_session_details_device_ip_location" = "Tartózkodási helyem"; +"user_session_details_device_ip_location" = "Saját tartózkodási hely"; "user_session_details_device_ip_address" = "IP cím"; "user_session_details_last_activity" = "Utolsó tevékenység"; -"user_session_details_session_section_footer" = "A másoláshoz koppints és tartsd rajta az ujjad."; -"user_session_details_session_id" = "Kapcsolat azonosító"; +"user_session_details_session_section_footer" = "A másoláshoz koppintson és tartsa lenyomva."; +"user_session_details_session_id" = "Kapcsolatazonosító"; "user_session_details_session_name" = "Munkamenet neve"; "user_session_details_device_section_header" = "Eszköz"; "user_session_details_application_section_header" = "Alkalmazás"; "user_session_details_session_section_header" = "Munkamenet"; -"user_session_details_title" = "Munkamenet információk"; +"user_session_details_title" = "Munkamenet-információk"; "device_type_name_unknown" = "Ismeretlen"; -"device_type_name_mobile" = "Mobil"; -"device_type_name_web" = "Web"; +"device_type_name_mobile" = "Mobilos"; +"device_type_name_web" = "Webes"; "device_type_name_desktop" = "Asztali"; "user_inactive_session_item_with_date" = "90+ napja inaktív (%@)"; "user_inactive_session_item" = "90+ napja inaktív"; @@ -2763,3 +2763,13 @@ "settings_manage_account_action" = "Fiók kezelése"; "settings_manage_account_description" = "A fiókja kezelése itt: %@"; "room_command_change_room_topic_description" = "Beállítja a szoba témáját"; +"room_action_report" = "Szoba jelentése"; +"room_action_report_prompt_reason" = "A szoba jelentésének oka"; + + +// MARK: - WYSIWYG Composer +"wysiwyg_composer_action_minimise_action" = "Szerkesztő összecsukása"; +"wysiwyg_composer_action_maximise_action" = "Szerkesztő kibontása"; +"room_command_set_user_power_level_description" = "Meghatározza a felhasználó szintjét"; +"room_command_reset_user_power_level_description" = "Elveszi az adott azonosítójú felhasználó operátori jogosultságát"; +"room_command_error_unknown_command" = "Érvénytelen vagy nem kezelt parancs"; From 64de16c1dd042bc235618db81b5616d866f1b841 Mon Sep 17 00:00:00 2001 From: Ihor Hordiichuk Date: Sun, 30 Jun 2024 12:53:35 +0000 Subject: [PATCH 75/79] Translated using Weblate (Ukrainian) Currently translated at 100.0% (2420 of 2420 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/uk/ --- Riot/Assets/uk.lproj/Vector.strings | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Assets/uk.lproj/Vector.strings b/Riot/Assets/uk.lproj/Vector.strings index 7c18d9f8b..0119a6575 100644 --- a/Riot/Assets/uk.lproj/Vector.strings +++ b/Riot/Assets/uk.lproj/Vector.strings @@ -2972,3 +2972,10 @@ "settings_manage_account_description" = "Керувати обліковим записом у %@"; "manage_session_redirect" = "Вас буде перенаправлено до постачальника автентифікації вашого сервера для завершення виходу."; "manage_session_redirect_error" = "Функціональність наразі недоступна. Зверніться до адміністратора вашого домашнього сервера"; +"wysiwyg_composer_action_maximise_action" = "Розгорнути редактор"; +"room_action_report" = "Поскаржитися на кімнату"; +"room_action_report_prompt_reason" = "Причина скарги на цю кімнату"; + + +// MARK: - WYSIWYG Composer +"wysiwyg_composer_action_minimise_action" = "Зменшити редактор"; From 8b467f3847c19f0c07935cad6b4d90fd91ff04f2 Mon Sep 17 00:00:00 2001 From: random Date: Sat, 13 Jul 2024 09:21:50 +0000 Subject: [PATCH 76/79] Translated using Weblate (Italian) Currently translated at 100.0% (2420 of 2420 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/it/ --- Riot/Assets/it.lproj/Vector.strings | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Riot/Assets/it.lproj/Vector.strings b/Riot/Assets/it.lproj/Vector.strings index 0e893b97c..55551cc09 100644 --- a/Riot/Assets/it.lproj/Vector.strings +++ b/Riot/Assets/it.lproj/Vector.strings @@ -2747,3 +2747,10 @@ "settings_manage_account_description" = "Gestisci il tuo account su %@"; "manage_session_redirect" = "Verrai reindirizzato al fornitore di autenticazione del tuo server per completare la disconnessione."; "manage_session_redirect_error" = "Funzionalità attualmente non disponibile. Contatta l'amministratore del tuo homeserver"; + + +// MARK: - WYSIWYG Composer +"wysiwyg_composer_action_minimise_action" = "Rimpicciolisci il compositore"; +"wysiwyg_composer_action_maximise_action" = "Espandi il compositore"; +"room_action_report" = "Segnala stanza"; +"room_action_report_prompt_reason" = "Motivo della segnalazione della stanza"; From 16862654ccea6d65906591120746c6ef1a6c2f3d Mon Sep 17 00:00:00 2001 From: simsononroad Date: Sun, 14 Jul 2024 11:22:12 +0000 Subject: [PATCH 77/79] Translated using Weblate (Hungarian) Currently translated at 99.9% (2419 of 2420 strings) Translation: Element iOS/Element iOS Translate-URL: https://translate.element.io/projects/riot-ios/riot-ios/hu/ --- Riot/Assets/hu.lproj/Vector.strings | 1 + 1 file changed, 1 insertion(+) diff --git a/Riot/Assets/hu.lproj/Vector.strings b/Riot/Assets/hu.lproj/Vector.strings index bac644244..8e324169f 100644 --- a/Riot/Assets/hu.lproj/Vector.strings +++ b/Riot/Assets/hu.lproj/Vector.strings @@ -2773,3 +2773,4 @@ "room_command_set_user_power_level_description" = "Meghatározza a felhasználó szintjét"; "room_command_reset_user_power_level_description" = "Elveszi az adott azonosítójú felhasználó operátori jogosultságát"; "room_command_error_unknown_command" = "Érvénytelen vagy nem kezelt parancs"; +"room_command_discard_session_description" = "Kényszeríti a titkosított szobában lévő aktuális kimenő csoportmunkamenet elvetését"; From 0eb6ba084e60e95fc14ceed3077612c64d4cc8b9 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 23 Jul 2024 13:41:51 +0200 Subject: [PATCH 78/79] version++ --- CHANGES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 907d69b54..11ffc2409 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,8 @@ +## Changes in 1.11.16 (2024-07-23) + +No significant changes. + + ## Changes in 1.11.15 (2024-06-18) No significant changes. From bbc74c1c8f556a3f289cca5a7aa597e8af2cc666 Mon Sep 17 00:00:00 2001 From: Mauro Romito Date: Tue, 23 Jul 2024 14:13:03 +0200 Subject: [PATCH 79/79] finish version++