mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Improve how alias settings are handled, add unit tests (#3686)
This commit is contained in:
parent
13e66062ba
commit
0fd8df52ab
@ -25,6 +25,7 @@ struct JoinedRoomProxyMockConfiguration {
|
|||||||
var isEncrypted = true
|
var isEncrypted = true
|
||||||
var hasOngoingCall = true
|
var hasOngoingCall = true
|
||||||
var canonicalAlias: String?
|
var canonicalAlias: String?
|
||||||
|
var alternativeAliases: [String] = []
|
||||||
var pinnedEventIDs: Set<String> = []
|
var pinnedEventIDs: Set<String> = []
|
||||||
|
|
||||||
var timelineStartReached = false
|
var timelineStartReached = false
|
||||||
@ -146,7 +147,7 @@ extension RoomInfo {
|
|||||||
isTombstoned: false,
|
isTombstoned: false,
|
||||||
isFavourite: false,
|
isFavourite: false,
|
||||||
canonicalAlias: configuration.canonicalAlias,
|
canonicalAlias: configuration.canonicalAlias,
|
||||||
alternativeAliases: [],
|
alternativeAliases: configuration.alternativeAliases,
|
||||||
membership: .joined,
|
membership: .joined,
|
||||||
inviter: configuration.inviter.map { RoomMember(userId: $0.userID,
|
inviter: configuration.inviter.map { RoomMember(userId: $0.userID,
|
||||||
displayName: $0.displayName,
|
displayName: $0.displayName,
|
||||||
|
@ -22,11 +22,11 @@ struct EditRoomAddressScreenViewState: BindableState {
|
|||||||
!bindings.desiredAliasLocalPart.isEmpty
|
!bindings.desiredAliasLocalPart.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
var bindings: EditRoomAddressScreenViewStateBindings
|
var bindings = EditRoomAddressScreenViewStateBindings()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EditRoomAddressScreenViewStateBindings {
|
struct EditRoomAddressScreenViewStateBindings {
|
||||||
var desiredAliasLocalPart: String
|
var desiredAliasLocalPart = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EditRoomAddressScreenViewAction {
|
enum EditRoomAddressScreenViewAction {
|
||||||
|
@ -31,23 +31,33 @@ class EditRoomAddressScreenViewModel: EditRoomAddressScreenViewModelType, EditRo
|
|||||||
self.clientProxy = clientProxy
|
self.clientProxy = clientProxy
|
||||||
self.userIndicatorController = userIndicatorController
|
self.userIndicatorController = userIndicatorController
|
||||||
|
|
||||||
var aliasLocalPart = ""
|
|
||||||
if let canonicalAlias = roomProxy.infoPublisher.value.canonicalAlias {
|
|
||||||
aliasLocalPart = canonicalAlias.dropFirst().split(separator: ":").first.flatMap(String.init) ?? ""
|
|
||||||
} else if let displayName = roomProxy.infoPublisher.value.displayName {
|
|
||||||
aliasLocalPart = roomAliasNameFromRoomDisplayName(roomName: displayName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let initialViewState {
|
if let initialViewState {
|
||||||
super.init(initialViewState: initialViewState)
|
super.init(initialViewState: initialViewState)
|
||||||
} else {
|
} else {
|
||||||
super.init(initialViewState: EditRoomAddressScreenViewState(serverName: clientProxy.userIDServerName ?? "",
|
super.init(initialViewState: EditRoomAddressScreenViewState(serverName: clientProxy.userIDServerName ?? ""))
|
||||||
currentAliasLocalPart: aliasLocalPart,
|
|
||||||
bindings: .init(desiredAliasLocalPart: aliasLocalPart)))
|
state.currentAliasLocalPart = localPartForMatchingAlias(computeFromDisplayName: false)
|
||||||
|
state.bindings.desiredAliasLocalPart = localPartForMatchingAlias(computeFromDisplayName: true) ?? ""
|
||||||
}
|
}
|
||||||
|
|
||||||
setupSubscriptions()
|
setupSubscriptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Give priority to aliases from the current user's homeserver as remote ones
|
||||||
|
/// cannot be edited. If none match then don't fallback and show an empty alias
|
||||||
|
/// instead so that the user can add one sepecific to this homeserver.
|
||||||
|
private func localPartForMatchingAlias(computeFromDisplayName: Bool) -> String? {
|
||||||
|
if let matchingAlias = roomProxy.infoPublisher.value.firstAliasMatching(serverName: clientProxy.userIDServerName, useFallback: false) {
|
||||||
|
return matchingAlias.aliasLocalPart
|
||||||
|
}
|
||||||
|
|
||||||
|
guard computeFromDisplayName, let displayName = roomProxy.infoPublisher.value.displayName else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return roomAliasNameFromRoomDisplayName(roomName: displayName)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Public
|
// MARK: - Public
|
||||||
|
|
||||||
override func process(viewAction: EditRoomAddressScreenViewAction) {
|
override func process(viewAction: EditRoomAddressScreenViewAction) {
|
||||||
@ -136,7 +146,7 @@ class EditRoomAddressScreenViewModel: EditRoomAddressScreenViewModelType, EditRo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let oldAlias = roomProxy.infoPublisher.value.canonicalAlias
|
let oldAlias = roomProxy.infoPublisher.value.firstAliasMatching(serverName: clientProxy.userIDServerName, useFallback: false)
|
||||||
|
|
||||||
// First publish the new alias
|
// First publish the new alias
|
||||||
if case .failure = await roomProxy.publishRoomAliasInRoomDirectory(canonicalAlias) {
|
if case .failure = await roomProxy.publishRoomAliasInRoomDirectory(canonicalAlias) {
|
||||||
@ -172,3 +182,9 @@ class EditRoomAddressScreenViewModel: EditRoomAddressScreenViewModelType, EditRo
|
|||||||
userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier)
|
userIndicatorController.retractIndicatorWithId(Self.loadingIndicatorIdentifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private extension String {
|
||||||
|
var aliasLocalPart: String {
|
||||||
|
dropFirst().split(separator: ":").first.flatMap(String.init) ?? ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -79,8 +79,18 @@ class SecurityAndPrivacyScreenViewModel: SecurityAndPrivacyScreenViewModelType,
|
|||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
|
|
||||||
|
let userIDServerName = clientProxy.userIDServerName
|
||||||
|
|
||||||
roomProxy.infoPublisher
|
roomProxy.infoPublisher
|
||||||
.map(\.canonicalAlias)
|
.compactMap { roomInfo in
|
||||||
|
guard let userIDServerName else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Give priority to aliases from the current user's homeserver as remote ones
|
||||||
|
// cannot be edited.
|
||||||
|
return roomInfo.firstAliasMatching(serverName: userIDServerName, useFallback: true)
|
||||||
|
}
|
||||||
.removeDuplicates()
|
.removeDuplicates()
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.weakAssign(to: \.state.canonicalAlias, on: self)
|
.weakAssign(to: \.state.canonicalAlias, on: self)
|
||||||
|
@ -67,6 +67,37 @@ struct RoomInfoProxy: BaseRoomInfoProxyProtocol {
|
|||||||
var pinnedEventIDs: Set<String> { Set(roomInfo.pinnedEventIds) }
|
var pinnedEventIDs: Set<String> { Set(roomInfo.pinnedEventIds) }
|
||||||
var joinRule: JoinRule? { roomInfo.joinRule }
|
var joinRule: JoinRule? { roomInfo.joinRule }
|
||||||
var historyVisibility: RoomHistoryVisibility { roomInfo.historyVisibility }
|
var historyVisibility: RoomHistoryVisibility { roomInfo.historyVisibility }
|
||||||
|
|
||||||
|
/// Find the first alias that matches the given homeserver
|
||||||
|
/// - Parameters:
|
||||||
|
/// - serverName: the homserver in question
|
||||||
|
/// - useFallback: whether to return any alias if none match
|
||||||
|
func firstAliasMatching(serverName: String?, useFallback: Bool) -> String? {
|
||||||
|
guard let serverName else { return nil }
|
||||||
|
|
||||||
|
// Check if the canonical alias matches the homeserver
|
||||||
|
if let canonicalAlias = roomInfo.canonicalAlias,
|
||||||
|
canonicalAlias.range(of: serverName) != nil {
|
||||||
|
return canonicalAlias
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise check the alternative aliases and return the first one that matches
|
||||||
|
if let matchingAlternativeAlias = roomInfo.alternativeAliases.filter({ $0.range(of: serverName) != nil }).first {
|
||||||
|
return matchingAlternativeAlias
|
||||||
|
}
|
||||||
|
|
||||||
|
guard useFallback else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or just return the canonical alias if any
|
||||||
|
if let canonicalAlias = roomInfo.canonicalAlias {
|
||||||
|
return canonicalAlias
|
||||||
|
}
|
||||||
|
|
||||||
|
// And finally return whatever the first alternative alias is
|
||||||
|
return roomInfo.alternativeAliases.first
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RoomPreviewInfoProxy: BaseRoomInfoProxyProtocol {
|
struct RoomPreviewInfoProxy: BaseRoomInfoProxyProtocol {
|
||||||
|
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_editRoomAddressScreen-iPad-en-GB.No-alias.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_editRoomAddressScreen-iPad-en-GB.No-alias.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_editRoomAddressScreen-iPad-pseudo.No-alias.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_editRoomAddressScreen-iPad-pseudo.No-alias.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_editRoomAddressScreen-iPhone-16-en-GB.No-alias.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_editRoomAddressScreen-iPhone-16-en-GB.No-alias.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_editRoomAddressScreen-iPhone-16-pseudo.No-alias.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_editRoomAddressScreen-iPhone-16-pseudo.No-alias.png
(Stored with Git LFS)
Binary file not shown.
@ -17,5 +17,67 @@ class EditRoomAddressScreenViewModelTests: XCTestCase {
|
|||||||
viewModel.context
|
viewModel.context
|
||||||
}
|
}
|
||||||
|
|
||||||
override func setUpWithError() throws { }
|
func testCanonicalAliasChosen() async throws {
|
||||||
|
let roomProxy = JoinedRoomProxyMock(.init(name: "Room Name", canonicalAlias: "#room-name:matrix.org",
|
||||||
|
alternativeAliases: ["#beta:homeserver.io",
|
||||||
|
"#alternative-room-name:matrix.org"]))
|
||||||
|
|
||||||
|
viewModel = EditRoomAddressScreenViewModel(roomProxy: roomProxy,
|
||||||
|
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org")),
|
||||||
|
userIndicatorController: UserIndicatorControllerMock())
|
||||||
|
|
||||||
|
let deferred = deferFulfillment(context.$viewState) { state in
|
||||||
|
state.bindings.desiredAliasLocalPart == "room-name"
|
||||||
|
}
|
||||||
|
|
||||||
|
try await deferred.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Priority should be given to aliases from the current user's homeserver as they can edit those.
|
||||||
|
func testAlternativeAliasChosen() async throws {
|
||||||
|
let roomProxy = JoinedRoomProxyMock(.init(name: "Room Name", canonicalAlias: "#alpha:homeserver.io",
|
||||||
|
alternativeAliases: ["#beta:homeserver.io",
|
||||||
|
"#room-name:matrix.org",
|
||||||
|
"#alternative-room-name:matrix.org"]))
|
||||||
|
|
||||||
|
viewModel = EditRoomAddressScreenViewModel(roomProxy: roomProxy,
|
||||||
|
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org")),
|
||||||
|
userIndicatorController: UserIndicatorControllerMock())
|
||||||
|
|
||||||
|
let deferred = deferFulfillment(context.$viewState) { state in
|
||||||
|
state.bindings.desiredAliasLocalPart == "room-name"
|
||||||
|
}
|
||||||
|
|
||||||
|
try await deferred.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testBuildAliasFromDisplayName() async throws {
|
||||||
|
let roomProxy = JoinedRoomProxyMock(.init(name: "Room Name"))
|
||||||
|
|
||||||
|
viewModel = EditRoomAddressScreenViewModel(roomProxy: roomProxy,
|
||||||
|
clientProxy: ClientProxyMock(.init(userIDServerName: "matrix.org")),
|
||||||
|
userIndicatorController: UserIndicatorControllerMock())
|
||||||
|
|
||||||
|
let deferred = deferFulfillment(context.$viewState) { state in
|
||||||
|
state.bindings.desiredAliasLocalPart == "room-name"
|
||||||
|
}
|
||||||
|
|
||||||
|
try await deferred.fulfill()
|
||||||
|
}
|
||||||
|
|
||||||
|
func testCorrectMethodsCalledOnSave() async throws {
|
||||||
|
let clientProxy = ClientProxyMock(.init(userIDServerName: "matrix.org"))
|
||||||
|
clientProxy.isAliasAvailableReturnValue = .success(true)
|
||||||
|
|
||||||
|
let roomProxy = JoinedRoomProxyMock(.init(name: "Room Name"))
|
||||||
|
roomProxy.publishRoomAliasInRoomDirectoryReturnValue = .success(true)
|
||||||
|
roomProxy.updateCanonicalAliasAltAliasesReturnValue = .success(())
|
||||||
|
roomProxy.removeRoomAliasFromRoomDirectoryReturnValue = .success(true)
|
||||||
|
|
||||||
|
viewModel = EditRoomAddressScreenViewModel(roomProxy: roomProxy,
|
||||||
|
clientProxy: clientProxy,
|
||||||
|
userIndicatorController: UserIndicatorControllerMock())
|
||||||
|
|
||||||
|
context.send(viewAction: .save)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user