Skip to content

Commit

Permalink
implemented error checking
Browse files Browse the repository at this point in the history
when editing the address
  • Loading branch information
Velin92 committed Dec 20, 2024
1 parent 3246236 commit 218958d
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ class CreateRoomViewModel: CreateRoomViewModelType, CreateRoomViewModelProtocol
}
}

func canonicalAlias(aliasLocalPart: String?) -> String? {
private func canonicalAlias(aliasLocalPart: String?) -> String? {
guard let aliasLocalPart,
!aliasLocalPart.isEmpty else {
return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,22 @@ enum EditRoomAddressScreenViewModelAction {
struct EditRoomAddressScreenViewState: BindableState {
let serverName: String
var currentAliasLocalPart: String?
var desiredAliasLocalPart: String
var aliasErrors: Set<EditRoomAddressErrorState> = []

var canSave: Bool {
currentAliasLocalPart != desiredAliasLocalPart &&
!aliasErrors.isEmpty &&
!desiredAliasLocalPart.isEmpty
currentAliasLocalPart != bindings.desiredAliasLocalPart &&
aliasErrors.isEmpty &&
!bindings.desiredAliasLocalPart.isEmpty
}

var bindings: EditRoomAddressScreenViewStateBindings
}

struct EditRoomAddressScreenViewStateBindings {
var desiredAliasLocalPart: String
}

enum EditRoomAddressScreenViewAction {
case save
case cancel
case updateAliasLocalPart(String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class EditRoomAddressScreenViewModel: EditRoomAddressScreenViewModelType, EditRo
var actionsPublisher: AnyPublisher<EditRoomAddressScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher()
}

@CancellableTask private var checkAliasAvailabilityTask: Task<Void, Never>?

init(roomProxy: JoinedRoomProxyProtocol,
clientProxy: ClientProxyProtocol,
Expand All @@ -36,7 +38,8 @@ class EditRoomAddressScreenViewModel: EditRoomAddressScreenViewModelType, EditRo
}

super.init(initialViewState: EditRoomAddressScreenViewState(serverName: clientProxy.userIDServerName ?? "",
desiredAliasLocalPart: aliasLocalPart))
bindings: .init(desiredAliasLocalPart: aliasLocalPart)))
setupSubscriptions()
}

// MARK: - Public
Expand All @@ -46,12 +49,80 @@ class EditRoomAddressScreenViewModel: EditRoomAddressScreenViewModelType, EditRo

switch viewAction {
case .save:
// TODO: Handle the save action
break
Task { await save() }
case .cancel:
actionsSubject.send(.cancel)
case .updateAliasLocalPart(let updatedValue):
}
}

private func setupSubscriptions() {
context.$viewState
.map(\.bindings.desiredAliasLocalPart)
.removeDuplicates()
.debounce(for: 1, scheduler: DispatchQueue.main)
.sink { [weak self] aliasLocalPart in
guard let self else {
return
}

guard let canonicalAlias = canonicalAlias(aliasLocalPart: aliasLocalPart) else {
// While is empty don't display the errors, since the save button is already disabled
state.aliasErrors.removeAll()
return
}

if !isRoomAliasFormatValid(alias: canonicalAlias) {
state.aliasErrors.insert(.invalidSymbols)
// If the alias is invalid we don't need to check for availability
state.aliasErrors.remove(.alreadyExists)
checkAliasAvailabilityTask = nil
return
}

state.aliasErrors.remove(.invalidSymbols)

checkAliasAvailabilityTask = Task { [weak self] in
guard let self else {
return
}

if case .success(false) = await self.clientProxy.isAliasAvailable(canonicalAlias) {
guard !Task.isCancelled else { return }
state.aliasErrors.insert(.alreadyExists)
} else {
guard !Task.isCancelled else { return }
state.aliasErrors.remove(.alreadyExists)
}
}
}
.store(in: &cancellables)
}

private func save() async {
guard let canonicalAlias = canonicalAlias(aliasLocalPart: state.bindings.desiredAliasLocalPart),
isRoomAliasFormatValid(alias: canonicalAlias) else {
state.aliasErrors = [.invalidSymbols]
return
}

switch await clientProxy.isAliasAvailable(canonicalAlias) {
case .success(true):
break
case .success(false):
state.aliasErrors = [.alreadyExists]
return
case .failure:
userIndicatorController.submitIndicator(.init(title: L10n.errorUnknown))
return
}

// TODO: API calls to edit/add the alias and maybe also dismiss the view? (check with design)
}

private func canonicalAlias(aliasLocalPart: String) -> String? {
guard !aliasLocalPart.isEmpty else {
return nil
}
return "#\(aliasLocalPart):\(state.serverName)"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,14 @@ import SwiftUI
struct EditRoomAddressScreen: View {
@ObservedObject var context: EditRoomAddressScreenViewModel.Context

private var aliasBinding: Binding<String> {
.init(get: {
context.viewState.desiredAliasLocalPart
}, set: {
context.send(viewAction: .updateAliasLocalPart($0))
})
}

var body: some View {
Form {
Section {
EditRoomAddressListRow(aliasLocalPart: aliasBinding,
EditRoomAddressListRow(aliasLocalPart: $context.desiredAliasLocalPart,
serverName: context.viewState.serverName, shouldDisplayError: context.viewState.aliasErrors.errorDescription != nil)
.onChange(of: context.desiredAliasLocalPart) { _, newAliasLocalPart in
context.desiredAliasLocalPart = newAliasLocalPart.lowercased()
}
} footer: {
VStack(alignment: .leading, spacing: 12) {
if let errorDescription = context.viewState.aliasErrors.errorDescription {
Expand Down Expand Up @@ -70,6 +65,18 @@ struct EditRoomAddressScreen_Previews: PreviewProvider, TestablePreview {
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org")),
userIndicatorController: UserIndicatorControllerMock())

static let invalidSymbolsViewModel = EditRoomAddressScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Room Name", canonicalAlias: "#room#-alias:matrix.org")),
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org")),
userIndicatorController: UserIndicatorControllerMock())

static let alreadyExistingViewModel = {
let clientProxy = ClientProxyMock(.init(userIDServerName: "matrix.org"))
clientProxy.isAliasAvailableReturnValue = .success(false)
return EditRoomAddressScreenViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Room Name")),
clientProxy: clientProxy,
userIndicatorController: UserIndicatorControllerMock())
}()

static var previews: some View {
NavigationStack {
EditRoomAddressScreen(context: noAliasviewModel.context)
Expand All @@ -80,5 +87,15 @@ struct EditRoomAddressScreen_Previews: PreviewProvider, TestablePreview {
EditRoomAddressScreen(context: aliasviewModel.context)
}
.previewDisplayName("With alias")

NavigationStack {
EditRoomAddressScreen(context: invalidSymbolsViewModel.context)
}
.previewDisplayName("Invalid symbols")

NavigationStack {
EditRoomAddressScreen(context: alreadyExistingViewModel.context)
}
.previewDisplayName("Already existing")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ class SecurityAndPrivacyScreenViewModel: SecurityAndPrivacyScreenViewModelType,
self.roomProxy = roomProxy
self.clientProxy = clientProxy
self.userIndicatorController = userIndicatorController
let canonicalAlias = roomProxy.infoPublisher.value.canonicalAlias
super.init(initialViewState: SecurityAndPrivacyScreenViewState(serverName: clientProxy.userIDServerName ?? "",
accessType: roomProxy.infoPublisher.value.roomAccessType,
isEncryptionEnabled: roomProxy.isEncrypted,
Expand Down

0 comments on commit 218958d

Please sign in to comment.