Add RoomDetails for use (with RoomMemberDetails) in AvatarHeaderView. (#2490)

* Add RoomDetails and refactor AvatarHeaderView to use it.
* Remove old displayName property and use RoomDetails in the RoomDetailsScreenViewState
This commit is contained in:
Doug
2024-02-21 14:19:05 +00:00
committed by GitHub
parent 9b949ce84e
commit 730d099a76
48 changed files with 255 additions and 191 deletions
@@ -436,12 +436,12 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
}
if room.isPublic {
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomId: roomId, isDM: room.isEncryptedOneToOneRoom, state: .public)
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomID: roomId, isDM: room.isEncryptedOneToOneRoom, state: .public)
} else {
state.bindings.leaveRoomAlertItem = if room.joinedMembersCount > 1 {
LeaveRoomAlertItem(roomId: roomId, isDM: room.isEncryptedOneToOneRoom, state: .private)
LeaveRoomAlertItem(roomID: roomId, isDM: room.isEncryptedOneToOneRoom, state: .private)
} else {
LeaveRoomAlertItem(roomId: roomId, isDM: room.isEncryptedOneToOneRoom, state: .empty)
LeaveRoomAlertItem(roomID: roomId, isDM: room.isEncryptedOneToOneRoom, state: .empty)
}
}
}
@@ -184,7 +184,7 @@ struct HomeScreen: View {
private func leaveRoomAlertActions(_ item: LeaveRoomAlertItem) -> some View {
Button(item.cancelTitle, role: .cancel) { }
Button(item.confirmationTitle, role: .destructive) {
context.send(viewAction: .confirmLeaveRoom(roomIdentifier: item.roomId))
context.send(viewAction: .confirmLeaveRoom(roomIdentifier: item.roomID))
}
}
@@ -77,7 +77,7 @@ struct ReportContentScreen: View {
struct ReportContentScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = ReportContentScreenViewModel(eventID: "",
senderID: "",
roomProxy: RoomProxyMock(with: .init(displayName: nil)))
roomProxy: RoomProxyMock(with: .init()))
static var previews: some View {
NavigationStack {
@@ -158,14 +158,14 @@ struct RoomDetailsEditScreen: View {
struct RoomDetailsEditScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = RoomDetailsEditScreenViewModel(accountOwner: RoomMemberProxyMock.mockAlice,
mediaProvider: MockMediaProvider(),
roomProxy: RoomProxyMock(with: .init(id: "test_id", name: "Room", displayName: "Room")),
roomProxy: RoomProxyMock(with: .init(id: "test_id", name: "Room")),
userIndicatorController: UserIndicatorControllerMock.default)
static let readOnlyViewModel = {
let accountOwner = RoomMemberProxyMock.mockOwner(allowedStateEvents: [])
return RoomDetailsEditScreenViewModel(accountOwner: accountOwner,
mediaProvider: MockMediaProvider(),
roomProxy: RoomProxyMock(with: .init(id: "test_id", name: "Room", displayName: "Room")),
roomProxy: RoomProxyMock(with: .init(id: "test_id", name: "Room")),
userIndicatorController: UserIndicatorControllerMock.default)
}()
@@ -33,16 +33,14 @@ enum RoomDetailsScreenViewModelAction {
// MARK: View
struct RoomDetailsScreenViewState: BindableState {
let roomId: String
let canonicalAlias: String?
var details: RoomDetails
let isEncrypted: Bool
let isDirect: Bool
let permalink: URL?
var title = ""
var topic: AttributedString?
var topicSummary: AttributedString?
var avatarURL: URL?
var joinedMembersCount: Int
var isProcessingIgnoreRequest = false
var canInviteUsers = false
@@ -148,7 +146,7 @@ struct LeaveRoomAlertItem: AlertProtocol {
case `private`
}
let roomId: String
let roomID: String
let isDM: Bool
let state: RoomState
let confirmationTitle = L10n.actionLeave
@@ -57,15 +57,12 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
let topic = attributedStringBuilder.fromPlain(roomProxy.topic)
super.init(initialViewState: .init(roomId: roomProxy.id,
canonicalAlias: roomProxy.canonicalAlias,
super.init(initialViewState: .init(details: roomProxy.details,
isEncrypted: roomProxy.isEncrypted,
isDirect: roomProxy.isDirect,
permalink: roomProxy.permalink,
title: roomProxy.roomTitle,
topic: topic,
topicSummary: topic?.unattributedStringByReplacingNewlinesWithSpaces(),
avatarURL: roomProxy.avatarURL,
joinedMembersCount: roomProxy.joinedMembersCount,
notificationSettingsState: .loading,
bindings: .init()),
@@ -95,10 +92,10 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
actionsSubject.send(.requestInvitePeoplePresentation)
case .processTapLeave:
guard state.joinedMembersCount > 1 else {
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomId: roomProxy.id, isDM: roomProxy.isEncryptedOneToOneRoom, state: .empty)
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomID: roomProxy.id, isDM: roomProxy.isEncryptedOneToOneRoom, state: .empty)
return
}
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomId: roomProxy.id, isDM: roomProxy.isEncryptedOneToOneRoom, state: roomProxy.isPublic ? .public : .private)
state.bindings.leaveRoomAlertItem = LeaveRoomAlertItem(roomID: roomProxy.id, isDM: roomProxy.isEncryptedOneToOneRoom, state: roomProxy.isPublic ? .public : .private)
case .confirmLeave:
Task { await leaveRoom() }
case .processTapIgnore:
@@ -145,12 +142,11 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
}
private func updateRoomInfo() {
state.title = roomProxy.roomTitle
state.details = roomProxy.details
let topic = attributedStringBuilder.fromPlain(roomProxy.topic)
state.topic = topic
state.topicSummary = topic?.unattributedStringByReplacingNewlinesWithSpaces()
state.avatarURL = roomProxy.avatarURL
state.joinedMembersCount = roomProxy.joinedMembersCount
Task {
@@ -68,12 +68,9 @@ struct RoomDetailsScreen: View {
// MARK: - Private
private var normalRoomHeaderSection: some View {
AvatarHeaderView(avatarUrl: context.viewState.avatarURL,
name: context.viewState.title,
id: context.viewState.roomId,
AvatarHeaderView(room: context.viewState.details,
avatarSize: .room(on: .details),
imageProvider: context.imageProvider,
subtitle: context.viewState.canonicalAlias) {
imageProvider: context.imageProvider) {
context.send(viewAction: .displayAvatar)
} footer: {
if !context.viewState.shortcuts.isEmpty {
@@ -84,12 +81,9 @@ struct RoomDetailsScreen: View {
}
private func dmHeaderSection(recipient: RoomMemberDetails) -> some View {
AvatarHeaderView(avatarUrl: recipient.avatarURL,
name: recipient.name,
id: recipient.id,
AvatarHeaderView(member: recipient,
avatarSize: .user(on: .memberDetails),
imageProvider: context.imageProvider,
subtitle: recipient.id) {
imageProvider: context.imageProvider) {
context.send(viewAction: .displayAvatar)
} footer: {
if !context.viewState.shortcuts.isEmpty {
@@ -291,7 +285,7 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
.mockCharlie
]
let roomProxy = RoomProxyMock(with: .init(id: "room_a_id",
displayName: "Room A",
name: "Room A",
topic: """
Discussions about Element X iOS | https://github.com/vector-im/element-x-ios
@@ -327,7 +321,7 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
]
let roomProxy = RoomProxyMock(with: .init(id: "dm_room_id",
displayName: "DM Room",
name: "DM Room",
topic: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
isDirect: true,
isEncrypted: true,
@@ -354,7 +348,7 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
.mockCharlie
]
let roomProxy = RoomProxyMock(with: .init(id: "simple_room_id",
displayName: "Room A",
name: "Room A",
isDirect: false,
isEncrypted: false,
members: members))
@@ -47,12 +47,9 @@ struct RoomMemberDetailsScreen: View {
@ViewBuilder
private var headerSection: some View {
if let memberDetails = context.viewState.memberDetails {
AvatarHeaderView(avatarUrl: memberDetails.avatarURL,
name: memberDetails.name,
id: memberDetails.id,
AvatarHeaderView(member: memberDetails,
avatarSize: .user(on: .memberDetails),
imageProvider: context.imageProvider,
subtitle: memberDetails.id) {
imageProvider: context.imageProvider) {
context.send(viewAction: .displayAvatar)
} footer: {
if let permalink = memberDetails.permalink {
@@ -66,12 +63,9 @@ struct RoomMemberDetailsScreen: View {
}
}
} else {
AvatarHeaderView(avatarUrl: nil,
name: nil,
id: context.viewState.userID,
AvatarHeaderView(member: .init(loading: context.viewState.userID),
avatarSize: .user(on: .memberDetails),
imageProvider: context.imageProvider,
subtitle: nil,
footer: { })
}
}
@@ -127,7 +121,7 @@ struct RoomMemberDetailsScreen: View {
struct RoomMemberDetailsScreen_Previews: PreviewProvider, TestablePreview {
static let otherUserViewModel = {
let member = RoomMemberProxyMock.mockDan
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
let roomProxyMock = RoomProxyMock(with: .init(name: ""))
roomProxyMock.getMemberUserIDReturnValue = .success(member)
return RoomMemberDetailsScreenViewModel(roomProxy: roomProxyMock,
@@ -138,7 +132,7 @@ struct RoomMemberDetailsScreen_Previews: PreviewProvider, TestablePreview {
static let accountOwnerViewModel = {
let member = RoomMemberProxyMock.mockMe
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
let roomProxyMock = RoomProxyMock(with: .init(name: ""))
roomProxyMock.getMemberUserIDReturnValue = .success(member)
return RoomMemberDetailsScreenViewModel(roomProxy: roomProxyMock,
@@ -149,7 +143,7 @@ struct RoomMemberDetailsScreen_Previews: PreviewProvider, TestablePreview {
static let ignoredUserViewModel = {
let member = RoomMemberProxyMock.mockIgnored
let roomProxyMock = RoomProxyMock(with: .init(displayName: ""))
let roomProxyMock = RoomProxyMock(with: .init(name: ""))
roomProxyMock.getMemberUserIDReturnValue = .success(member)
return RoomMemberDetailsScreenViewModel(roomProxy: roomProxyMock,
@@ -160,7 +160,7 @@ struct RoomMembersListScreen_Previews: PreviewProvider, TestablePreview {
}
return RoomMembersListScreenViewModel(initialMode: initialMode,
roomProxy: RoomProxyMock(with: .init(displayName: "Some room", members: members)),
roomProxy: RoomProxyMock(with: .init(name: "Some room", members: members)),
mediaProvider: MockMediaProvider(),
userIndicatorController: ServiceLocator.shared.userIndicatorController)
}
@@ -106,7 +106,7 @@ struct RoomMembersListMemberCell_Previews: PreviewProvider, TestablePreview {
.init(with: .init(userID: "@badavatar:matrix.org", avatarURL: .picturesDirectory, membership: .ban))
]
static let viewModel = RoomMembersListScreenViewModel(roomProxy: RoomProxyMock(with: .init(displayName: "Some room",
static let viewModel = RoomMembersListScreenViewModel(roomProxy: RoomProxyMock(with: .init(name: "Some room",
members: members)),
mediaProvider: MockMediaProvider(),
userIndicatorController: ServiceLocator.shared.userIndicatorController)
@@ -42,7 +42,7 @@ struct RoomNotificationSettingsCustomSectionView_Previews: PreviewProvider, Test
static let viewModel = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .allMessages, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(with: .init(displayName: "Room", isEncrypted: true))
let roomProxy = RoomProxyMock(with: .init(name: "Room", isEncrypted: true))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -52,7 +52,7 @@ struct RoomNotificationSettingsCustomSectionView_Previews: PreviewProvider, Test
static let viewModelUnencrypted = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .allMessages, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(with: .init(displayName: "Room", isEncrypted: false))
let roomProxy = RoomProxyMock(with: .init(name: "Room", isEncrypted: false))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -83,7 +83,7 @@ struct RoomNotificationSettingsScreen_Previews: PreviewProvider, TestablePreview
static let viewModel = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .mentionsAndKeywordsOnly, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(with: .init(displayName: "Room", isEncrypted: true))
let roomProxy = RoomProxyMock(with: .init(name: "Room", isEncrypted: true))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -93,7 +93,7 @@ struct RoomNotificationSettingsScreen_Previews: PreviewProvider, TestablePreview
static let viewModelCustom = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .allMessages, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(with: .init(displayName: "Room", isEncrypted: true))
let roomProxy = RoomProxyMock(with: .init(name: "Room", isEncrypted: true))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -52,7 +52,7 @@ struct RoomNotificationSettingsUserDefinedScreen_Previews: PreviewProvider, Test
static let viewModel = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .mentionsAndKeywordsOnly, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(with: .init(displayName: "Room", isEncrypted: true))
let roomProxy = RoomProxyMock(with: .init(name: "Room", isEncrypted: true))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -62,7 +62,7 @@ struct RoomNotificationSettingsUserDefinedScreen_Previews: PreviewProvider, Test
static let viewModelUnencrypted = {
let notificationSettingsProxy = NotificationSettingsProxyMock(with: .init(defaultRoomMode: .mentionsAndKeywordsOnly, roomMode: .mentionsAndKeywordsOnly))
let roomProxy = RoomProxyMock(with: .init(displayName: "Room", isEncrypted: false))
let roomProxy = RoomProxyMock(with: .init(name: "Room", isEncrypted: false))
return RoomNotificationSettingsScreenViewModel(notificationSettingsProxy: notificationSettingsProxy,
roomProxy: roomProxy,
@@ -124,7 +124,7 @@ struct RoomPollsHistoryScreen_Previews: PreviewProvider, TestablePreview {
static let viewModelEmpty: RoomPollsHistoryScreenViewModel = {
let roomTimelineController = MockRoomTimelineController()
roomTimelineController.timelineItems = []
let roomProxyMockConfiguration = RoomProxyMockConfiguration(displayName: "Polls")
let roomProxyMockConfiguration = RoomProxyMockConfiguration(name: "Polls")
roomProxyMockConfiguration.timeline.timelineStartReached = false
let viewModel = RoomPollsHistoryScreenViewModel(pollInteractionHandler: PollInteractionHandlerMock(),
roomTimelineController: roomTimelineController,
@@ -147,7 +147,7 @@ struct RoomPollsHistoryScreen_Previews: PreviewProvider, TestablePreview {
roomTimelineController.timelineItemsTimestamp[item.id] = date
}
let roomProxyMockConfiguration = RoomProxyMockConfiguration(displayName: "Polls")
let roomProxyMockConfiguration = RoomProxyMockConfiguration(name: "Polls")
roomProxyMockConfiguration.timeline.timelineStartReached = true
let viewModel = RoomPollsHistoryScreenViewModel(pollInteractionHandler: PollInteractionHandlerMock(),
roomTimelineController: roomTimelineController,
@@ -652,7 +652,7 @@ private extension RoomProxyProtocol {
// MARK: - Mocks
extension RoomScreenViewModel {
static let mock = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(displayName: "Preview room")),
static let mock = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(name: "Preview room")),
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -51,7 +51,7 @@ struct ReadReceiptsSummaryView_Previews: PreviewProvider, TestablePreview {
.mockCharlie,
.mockDan
]
let roomProxyMock = RoomProxyMock(with: .init(displayName: "Room", members: members))
let roomProxyMock = RoomProxyMock(with: .init(name: "Room", members: members))
let mock = RoomScreenViewModel(roomProxy: roomProxyMock,
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
@@ -55,7 +55,7 @@ struct RoomHeaderView_Previews: PreviewProvider, TestablePreview {
@ViewBuilder
static var bodyPlain: some View {
let viewModel = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(displayName: "Some Room name", avatarURL: URL.picturesDirectory)),
let viewModel = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(name: "Some Room name", avatarURL: URL.picturesDirectory)),
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -73,7 +73,7 @@ struct RoomHeaderView_Previews: PreviewProvider, TestablePreview {
@ViewBuilder
static var bodyEncrypted: some View {
let viewModel = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(displayName: "Some Room name")),
let viewModel = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(name: "Some Room name")),
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -178,7 +178,7 @@ struct RoomScreen: View {
// MARK: - Previews
struct RoomScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(displayName: "Preview room", hasOngoingCall: true)),
static let viewModel = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(name: "Preview room", hasOngoingCall: true)),
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -90,7 +90,7 @@ struct TimelineReadReceiptsView_Previews: PreviewProvider, TestablePreview {
.mockMe
]
static let viewModel = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(displayName: "Test", members: members)),
static let viewModel = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(name: "Test", members: members)),
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),
@@ -77,7 +77,7 @@ struct UITimelineView: UIViewControllerRepresentable {
// MARK: - Previews
struct UITimelineView_Previews: PreviewProvider, TestablePreview {
static let viewModel = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(displayName: "Preview room")),
static let viewModel = RoomScreenViewModel(roomProxy: RoomProxyMock(with: .init(name: "Preview room")),
timelineController: MockRoomTimelineController(),
mediaProvider: MockMediaProvider(),
mediaPlayerProvider: MediaPlayerProviderMock(),