mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
refactor: manage member sheet in timeline
better implementation updated tests Update ElementX/Sources/Screens/Timeline/TimelineViewModel.swift Co-authored-by: Doug <6060466+pixlwave@users.noreply.github.com> fix
This commit is contained in:
@@ -19,7 +19,7 @@ enum TimelineViewModelAction {
|
||||
case displayLocationPicker
|
||||
case displayPollForm(mode: PollFormMode)
|
||||
case displayMediaUploadPreviewScreen(url: URL)
|
||||
case tappedOnSenderDetails(userID: String)
|
||||
case displaySenderDetails(userID: String)
|
||||
case displayMessageForwarding(forwardingItem: MessageForwardingItem)
|
||||
case displayMediaPreview(TimelineMediaPreviewViewModel)
|
||||
case displayLocation(body: String, geoURI: GeoURI, description: String?)
|
||||
@@ -99,6 +99,8 @@ struct TimelineViewState: BindableState {
|
||||
var canCurrentUserRedactOthers = false
|
||||
var canCurrentUserRedactSelf = false
|
||||
var canCurrentUserPin = false
|
||||
var canCurrentUserKick = false
|
||||
var canCurrentUserBan = false
|
||||
var isViewSourceEnabled: Bool
|
||||
var hideTimelineMedia: Bool
|
||||
|
||||
@@ -135,7 +137,7 @@ struct TimelineViewStateBindings {
|
||||
/// Key is itemID, value is the collapsed state.
|
||||
var reactionsCollapsed: [TimelineItemIdentifier: Bool]
|
||||
|
||||
var alertInfo: AlertInfo<RoomScreenAlertInfoType>?
|
||||
var alertInfo: AlertInfo<TimelineAlertInfoType>?
|
||||
|
||||
var debugInfo: TimelineItemDebugInfo?
|
||||
|
||||
@@ -144,6 +146,8 @@ struct TimelineViewStateBindings {
|
||||
var reactionSummaryInfo: ReactionSummaryInfo?
|
||||
|
||||
var readReceiptsSummaryInfo: ReadReceiptSummaryInfo?
|
||||
|
||||
var manageMemberViewModel: ManageRoomMemberSheetViewModel?
|
||||
}
|
||||
|
||||
struct TimelineItemActionMenuInfo: Equatable, Identifiable {
|
||||
@@ -172,7 +176,7 @@ struct ReadReceiptSummaryInfo: Identifiable {
|
||||
let id: TimelineItemIdentifier
|
||||
}
|
||||
|
||||
enum RoomScreenAlertInfoType: Hashable {
|
||||
enum TimelineAlertInfoType: Hashable {
|
||||
case audioRecodingPermissionError
|
||||
case pollEndConfirmation(String)
|
||||
case sendingFailed
|
||||
|
||||
@@ -42,6 +42,8 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
private var currentUserProxy: RoomMemberProxyProtocol?
|
||||
|
||||
private var paginateBackwardsTask: Task<Void, Never>?
|
||||
private var paginateForwardsTask: Task<Void, Never>?
|
||||
|
||||
@@ -173,7 +175,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
case .handleTimelineItemMenuAction(let itemID, let action):
|
||||
timelineInteractionHandler.handleTimelineItemMenuAction(action, itemID: itemID)
|
||||
case .tappedOnSenderDetails(userID: let userID):
|
||||
actionsSubject.send(.tappedOnSenderDetails(userID: userID))
|
||||
handleTappedOnSenderDetails(userID: userID)
|
||||
case .displayEmojiPicker(let itemID):
|
||||
timelineInteractionHandler.displayEmojiPicker(for: itemID)
|
||||
case .displayReactionSummary(let itemID, let key):
|
||||
@@ -258,6 +260,41 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func handleTappedOnSenderDetails(userID: String) {
|
||||
// We also need to make sure the user is in the joined state, otherwise we just show the details.
|
||||
guard let memberProxy = roomProxy.membersPublisher.value.first(where: { $0.userID == userID && $0.membership == .join }),
|
||||
let currentUserProxy,
|
||||
currentUserProxy.powerLevel > memberProxy.powerLevel else {
|
||||
actionsSubject.send(.displaySenderDetails(userID: userID))
|
||||
return
|
||||
}
|
||||
|
||||
if state.canCurrentUserBan || state.canCurrentUserKick {
|
||||
let member = RoomMemberDetails(withProxy: memberProxy)
|
||||
let manageMemeberViewModel = ManageRoomMemberSheetViewModel(member: member,
|
||||
canKick: state.canCurrentUserKick,
|
||||
canBan: state.canCurrentUserBan,
|
||||
roomProxy: roomProxy,
|
||||
userIndicatorController: userIndicatorController,
|
||||
analyticsService: analyticsService,
|
||||
mediaProvider: mediaProvider)
|
||||
manageMemeberViewModel.actions.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
case .dismiss(let shouldShowDetails):
|
||||
state.bindings.manageMemberViewModel = nil
|
||||
if shouldShowDetails {
|
||||
actionsSubject.send(.displaySenderDetails(userID: userID))
|
||||
}
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
state.bindings.manageMemberViewModel = manageMemeberViewModel
|
||||
} else {
|
||||
actionsSubject.send(.displaySenderDetails(userID: userID))
|
||||
}
|
||||
}
|
||||
|
||||
private func focusLive() {
|
||||
timelineController.focusLive()
|
||||
}
|
||||
@@ -348,6 +385,9 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
private func updateMembers(_ members: [RoomMemberProxyProtocol]) {
|
||||
state.members = members.reduce(into: [String: RoomMemberState]()) { dictionary, member in
|
||||
dictionary[member.userID] = RoomMemberState(displayName: member.displayName, avatarURL: member.avatarURL)
|
||||
if member.userID == roomProxy.ownUserID {
|
||||
currentUserProxy = member
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,6 +409,18 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
} else {
|
||||
state.canCurrentUserPin = false
|
||||
}
|
||||
|
||||
if case let .success(value) = await roomProxy.canUserKick(userID: roomProxy.ownUserID) {
|
||||
state.canCurrentUserKick = value
|
||||
} else {
|
||||
state.canCurrentUserKick = false
|
||||
}
|
||||
|
||||
if case let .success(value) = await roomProxy.canUserBan(userID: roomProxy.ownUserID) {
|
||||
state.canCurrentUserBan = value
|
||||
} else {
|
||||
state.canCurrentUserBan = false
|
||||
}
|
||||
}
|
||||
|
||||
private func setupSubscriptions() {
|
||||
@@ -898,7 +950,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
|
||||
userIndicatorController.retractIndicatorWithId(Constants.focusTimelineToastIndicatorID)
|
||||
}
|
||||
|
||||
private func displayAlert(_ type: RoomScreenAlertInfoType) {
|
||||
private func displayAlert(_ type: TimelineAlertInfoType) {
|
||||
switch type {
|
||||
case .audioRecodingPermissionError:
|
||||
state.bindings.alertInfo = .init(id: type,
|
||||
|
||||
Reference in New Issue
Block a user