mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-10-31 08:15:24 +00:00
121 lines
4.4 KiB
Swift
121 lines
4.4 KiB
Swift
//
|
|
// Copyright 2025 Element Creations Ltd.
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
|
// Please see LICENSE files in the repository root for full details.
|
|
//
|
|
|
|
import Combine
|
|
import Foundation
|
|
import MatrixRustSDK
|
|
|
|
/// A ``TimelineItemProviderMock`` subclass that optionally listens for ``UITestsSignalling`` signals
|
|
/// to drive pagination and incoming message simulation.
|
|
@MainActor
|
|
class SignallingTimelineItemProviderMock: TimelineItemProviderMock, @unchecked Sendable {
|
|
private let stateSubject: CurrentValueSubject<([TimelineItemProxy], TimelinePaginationState), Never>
|
|
|
|
/// An array of item arrays that will be prepended in order on each paginate signal.
|
|
var backPaginationResponses: [[TimelineItemProxy]] = []
|
|
/// An array of items that will be appended in order on each incoming message signal.
|
|
var incomingItems: [TimelineItemProxy] = []
|
|
|
|
private var client: UITestsSignalling.Client?
|
|
private var signalCancellable: AnyCancellable?
|
|
|
|
override nonisolated init() {
|
|
fatalError("Use init(itemProxies:paginationState:listenForSignals:) instead.")
|
|
}
|
|
|
|
init(itemProxies: [TimelineItemProxy] = [],
|
|
paginationState: TimelinePaginationState = .init(backward: .idle, forward: .endReached),
|
|
listenForSignals: Bool = false) {
|
|
stateSubject = CurrentValueSubject((itemProxies, paginationState))
|
|
|
|
super.init()
|
|
|
|
self.itemProxies = itemProxies
|
|
|
|
self.paginationState = paginationState
|
|
kind = .live
|
|
updatePublisher = stateSubject.eraseToAnyPublisher()
|
|
membershipChangePublisher = Empty().eraseToAnyPublisher()
|
|
|
|
guard listenForSignals else { return }
|
|
|
|
do {
|
|
let client = try UITestsSignalling.Client(mode: .app)
|
|
signalCancellable = client.signals.sink { [weak self] signal in
|
|
Task { @MainActor [weak self] in
|
|
guard let self else { return }
|
|
do {
|
|
try self.handleSignal(signal)
|
|
} catch {
|
|
MXLog.error(error.localizedDescription)
|
|
}
|
|
}
|
|
}
|
|
self.client = client
|
|
} catch {
|
|
fatalError("Failure setting up signalling: \(error)")
|
|
}
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private func handleSignal(_ signal: UITestsSignal) throws {
|
|
switch signal {
|
|
case .timeline(.paginate):
|
|
try simulateBackPagination()
|
|
case .timeline(.incomingMessage):
|
|
try simulateIncomingItem()
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
private func simulateIncomingItem() throws {
|
|
guard !incomingItems.isEmpty else { return }
|
|
let item = incomingItems.removeFirst()
|
|
let (items, paginationState) = stateSubject.value
|
|
let newItems = items + [item]
|
|
itemProxies = newItems
|
|
stateSubject.send((newItems, paginationState))
|
|
try client?.send(.success)
|
|
}
|
|
|
|
func inject(_ proxies: [TimelineItemProxy]) {
|
|
let (items, paginationState) = stateSubject.value
|
|
let newItems = items + proxies
|
|
itemProxies = newItems
|
|
stateSubject.send((newItems, paginationState))
|
|
}
|
|
|
|
func replaceLastItem(with proxy: TimelineItemProxy) {
|
|
var (items, paginationState) = stateSubject.value
|
|
guard !items.isEmpty else { return }
|
|
items[items.index(before: items.endIndex)] = proxy
|
|
itemProxies = items
|
|
stateSubject.send((items, paginationState))
|
|
}
|
|
|
|
private func simulateBackPagination() throws {
|
|
let (items, _) = stateSubject.value
|
|
|
|
guard !backPaginationResponses.isEmpty else {
|
|
let newState = TimelinePaginationState(backward: .endReached, forward: .endReached)
|
|
paginationState = newState
|
|
stateSubject.send((items, newState))
|
|
return
|
|
}
|
|
|
|
let newItems = backPaginationResponses.removeFirst()
|
|
let newPaginationState = TimelinePaginationState(backward: backPaginationResponses.isEmpty ? .endReached : .idle,
|
|
forward: .endReached)
|
|
itemProxies = newItems + items
|
|
paginationState = newPaginationState
|
|
stateSubject.send((newItems + items, newPaginationState))
|
|
try client?.send(.success)
|
|
}
|
|
}
|