Add TimelineProxy (update sdk to 0.0.7-november23) (#2178)

* Refactor RoomProxy

* Refactor paginateBackwards

* Refactor sendReadReceipt

* Refactor messageEventContent APIs

* Refactor sendMessage

* Refactor toggleReaction

* Refactor send attachments

* Refactor sendLocation

* Refactor cancel/retry send

* ⚠️ Fix encryption build errors

* Refactor editMessage

* Refactor retryDecryption

* Refactor fetchDetails

* Refactor polls APIs

* Refactor fetchMembers

* Refactor RoomTimelineProviderProtocol

* Update sdk to 0.0.7-november23

* Fix UTs

* Fix comment

* Delete old workaround

* Move TimelineProxyError

* Delete queue warnings

* Fix key listener

* Add pollHistory timeline property

* Refactor room/timeline subscriptions

* Delete unused code
This commit is contained in:
Alfonso Grillo
2023-11-28 20:01:35 +01:00
committed by GitHub
parent fb2bc1c39a
commit e7494164b2
18 changed files with 1212 additions and 1085 deletions
@@ -332,6 +332,8 @@ class RoomScreenViewModelTests: XCTestCase {
func testRetrySend() async throws {
let timelineController = MockRoomTimelineController()
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
let timelineProxy = TimelineProxyMock()
roomProxyMock.timeline = timelineProxy
timelineController.roomProxy = roomProxyMock
let viewModel = RoomScreenViewModel(roomProxy: roomProxyMock,
@@ -349,13 +351,15 @@ class RoomScreenViewModelTests: XCTestCase {
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(roomProxyMock.retrySendTransactionIDCallsCount == 1)
XCTAssert(roomProxyMock.retrySendTransactionIDReceivedInvocations == ["test retry send id"])
XCTAssert(timelineProxy.retrySendTransactionIDCallsCount == 1)
XCTAssert(timelineProxy.retrySendTransactionIDReceivedInvocations == ["test retry send id"])
}
func testRetrySendNoTransactionID() async {
let timelineController = MockRoomTimelineController()
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
let timelineProxy = TimelineProxyMock()
roomProxyMock.timeline = timelineProxy
let viewModel = RoomScreenViewModel(roomProxy: roomProxyMock,
timelineController: timelineController,
@@ -372,12 +376,14 @@ class RoomScreenViewModelTests: XCTestCase {
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(roomProxyMock.retrySendTransactionIDCallsCount == 0)
XCTAssert(timelineProxy.retrySendTransactionIDCallsCount == 0)
}
func testCancelSend() async {
let timelineController = MockRoomTimelineController()
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
let timelineProxy = TimelineProxyMock()
roomProxyMock.timeline = timelineProxy
timelineController.roomProxy = roomProxyMock
let viewModel = RoomScreenViewModel(roomProxy: roomProxyMock,
@@ -395,13 +401,15 @@ class RoomScreenViewModelTests: XCTestCase {
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(roomProxyMock.cancelSendTransactionIDCallsCount == 1)
XCTAssert(roomProxyMock.cancelSendTransactionIDReceivedInvocations == ["test cancel send id"])
XCTAssert(timelineProxy.cancelSendTransactionIDCallsCount == 1)
XCTAssert(timelineProxy.cancelSendTransactionIDReceivedInvocations == ["test cancel send id"])
}
func testCancelSendNoTransactionID() async {
let timelineController = MockRoomTimelineController()
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
let timelineProxy = TimelineProxyMock()
roomProxyMock.timeline = timelineProxy
let viewModel = RoomScreenViewModel(roomProxy: roomProxyMock,
timelineController: timelineController,
@@ -418,7 +426,7 @@ class RoomScreenViewModelTests: XCTestCase {
try? await Task.sleep(for: .milliseconds(100))
XCTAssert(roomProxyMock.cancelSendTransactionIDCallsCount == 0)
XCTAssert(timelineProxy.cancelSendTransactionIDCallsCount == 0)
}
// MARK: - Read Receipts
@@ -429,15 +437,15 @@ class RoomScreenViewModelTests: XCTestCase {
let items = [TextRoomTimelineItem(eventID: "t1"),
TextRoomTimelineItem(eventID: "t2"),
TextRoomTimelineItem(eventID: "t3")]
let (viewModel, roomProxy, _, notificationCenter) = readReceiptsConfiguration(with: items)
let (viewModel, roomProxy, timelineProxy, _, notificationCenter) = readReceiptsConfiguration(with: items)
// When sending a read receipt for the last item.
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .milliseconds(100))
// Then the receipt should be sent.
XCTAssertEqual(roomProxy.sendReadReceiptForCalled, true)
XCTAssertEqual(roomProxy.sendReadReceiptForReceivedEventID, "t3")
XCTAssertEqual(timelineProxy.sendReadReceiptForCalled, true)
XCTAssertEqual(timelineProxy.sendReadReceiptForReceivedEventID, "t3")
// And the notifications should be cleared.
XCTAssertEqual(notificationCenter.postNameObjectReceivedArguments?.aName, .roomMarkedAsRead)
@@ -450,19 +458,19 @@ class RoomScreenViewModelTests: XCTestCase {
let items = [TextRoomTimelineItem(eventID: "t1"),
TextRoomTimelineItem(eventID: "t2"),
TextRoomTimelineItem(eventID: "t3")]
let (viewModel, roomProxy, timelineController, _) = readReceiptsConfiguration(with: items)
let (viewModel, _, timelineProxy, timelineController, _) = readReceiptsConfiguration(with: items)
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .milliseconds(100))
XCTAssertEqual(roomProxy.sendReadReceiptForCallsCount, 1)
XCTAssertEqual(roomProxy.sendReadReceiptForReceivedEventID, "t3")
XCTAssertEqual(timelineProxy.sendReadReceiptForCallsCount, 1)
XCTAssertEqual(timelineProxy.sendReadReceiptForReceivedEventID, "t3")
// When sending a receipt for the first item in the timeline.
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.first!.id))
try await Task.sleep(for: .milliseconds(100))
// Then the request should be ignored.
XCTAssertEqual(roomProxy.sendReadReceiptForCallsCount, 1)
XCTAssertEqual(roomProxy.sendReadReceiptForReceivedEventID, "t3")
XCTAssertEqual(timelineProxy.sendReadReceiptForCallsCount, 1)
XCTAssertEqual(timelineProxy.sendReadReceiptForReceivedEventID, "t3")
// When a new message is received and marked as read.
let newMessage = TextRoomTimelineItem(eventID: "t4")
@@ -474,8 +482,8 @@ class RoomScreenViewModelTests: XCTestCase {
try await Task.sleep(for: .milliseconds(100))
// Then the request should be made.
XCTAssertEqual(roomProxy.sendReadReceiptForCallsCount, 2)
XCTAssertEqual(roomProxy.sendReadReceiptForReceivedEventID, "t4")
XCTAssertEqual(timelineProxy.sendReadReceiptForCallsCount, 2)
XCTAssertEqual(timelineProxy.sendReadReceiptForReceivedEventID, "t4")
}
func testSendReadReceiptWithoutEvents() async throws {
@@ -483,14 +491,14 @@ class RoomScreenViewModelTests: XCTestCase {
let items = [SeparatorRoomTimelineItem(timelineID: "v1"),
SeparatorRoomTimelineItem(timelineID: "v2"),
SeparatorRoomTimelineItem(timelineID: "v3")]
let (viewModel, roomProxy, _, _) = readReceiptsConfiguration(with: items)
let (viewModel, _, timelineProxy, _, _) = readReceiptsConfiguration(with: items)
// When sending a read receipt for the last item.
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .milliseconds(100))
// Then nothing should be sent.
XCTAssertEqual(roomProxy.sendReadReceiptForCalled, false)
XCTAssertEqual(timelineProxy.sendReadReceiptForCalled, false)
}
func testSendReadReceiptVirtualLast() async throws {
@@ -498,15 +506,15 @@ class RoomScreenViewModelTests: XCTestCase {
let items: [RoomTimelineItemProtocol] = [TextRoomTimelineItem(eventID: "t1"),
TextRoomTimelineItem(eventID: "t2"),
SeparatorRoomTimelineItem(timelineID: "v3")]
let (viewModel, roomProxy, _, _) = readReceiptsConfiguration(with: items)
let (viewModel, _, timelineProxy, _, _) = readReceiptsConfiguration(with: items)
// When sending a read receipt for the last item.
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .milliseconds(100))
// Then a read receipt should be sent for the item before it.
XCTAssertEqual(roomProxy.sendReadReceiptForCalled, true)
XCTAssertEqual(roomProxy.sendReadReceiptForReceivedEventID, "t2")
XCTAssertEqual(timelineProxy.sendReadReceiptForCalled, true)
XCTAssertEqual(timelineProxy.sendReadReceiptForReceivedEventID, "t2")
}
func testSendReadReceiptMultipleRequests() async throws {
@@ -514,31 +522,34 @@ class RoomScreenViewModelTests: XCTestCase {
let items: [RoomTimelineItemProtocol] = [TextRoomTimelineItem(eventID: "t1"),
TextRoomTimelineItem(eventID: "t2"),
SeparatorRoomTimelineItem(timelineID: "v3")]
let (viewModel, roomProxy, _, _) = readReceiptsConfiguration(with: items)
let (viewModel, _, timelineProxy, _, _) = readReceiptsConfiguration(with: items)
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .milliseconds(100))
XCTAssertEqual(roomProxy.sendReadReceiptForCallsCount, 1)
XCTAssertEqual(roomProxy.sendReadReceiptForReceivedEventID, "t2")
XCTAssertEqual(timelineProxy.sendReadReceiptForCallsCount, 1)
XCTAssertEqual(timelineProxy.sendReadReceiptForReceivedEventID, "t2")
// When sending the same receipt again
viewModel.context.send(viewAction: .sendReadReceiptIfNeeded(items.last!.id))
try await Task.sleep(for: .milliseconds(100))
// Then the second call should be ignored.
XCTAssertEqual(roomProxy.sendReadReceiptForCallsCount, 1)
XCTAssertEqual(timelineProxy.sendReadReceiptForCallsCount, 1)
}
// swiftlint:enable force_unwrapping
// swiftlint:disable:next large_tuple
private func readReceiptsConfiguration(with items: [RoomTimelineItemProtocol]) -> (RoomScreenViewModel,
RoomProxyMock,
TimelineProxyMock,
MockRoomTimelineController,
NotificationCenterMock) {
let notificationCenter = NotificationCenterMock()
let roomProxy = RoomProxyMock(with: .init(displayName: ""))
let timelineProxy = TimelineProxyMock()
roomProxy.timeline = timelineProxy
let timelineController = MockRoomTimelineController()
roomProxy.sendReadReceiptForReturnValue = .success(())
timelineProxy.sendReadReceiptForReturnValue = .success(())
roomProxy.underlyingHasUnreadNotifications = true
timelineController.timelineItems = items
timelineController.roomProxy = roomProxy
@@ -554,7 +565,7 @@ class RoomScreenViewModelTests: XCTestCase {
analyticsService: ServiceLocator.shared.analytics,
notificationCenter: notificationCenter)
return (viewModel, roomProxy, timelineController, notificationCenter)
return (viewModel, roomProxy, timelineProxy, timelineController, notificationCenter)
}
func testShowReadReceipts() async throws {
@@ -237,8 +237,10 @@ class VoiceMessageRecorderTests: XCTestCase {
try? FileManager.default.removeItem(at: destination)
}
let timelineProxy = TimelineProxyMock()
let roomProxy = RoomProxyMock()
roomProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleReturnValue = .failure(.failedSendingMedia)
roomProxy.timeline = timelineProxy
timelineProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleReturnValue = .failure(.failedSendingMedia)
guard case .failure(.failedSendingVoiceMessage) = await voiceMessageRecorder.sendVoiceMessage(inRoom: roomProxy, audioConverter: audioConverter) else {
XCTFail("An error is expected")
return
@@ -256,8 +258,10 @@ class VoiceMessageRecorderTests: XCTestCase {
try? FileManager.default.copyItem(at: imageFileURL, to: destination)
}
let timelineProxy = TimelineProxyMock()
let roomProxy = RoomProxyMock()
roomProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleReturnValue = .failure(.failedSendingMedia)
roomProxy.timeline = timelineProxy
timelineProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleReturnValue = .failure(.failedSendingMedia)
guard case .failure(.failedSendingVoiceMessage) = await voiceMessageRecorder.sendVoiceMessage(inRoom: roomProxy, audioConverter: audioConverter) else {
XCTFail("An error is expected")
return
@@ -277,8 +281,10 @@ class VoiceMessageRecorderTests: XCTestCase {
}
// If the media upload fails
let timelineProxy = TimelineProxyMock()
let roomProxy = RoomProxyMock()
roomProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleReturnValue = .failure(.failedSendingMedia)
roomProxy.timeline = timelineProxy
timelineProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleReturnValue = .failure(.failedSendingMedia)
guard case .failure(.failedSendingVoiceMessage) = await voiceMessageRecorder.sendVoiceMessage(inRoom: roomProxy, audioConverter: audioConverter) else {
XCTFail("An error is expected")
return
@@ -291,7 +297,9 @@ class VoiceMessageRecorderTests: XCTestCase {
return
}
let timelineProxy = TimelineProxyMock()
let roomProxy = RoomProxyMock()
roomProxy.timeline = timelineProxy
audioRecorder.currentTime = 42
audioRecorder.audioFileURL = imageFileURL
_ = await voiceMessageRecorder.startRecording()
@@ -312,7 +320,7 @@ class VoiceMessageRecorderTests: XCTestCase {
XCTAssertEqual(destination.pathExtension, "ogg")
}
roomProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleClosure = { url, audioInfo, waveform, _, _ in
timelineProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleClosure = { url, audioInfo, waveform, _, _ in
XCTAssertEqual(url, convertedFileURL)
XCTAssertEqual(audioInfo.duration, self.audioRecorder.currentTime)
XCTAssertEqual(audioInfo.size, convertedFileSize)
@@ -328,7 +336,7 @@ class VoiceMessageRecorderTests: XCTestCase {
}
XCTAssert(audioConverter.convertToOpusOggSourceURLDestinationURLCalled)
XCTAssert(roomProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleCalled)
XCTAssert(timelineProxy.sendVoiceMessageUrlAudioInfoWaveformProgressSubjectRequestHandleCalled)
// the converted file must have been deleted
if let convertedFileURL {