mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-04 01:20:12 +00:00
Room's details edit screen (#956)
* Add RoomDetailsEditScreen template * Add navigation to the edit screen * Delete template code * Start RoomDetailsEditScreen UI * Manage power levels in RoomDetailsScreen * Start RoomDetailsEditScreenViewModel logic * Inject initial room state * Add cancel action * Expose set name/topic APIs in RoomProxy * Refine RoomDetailsEditScreen UI * Add save logic * Add localisations * Fix avatar image * Update localisations * Add “Add topic” button * Add feature flag * Add dismiss on save logic * Reduce throttling * Improve form logic * Fix UT build errors * Add media sheet * Add media preprocessing * Add LoadableEditableAvatarImage * Add condition on delete image * Add avatar save button logic * Add remove avatar logic * Cleanup * Fix edit bug in DM * Add upload avatar * Add focus * Add RoomDetailsViewModel UTs * Fix button style * Add UTs * Add empty topic ui test * Fix iPad sheet presentation * Revert topic appearance in room’s details * Address PR comments * Add UI tests
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
//
|
||||
// Copyright 2022 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 Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias RoomDetailsEditScreenViewModelType = StateStoreViewModel<RoomDetailsEditScreenViewState, RoomDetailsEditScreenViewAction>
|
||||
|
||||
class RoomDetailsEditScreenViewModel: RoomDetailsEditScreenViewModelType, RoomDetailsEditScreenViewModelProtocol {
|
||||
private let actionsSubject: PassthroughSubject<RoomDetailsEditScreenViewModelAction, Never> = .init()
|
||||
private let roomProxy: RoomProxyProtocol
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
private let mediaPreprocessor: MediaUploadingPreprocessor = .init()
|
||||
|
||||
var actions: AnyPublisher<RoomDetailsEditScreenViewModelAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(accountOwner: RoomMemberProxyProtocol,
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
roomProxy: RoomProxyProtocol,
|
||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
||||
self.roomProxy = roomProxy
|
||||
self.userIndicatorController = userIndicatorController
|
||||
|
||||
let roomAvatar = roomProxy.avatarURL
|
||||
let roomName = roomProxy.name
|
||||
let roomTopic = roomProxy.topic
|
||||
|
||||
super.init(initialViewState: RoomDetailsEditScreenViewState(roomID: roomProxy.id,
|
||||
initialAvatarURL: roomAvatar,
|
||||
initialName: roomName ?? "",
|
||||
initialTopic: roomTopic ?? "",
|
||||
canEditAvatar: accountOwner.canSendStateEvent(type: .roomAvatar),
|
||||
canEditName: accountOwner.canSendStateEvent(type: .roomName),
|
||||
canEditTopic: accountOwner.canSendStateEvent(type: .roomTopic),
|
||||
avatarURL: roomAvatar,
|
||||
bindings: .init(name: roomName ?? "", topic: roomTopic ?? "")), imageProvider: mediaProvider)
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
override func process(viewAction: RoomDetailsEditScreenViewAction) {
|
||||
switch viewAction {
|
||||
case .cancel:
|
||||
actionsSubject.send(.cancel)
|
||||
case .save:
|
||||
saveRoomDetails()
|
||||
case .presentMediaSource:
|
||||
state.bindings.showMediaSheet = true
|
||||
case .displayCameraPicker:
|
||||
actionsSubject.send(.displayCameraPicker)
|
||||
case .displayMediaPicker:
|
||||
actionsSubject.send(.displayMediaPicker)
|
||||
case .removeImage:
|
||||
if state.localMedia != nil {
|
||||
state.localMedia = nil
|
||||
} else {
|
||||
state.avatarURL = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func didSelectMediaUrl(url: URL) {
|
||||
Task {
|
||||
let userIndicatorID = UUID().uuidString
|
||||
defer {
|
||||
userIndicatorController.retractIndicatorWithId(userIndicatorID)
|
||||
}
|
||||
userIndicatorController.submitIndicator(UserIndicator(id: userIndicatorID, type: .modal, title: L10n.commonLoading, persistent: true))
|
||||
|
||||
let mediaResult = await mediaPreprocessor.processMedia(at: url)
|
||||
|
||||
switch mediaResult {
|
||||
case .success(.image):
|
||||
state.localMedia = try? mediaResult.get()
|
||||
case .failure, .success:
|
||||
userIndicatorController.alertInfo = .init(id: .init(), title: L10n.commonError, message: L10n.errorUnknown)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func saveRoomDetails() {
|
||||
Task {
|
||||
let userIndicatorID = UUID().uuidString
|
||||
defer {
|
||||
userIndicatorController.retractIndicatorWithId(userIndicatorID)
|
||||
}
|
||||
userIndicatorController.submitIndicator(UserIndicator(id: userIndicatorID, type: .modal, title: L10n.screenRoomDetailsUpdatingRoom, persistent: true))
|
||||
|
||||
do {
|
||||
try await withThrowingTaskGroup(of: Void.self) { group in
|
||||
if state.avatarDidChange {
|
||||
group.addTask {
|
||||
if let localMedia = await self.state.localMedia {
|
||||
try await self.roomProxy.uploadAvatar(media: localMedia).get()
|
||||
} else if await self.state.avatarURL == nil {
|
||||
try await self.roomProxy.removeAvatar().get()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if state.nameDidChange {
|
||||
group.addTask {
|
||||
try await self.roomProxy.setName(self.state.bindings.name).get()
|
||||
}
|
||||
}
|
||||
|
||||
if state.topicDidChange {
|
||||
group.addTask {
|
||||
try await self.roomProxy.setTopic(self.state.bindings.topic).get()
|
||||
}
|
||||
}
|
||||
|
||||
try await group.waitForAll()
|
||||
}
|
||||
|
||||
actionsSubject.send(.saveFinished)
|
||||
} catch {
|
||||
userIndicatorController.alertInfo = .init(id: .init(),
|
||||
title: L10n.screenRoomDetailsEditionErrorTitle,
|
||||
message: L10n.screenRoomDetailsEditionError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user