RoomScreenViewModel is now TimelineViewModel (#3157)

Co-authored-by: Stefan Ceriu <stefanc@matrix.org>
This commit is contained in:
Mauro
2024-08-13 13:36:40 +02:00
committed by GitHub
parent 4519275559
commit 1ad361a6e8
88 changed files with 2266 additions and 1973 deletions
@@ -50,22 +50,22 @@ class ComposerToolbarViewModelTests: XCTestCase {
}
func testComposerFocus() {
viewModel.process(roomAction: .setMode(mode: .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))))
viewModel.process(timelineAction: .setMode(mode: .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))))
XCTAssertTrue(viewModel.state.bindings.composerFocused)
viewModel.process(roomAction: .removeFocus)
viewModel.process(timelineAction: .removeFocus)
XCTAssertFalse(viewModel.state.bindings.composerFocused)
}
func testComposerMode() {
let mode: RoomScreenComposerMode = .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))
viewModel.process(roomAction: .setMode(mode: mode))
let mode: ComposerMode = .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))
viewModel.process(timelineAction: .setMode(mode: mode))
XCTAssertEqual(viewModel.state.composerMode, mode)
viewModel.process(roomAction: .clear)
viewModel.process(timelineAction: .clear)
XCTAssertEqual(viewModel.state.composerMode, .default)
}
func testComposerModeIsPublished() {
let mode: RoomScreenComposerMode = .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))
let mode: ComposerMode = .edit(originalItemId: TimelineItemIdentifier(timelineID: "mock"))
let expectation = expectation(description: "Composer mode is published")
let cancellable = viewModel
.context
@@ -78,7 +78,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
expectation.fulfill()
})
viewModel.process(roomAction: .setMode(mode: mode))
viewModel.process(timelineAction: .setMode(mode: mode))
wait(for: [expectation], timeout: 2.0)
cancellable.cancel()
@@ -206,7 +206,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
viewModel.context.composerFormattingEnabled = false
viewModel.context.plainComposerText = .init(string: "Hello world!")
viewModel.process(roomAction: .saveDraft)
viewModel.saveDraft()
await fulfillment(of: [expectation], timeout: 10)
XCTAssertEqual(draftServiceMock.saveDraftCallsCount, 1)
@@ -226,7 +226,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
viewModel.context.composerFormattingEnabled = true
wysiwygViewModel.setHtmlContent("<strong>Hello</strong> world!")
viewModel.process(roomAction: .saveDraft)
viewModel.saveDraft()
await fulfillment(of: [expectation], timeout: 10)
XCTAssertEqual(draftServiceMock.saveDraftCallsCount, 1)
@@ -245,9 +245,9 @@ class ComposerToolbarViewModelTests: XCTestCase {
}
viewModel.context.composerFormattingEnabled = false
viewModel.process(roomAction: .setMode(mode: .edit(originalItemId: .init(timelineID: "", eventID: "testID"))))
viewModel.process(timelineAction: .setMode(mode: .edit(originalItemId: .init(timelineID: "", eventID: "testID"))))
viewModel.context.plainComposerText = .init(string: "Hello world!")
viewModel.process(roomAction: .saveDraft)
viewModel.saveDraft()
await fulfillment(of: [expectation], timeout: 10)
XCTAssertEqual(draftServiceMock.saveDraftCallsCount, 1)
@@ -266,14 +266,14 @@ class ComposerToolbarViewModelTests: XCTestCase {
}
viewModel.context.composerFormattingEnabled = false
viewModel.process(roomAction: .setMode(mode: .reply(itemID: .init(timelineID: "",
eventID: "testID"),
viewModel.process(timelineAction: .setMode(mode: .reply(itemID: .init(timelineID: "",
eventID: "testID"),
replyDetails: .loaded(sender: .init(id: ""),
eventID: "testID",
eventContent: .message(.text(.init(body: "reply text")))),
isThread: false)))
viewModel.context.plainComposerText = .init(string: "Hello world!")
viewModel.process(roomAction: .saveDraft)
viewModel.saveDraft()
await fulfillment(of: [expectation], timeout: 10)
XCTAssertEqual(draftServiceMock.saveDraftCallsCount, 1)
@@ -292,13 +292,13 @@ class ComposerToolbarViewModelTests: XCTestCase {
}
viewModel.context.composerFormattingEnabled = false
viewModel.process(roomAction: .setMode(mode: .reply(itemID: .init(timelineID: "",
eventID: "testID"),
viewModel.process(timelineAction: .setMode(mode: .reply(itemID: .init(timelineID: "",
eventID: "testID"),
replyDetails: .loaded(sender: .init(id: ""),
eventID: "testID",
eventContent: .message(.text(.init(body: "reply text")))),
isThread: false)))
viewModel.process(roomAction: .saveDraft)
viewModel.saveDraft()
await fulfillment(of: [expectation], timeout: 10)
XCTAssertEqual(draftServiceMock.saveDraftCallsCount, 1)
@@ -314,7 +314,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
}
viewModel.context.composerFormattingEnabled = false
viewModel.process(roomAction: .saveDraft)
viewModel.saveDraft()
await fulfillment(of: [expectation], timeout: 10)
XCTAssertFalse(draftServiceMock.saveDraftCalled)
@@ -332,8 +332,8 @@ class ComposerToolbarViewModelTests: XCTestCase {
viewModel.context.composerFormattingEnabled = false
let waveformData: [Float] = Array(repeating: 1.0, count: 1000)
viewModel.context.plainComposerText = .init(string: "Hello world!")
viewModel.process(roomAction: .setMode(mode: .previewVoiceMessage(state: AudioPlayerState(id: .recorderPreview, duration: 10.0), waveform: .data(waveformData), isUploading: false)))
viewModel.process(roomAction: .saveDraft)
viewModel.process(timelineAction: .setMode(mode: .previewVoiceMessage(state: AudioPlayerState(id: .recorderPreview, duration: 10.0), waveform: .data(waveformData), isUploading: false)))
viewModel.saveDraft()
await fulfillment(of: [expectation], timeout: 10)
XCTAssertFalse(draftServiceMock.saveDraftCalled)
@@ -349,7 +349,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
return .success(nil)
}
viewModel.process(roomAction: .loadDraft)
viewModel.loadDraft()
await fulfillment(of: [expectation], timeout: 10)
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
XCTAssertTrue(viewModel.state.composerEmpty)
@@ -365,7 +365,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
htmlText: nil,
draftType: .newMessage))
}
viewModel.process(roomAction: .loadDraft)
viewModel.loadDraft()
await fulfillment(of: [expectation], timeout: 10)
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
@@ -382,7 +382,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
htmlText: "<strong>Hello</strong> world!",
draftType: .newMessage))
}
viewModel.process(roomAction: .loadDraft)
viewModel.loadDraft()
await fulfillment(of: [expectation], timeout: 10)
XCTAssertTrue(viewModel.context.composerFormattingEnabled)
@@ -400,7 +400,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
htmlText: nil,
draftType: .edit(eventID: "testID")))
}
viewModel.process(roomAction: .loadDraft)
viewModel.loadDraft()
await fulfillment(of: [expectation], timeout: 10)
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
@@ -433,7 +433,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
return .success(.init(details: loadedReply,
isThreaded: true))
}
viewModel.process(roomAction: .loadDraft)
viewModel.loadDraft()
await fulfillment(of: [draftExpectation], timeout: 10)
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
@@ -474,7 +474,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
return .success(.init(details: loadedReply,
isThreaded: true))
}
viewModel.process(roomAction: .loadDraft)
viewModel.loadDraft()
await fulfillment(of: [draftExpectation], timeout: 10)
XCTAssertFalse(viewModel.context.composerFormattingEnabled)
@@ -493,7 +493,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
func testSaveVolatileDraftWhenEditing() {
viewModel.context.composerFormattingEnabled = false
viewModel.context.plainComposerText = .init(string: "Hello world!")
viewModel.process(roomAction: .setMode(mode: .edit(originalItemId: .random)))
viewModel.process(timelineAction: .setMode(mode: .edit(originalItemId: .random)))
let draft = draftServiceMock.saveVolatileDraftReceivedDraft
XCTAssertNotNil(draft)
@@ -530,7 +530,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
expectation2.fulfill()
}
viewModel.process(roomAction: .clear)
viewModel.process(timelineAction: .clear)
await fulfillment(of: [expectation1, expectation2])
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: "Hello world"))
}
@@ -549,7 +549,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
expectation2.fulfill()
}
viewModel.process(roomAction: .clear)
viewModel.process(timelineAction: .clear)
await fulfillment(of: [expectation1, expectation2])
XCTAssertEqual(viewModel.context.plainComposerText, NSAttributedString(string: "Hello world"))
}
@@ -557,7 +557,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
func testRestoreUserMentionInPlainText() async throws {
viewModel.context.composerFormattingEnabled = false
let text = "Hello [TestName](https://matrix.to/#/@test:matrix.org)!"
viewModel.process(roomAction: .setText(plainText: text, htmlText: nil))
viewModel.process(timelineAction: .setText(plainText: text, htmlText: nil))
let deferred = deferFulfillment(viewModel.actions) { action in
switch action {
@@ -577,7 +577,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
func testRestoreAllUsersMentionInPlainText() async throws {
viewModel.context.composerFormattingEnabled = false
let text = "Hello @room"
viewModel.process(roomAction: .setText(plainText: text, htmlText: nil))
viewModel.process(timelineAction: .setText(plainText: text, htmlText: nil))
let deferred = deferFulfillment(viewModel.actions) { action in
switch action {
@@ -596,7 +596,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
func testRestoreMixedMentionsInPlainText() async throws {
viewModel.context.composerFormattingEnabled = false
let text = "Hello [User1](https://matrix.to/#/@user1:matrix.org), [User2](https://matrix.to/#/@user2:matrix.org) and @room"
viewModel.process(roomAction: .setText(plainText: text, htmlText: nil))
viewModel.process(timelineAction: .setText(plainText: text, htmlText: nil))
let deferred = deferFulfillment(viewModel.actions) { action in
switch action {
@@ -616,7 +616,7 @@ class ComposerToolbarViewModelTests: XCTestCase {
func testRestoreAmbiguousMention() async throws {
viewModel.context.composerFormattingEnabled = false
let text = "Hello [User1](https://matrix.to/#/@roomuser:matrix.org)"
viewModel.process(roomAction: .setText(plainText: text, htmlText: nil))
viewModel.process(timelineAction: .setText(plainText: text, htmlText: nil))
let deferred = deferFulfillment(viewModel.actions) { action in
switch action {
+30 -30
View File
@@ -26,16 +26,16 @@ class PillContextTests: XCTestCase {
let proxyMock = RoomProxyMock(.init(name: "Test"))
let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([])
proxyMock.membersPublisher = subject.asCurrentValuePublisher()
let mock = RoomScreenViewModel(roomProxy: proxyMock,
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
let context = PillContext(roomContext: mock.context, data: PillTextAttachmentData(type: .user(userID: id), font: .preferredFont(forTextStyle: .body)))
let mock = TimelineViewModel(roomProxy: proxyMock,
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .user(userID: id), font: .preferredFont(forTextStyle: .body)))
XCTAssertFalse(context.viewState.isOwnMention)
XCTAssertEqual(context.viewState.displayText, id)
@@ -54,16 +54,16 @@ class PillContextTests: XCTestCase {
let proxyMock = RoomProxyMock(.init(name: "Test", ownUserID: id))
let subject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([])
proxyMock.membersPublisher = subject.asCurrentValuePublisher()
let mock = RoomScreenViewModel(roomProxy: proxyMock,
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
let context = PillContext(roomContext: mock.context, data: PillTextAttachmentData(type: .user(userID: id), font: .preferredFont(forTextStyle: .body)))
let mock = TimelineViewModel(roomProxy: proxyMock,
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .user(userID: id), font: .preferredFont(forTextStyle: .body)))
XCTAssertTrue(context.viewState.isOwnMention)
}
@@ -75,16 +75,16 @@ class PillContextTests: XCTestCase {
let proxyMock = RoomProxyMock(.init(id: id, name: displayName, avatarURL: avatarURL))
let mockController = MockRoomTimelineController()
mockController.roomProxy = proxyMock
let mock = RoomScreenViewModel(roomProxy: proxyMock,
timelineController: mockController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
let context = PillContext(roomContext: mock.context, data: PillTextAttachmentData(type: .allUsers, font: .preferredFont(forTextStyle: .body)))
let mock = TimelineViewModel(roomProxy: proxyMock,
timelineController: mockController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: ServiceLocator.shared.userIndicatorController,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
let context = PillContext(timelineContext: mock.context, data: PillTextAttachmentData(type: .allUsers, font: .preferredFont(forTextStyle: .body)))
XCTAssertTrue(context.viewState.isOwnMention)
XCTAssertEqual(context.viewState.displayText, PillConstants.atRoom)
@@ -20,7 +20,7 @@ import Combine
import XCTest
@MainActor
class RoomScreenViewModelTests: XCTestCase {
class TimelineViewModelTests: XCTestCase {
var userIndicatorControllerMock: UserIndicatorControllerMock!
var cancellables = Set<AnyCancellable>()
@@ -327,7 +327,7 @@ class RoomScreenViewModelTests: XCTestCase {
// swiftlint:enable force_unwrapping
// swiftlint:disable:next large_tuple
private func readReceiptsConfiguration(with items: [RoomTimelineItemProtocol]) -> (RoomScreenViewModel,
private func readReceiptsConfiguration(with items: [RoomTimelineItemProtocol]) -> (TimelineViewModel,
RoomProxyMock,
TimelineProxyMock,
MockRoomTimelineController) {
@@ -343,15 +343,15 @@ class RoomScreenViewModelTests: XCTestCase {
timelineController.timelineItems = items
timelineController.roomProxy = roomProxy
let viewModel = RoomScreenViewModel(roomProxy: roomProxy,
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: userIndicatorControllerMock,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
let viewModel = TimelineViewModel(roomProxy: roomProxy,
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: userIndicatorControllerMock,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
return (viewModel, roomProxy, timelineProxy, timelineController)
}
@@ -367,15 +367,15 @@ class RoomScreenViewModelTests: XCTestCase {
// When showing them in a timeline.
let timelineController = MockRoomTimelineController()
timelineController.timelineItems = [message]
let viewModel = RoomScreenViewModel(roomProxy: RoomProxyMock(.init(name: "", members: [RoomMemberProxyMock.mockAlice, RoomMemberProxyMock.mockCharlie])),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: userIndicatorControllerMock,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
let viewModel = TimelineViewModel(roomProxy: RoomProxyMock(.init(name: "", members: [RoomMemberProxyMock.mockAlice, RoomMemberProxyMock.mockCharlie])),
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: userIndicatorControllerMock,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
let deferred = deferFulfillment(viewModel.context.$viewState) { value in
value.bindings.readReceiptsSummaryInfo?.orderedReceipts == receipts
@@ -389,17 +389,17 @@ class RoomScreenViewModelTests: XCTestCase {
private func makeViewModel(roomProxy: RoomProxyProtocol? = nil,
focussedEventID: String? = nil,
timelineController: RoomTimelineControllerProtocol) -> RoomScreenViewModel {
RoomScreenViewModel(roomProxy: roomProxy ?? RoomProxyMock(.init(name: "")),
focussedEventID: focussedEventID,
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: userIndicatorControllerMock,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
timelineController: RoomTimelineControllerProtocol) -> TimelineViewModel {
TimelineViewModel(roomProxy: roomProxy ?? RoomProxyMock(.init(name: "")),
focussedEventID: focussedEventID,
timelineController: timelineController,
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
userIndicatorController: userIndicatorControllerMock,
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics)
}
}