mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-01 00:46:21 +00:00
f040964d3f
This will send the item to the rooms in order they were chosen and only deep link into the target room if single, otherwise it will just dismiss the forwarding screen after sending.
148 lines
5.5 KiB
Swift
148 lines
5.5 KiB
Swift
//
|
|
// Copyright 2025 Element Creations Ltd.
|
|
// Copyright 2022-2025 New Vector 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 SwiftUI
|
|
|
|
typealias MessageForwardingScreenViewModelType = StateStoreViewModel<MessageForwardingScreenViewState, MessageForwardingScreenViewAction>
|
|
|
|
class MessageForwardingScreenViewModel: MessageForwardingScreenViewModelType, MessageForwardingScreenViewModelProtocol {
|
|
private let forwardingItem: MessageForwardingItem
|
|
private let clientProxy: ClientProxyProtocol
|
|
private let roomSummaryProvider: RoomSummaryProviderProtocol
|
|
private let userIndicatorController: UserIndicatorControllerProtocol
|
|
|
|
private var actionsSubject: PassthroughSubject<MessageForwardingScreenViewModelAction, Never> = .init()
|
|
|
|
var actions: AnyPublisher<MessageForwardingScreenViewModelAction, Never> {
|
|
actionsSubject.eraseToAnyPublisher()
|
|
}
|
|
|
|
init(forwardingItem: MessageForwardingItem,
|
|
userSession: UserSessionProtocol,
|
|
roomSummaryProvider: RoomSummaryProviderProtocol,
|
|
userIndicatorController: UserIndicatorControllerProtocol) {
|
|
self.forwardingItem = forwardingItem
|
|
clientProxy = userSession.clientProxy
|
|
self.roomSummaryProvider = roomSummaryProvider
|
|
self.userIndicatorController = userIndicatorController
|
|
|
|
super.init(initialViewState: MessageForwardingScreenViewState(), mediaProvider: userSession.mediaProvider)
|
|
|
|
roomSummaryProvider.roomListPublisher
|
|
.receive(on: DispatchQueue.main)
|
|
.sink { [weak self] _ in
|
|
self?.updateRooms()
|
|
}
|
|
.store(in: &cancellables)
|
|
|
|
context.$viewState
|
|
.map(\.bindings.searchQuery)
|
|
.removeDuplicates()
|
|
.sink { [weak self] searchQuery in
|
|
if searchQuery.isEmpty {
|
|
self?.roomSummaryProvider.setFilter(.all(filters: []))
|
|
} else {
|
|
self?.roomSummaryProvider.setFilter(.search(query: searchQuery))
|
|
}
|
|
}
|
|
.store(in: &cancellables)
|
|
|
|
updateRooms()
|
|
}
|
|
|
|
override func process(viewAction: MessageForwardingScreenViewAction) {
|
|
switch viewAction {
|
|
case .cancel:
|
|
actionsSubject.send(.dismiss)
|
|
case .send:
|
|
Task { await forward() }
|
|
case .selectRoom(let roomID):
|
|
if let index = state.selectedRoomIDs.firstIndex(of: roomID) {
|
|
state.selectedRoomIDs.remove(at: index)
|
|
} else {
|
|
state.selectedRoomIDs.append(roomID)
|
|
}
|
|
case .reachedTop:
|
|
updateVisibleRange(edge: .top)
|
|
case .reachedBottom:
|
|
updateVisibleRange(edge: .bottom)
|
|
}
|
|
}
|
|
|
|
func stop() {
|
|
// This is a shared provider so we should reset the filtering when we are done with the view
|
|
roomSummaryProvider.setFilter(.all(filters: []))
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private func updateRooms() {
|
|
var rooms = [MessageForwardingRoom]()
|
|
|
|
for summary in roomSummaryProvider.roomListPublisher.value {
|
|
if summary.id == forwardingItem.roomID {
|
|
continue
|
|
}
|
|
|
|
rooms.append(.init(id: summary.id,
|
|
title: summary.name,
|
|
description: summary.roomListDescription,
|
|
avatar: summary.avatar))
|
|
}
|
|
|
|
state.rooms = rooms
|
|
}
|
|
|
|
/// The actual range values don't matter as long as they contain the lower
|
|
/// or upper bounds. updateVisibleRange is a hybrid API that powers both
|
|
/// sliding sync visible range update and list paginations
|
|
/// For lists other than the home screen one we don't care about visible ranges,
|
|
/// we just need the respective bounds to be there to trigger a next page load or
|
|
/// a reset to just one page
|
|
private func updateVisibleRange(edge: UIRectEdge) {
|
|
switch edge {
|
|
case .top:
|
|
roomSummaryProvider.updateVisibleRange(0..<0)
|
|
case .bottom:
|
|
let roomCount = roomSummaryProvider.roomListPublisher.value.count
|
|
roomSummaryProvider.updateVisibleRange(roomCount..<roomCount)
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
private func forward() async {
|
|
guard !state.selectedRoomIDs.isEmpty else {
|
|
fatalError()
|
|
}
|
|
|
|
var succeededRoomIdentifiers = [String]()
|
|
|
|
for roomID in state.selectedRoomIDs {
|
|
guard case let .joined(targetRoomProxy) = await clientProxy.roomForIdentifier(roomID) else {
|
|
MXLog.error("Failed retrieving room to forward to with id: \(roomID)")
|
|
userIndicatorController.submitIndicator(UserIndicator(title: L10n.errorUnknown))
|
|
continue
|
|
}
|
|
|
|
if case .failure(let error) = await targetRoomProxy.timeline.sendMessageEventContent(forwardingItem.content) {
|
|
MXLog.error("Failed forwarding message with error: \(error)")
|
|
userIndicatorController.submitIndicator(UserIndicator(title: L10n.errorUnknown))
|
|
continue
|
|
}
|
|
|
|
succeededRoomIdentifiers.append(roomID)
|
|
}
|
|
|
|
if !succeededRoomIdentifiers.isEmpty {
|
|
actionsSubject.send(.sent(roomIDs: succeededRoomIdentifiers))
|
|
}
|
|
}
|
|
}
|