Skip to content

Commit

Permalink
added an alert before creating a new DM
Browse files Browse the repository at this point in the history
  • Loading branch information
Element CI committed Feb 3, 2025
1 parent d7ac9e9 commit a331a64
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,9 @@
"screen_room_error_failed_retrieving_user_details" = "Could not retrieve user details";
"screen_room_invite_again_alert_message" = "Would you like to invite them back?";
"screen_room_invite_again_alert_title" = "You are alone in this chat";
"screen_room_member_details_alert_create_dm_confirmation_title" = "Send invite";
"screen_room_member_details_alert_create_dm_message" = "Would you like to start a chat with %1$@?";
"screen_room_member_details_alert_create_dm_title" = "Send invite?";
"screen_room_member_details_block_alert_action" = "Block";
"screen_room_member_details_block_alert_description" = "Blocked users won't be able to send you messages and all their messages will be hidden. You can unblock them anytime.";
"screen_room_member_details_block_user" = "Block user";
Expand Down
3 changes: 3 additions & 0 deletions ElementX/Resources/Localizations/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,9 @@
"screen_room_error_failed_retrieving_user_details" = "Could not retrieve user details";
"screen_room_invite_again_alert_message" = "Would you like to invite them back?";
"screen_room_invite_again_alert_title" = "You are alone in this chat";
"screen_room_member_details_alert_create_dm_confirmation_title" = "Send invite";
"screen_room_member_details_alert_create_dm_message" = "Would you like to start a chat with %1$@?";
"screen_room_member_details_alert_create_dm_title" = "Send invite?";
"screen_room_member_details_block_alert_action" = "Block";
"screen_room_member_details_block_alert_description" = "Blocked users won't be able to send you messages and all their messages will be hidden. You can unblock them anytime.";
"screen_room_member_details_block_user" = "Block user";
Expand Down
8 changes: 8 additions & 0 deletions ElementX/Sources/Generated/Strings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1938,6 +1938,14 @@ internal enum L10n {
internal static var screenRoomInviteAgainAlertMessage: String { return L10n.tr("Localizable", "screen_room_invite_again_alert_message") }
/// You are alone in this chat
internal static var screenRoomInviteAgainAlertTitle: String { return L10n.tr("Localizable", "screen_room_invite_again_alert_title") }
/// Send invite
internal static var screenRoomMemberDetailsAlertCreateDmConfirmationTitle: String { return L10n.tr("Localizable", "screen_room_member_details_alert_create_dm_confirmation_title") }
/// Would you like to start a chat with %1$@?
internal static func screenRoomMemberDetailsAlertCreateDmMessage(_ p1: Any) -> String {
return L10n.tr("Localizable", "screen_room_member_details_alert_create_dm_message", String(describing: p1))
}
/// Send invite?
internal static var screenRoomMemberDetailsAlertCreateDmTitle: String { return L10n.tr("Localizable", "screen_room_member_details_alert_create_dm_title") }
/// Block
internal static var screenRoomMemberDetailsBlockAlertAction: String { return L10n.tr("Localizable", "screen_room_member_details_block_alert_action") }
/// Blocked users won't be able to send you messages and all their messages will be hidden. You can unblock them anytime.
Expand Down
70 changes: 0 additions & 70 deletions ElementX/Sources/Mocks/Generated/GeneratedMocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2455,76 +2455,6 @@ class ClientProxyMock: ClientProxyProtocol, @unchecked Sendable {
return accountURLActionReturnValue
}
}
//MARK: - createDirectRoomIfNeeded

var createDirectRoomIfNeededWithExpectedRoomNameUnderlyingCallsCount = 0
var createDirectRoomIfNeededWithExpectedRoomNameCallsCount: Int {
get {
if Thread.isMainThread {
return createDirectRoomIfNeededWithExpectedRoomNameUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = createDirectRoomIfNeededWithExpectedRoomNameUnderlyingCallsCount
}

return returnValue!
}
}
set {
if Thread.isMainThread {
createDirectRoomIfNeededWithExpectedRoomNameUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
createDirectRoomIfNeededWithExpectedRoomNameUnderlyingCallsCount = newValue
}
}
}
}
var createDirectRoomIfNeededWithExpectedRoomNameCalled: Bool {
return createDirectRoomIfNeededWithExpectedRoomNameCallsCount > 0
}
var createDirectRoomIfNeededWithExpectedRoomNameReceivedArguments: (userID: String, expectedRoomName: String?)?
var createDirectRoomIfNeededWithExpectedRoomNameReceivedInvocations: [(userID: String, expectedRoomName: String?)] = []

var createDirectRoomIfNeededWithExpectedRoomNameUnderlyingReturnValue: Result<(roomID: String, isNewRoom: Bool), ClientProxyError>!
var createDirectRoomIfNeededWithExpectedRoomNameReturnValue: Result<(roomID: String, isNewRoom: Bool), ClientProxyError>! {
get {
if Thread.isMainThread {
return createDirectRoomIfNeededWithExpectedRoomNameUnderlyingReturnValue
} else {
var returnValue: Result<(roomID: String, isNewRoom: Bool), ClientProxyError>? = nil
DispatchQueue.main.sync {
returnValue = createDirectRoomIfNeededWithExpectedRoomNameUnderlyingReturnValue
}

return returnValue!
}
}
set {
if Thread.isMainThread {
createDirectRoomIfNeededWithExpectedRoomNameUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
createDirectRoomIfNeededWithExpectedRoomNameUnderlyingReturnValue = newValue
}
}
}
}
var createDirectRoomIfNeededWithExpectedRoomNameClosure: ((String, String?) async -> Result<(roomID: String, isNewRoom: Bool), ClientProxyError>)?

func createDirectRoomIfNeeded(with userID: String, expectedRoomName: String?) async -> Result<(roomID: String, isNewRoom: Bool), ClientProxyError> {
createDirectRoomIfNeededWithExpectedRoomNameCallsCount += 1
createDirectRoomIfNeededWithExpectedRoomNameReceivedArguments = (userID: userID, expectedRoomName: expectedRoomName)
DispatchQueue.main.async {
self.createDirectRoomIfNeededWithExpectedRoomNameReceivedInvocations.append((userID: userID, expectedRoomName: expectedRoomName))
}
if let createDirectRoomIfNeededWithExpectedRoomNameClosure = createDirectRoomIfNeededWithExpectedRoomNameClosure {
return await createDirectRoomIfNeededWithExpectedRoomNameClosure(userID, expectedRoomName)
} else {
return createDirectRoomIfNeededWithExpectedRoomNameReturnValue
}
}
//MARK: - directRoomForUserID

var directRoomForUserIDUnderlyingCallsCount = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,5 +90,6 @@ enum RoomMemberDetailsScreenViewAction {

enum RoomMemberDetailsScreenError: Hashable {
case failedOpeningDirectChat
case createDirectChatConfirmation
case unknown
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,36 @@ class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, Ro
persistent: true))
defer { userIndicatorController.retractIndicatorWithId(loadingIndicatorIdentifier) }

switch await clientProxy.createDirectRoomIfNeeded(with: roomMemberProxy.userID, expectedRoomName: roomMemberProxy.displayName) {
case .success((let roomID, let isNewRoom)):
if isNewRoom {
analytics.trackCreatedRoom(isDM: true)
switch await clientProxy.directRoomForUserID(roomMemberProxy.userID) {
case .success(let roomID):
if let roomID = roomID {
actionsSubject.send(.openDirectChat(roomID: roomID))
} else {
let string = roomMemberProxy.displayName ?? roomMemberProxy.userID
state.bindings.alertInfo = .init(id: .createDirectChatConfirmation,
title: L10n.screenRoomMemberDetailsAlertCreateDmTitle,
message: L10n.screenRoomMemberDetailsAlertCreateDmMessage(string),
primaryButton: .init(title: L10n.screenRoomMemberDetailsAlertCreateDmConfirmationTitle) { [weak self] in Task { await self?.createDirectChat() }},
secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil))
}
case .failure:
state.bindings.alertInfo = .init(id: .failedOpeningDirectChat)
}
}

private func createDirectChat() async {
guard let roomMemberProxy else { fatalError() }

let loadingIndicatorIdentifier = "createDirectChatLoadingIndicator"
userIndicatorController.submitIndicator(UserIndicator(id: loadingIndicatorIdentifier,
type: .modal(progress: .indeterminate, interactiveDismissDisabled: true, allowsInteraction: false),
title: L10n.commonLoading,
persistent: true))
defer { userIndicatorController.retractIndicatorWithId(loadingIndicatorIdentifier) }

switch await clientProxy.createDirectRoom(with: roomMemberProxy.userID, expectedRoomName: roomMemberProxy.displayName) {
case .success(let roomID):
analytics.trackCreatedRoom(isDM: true)
actionsSubject.send(.openDirectChat(roomID: roomID))
case .failure:
state.bindings.alertInfo = .init(id: .failedOpeningDirectChat)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,5 @@ enum UserProfileScreenViewAction {
enum UserProfileScreenError: Hashable {
case failedOpeningDirectChat
case unknown
case createDirectChatConfirmation
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,33 @@ class UserProfileScreenViewModel: UserProfileScreenViewModelType, UserProfileScr

showLoadingIndicator(allowsInteraction: false)
defer { hideLoadingIndicator() }

switch await clientProxy.createDirectRoomIfNeeded(with: userProfile.userID, expectedRoomName: userProfile.displayName) {
case .success((let roomID, let isNewRoom)):
if isNewRoom {
analytics.trackCreatedRoom(isDM: true)

switch await clientProxy.directRoomForUserID(userProfile.userID) {
case .success(let roomID):
if let roomID = roomID {
actionsSubject.send(.openDirectChat(roomID: roomID))
} else {
let string = userProfile.displayName ?? userProfile.userID
state.bindings.alertInfo = .init(id: .createDirectChatConfirmation,
title: L10n.screenRoomMemberDetailsAlertCreateDmTitle,
message: L10n.screenRoomMemberDetailsAlertCreateDmMessage(string),
primaryButton: .init(title: L10n.screenRoomMemberDetailsAlertCreateDmConfirmationTitle) { [weak self] in Task { await self?.createDirectChat() }},
secondaryButton: .init(title: L10n.actionCancel, role: .cancel, action: nil))
}
case .failure:
state.bindings.alertInfo = .init(id: .failedOpeningDirectChat)
}
}

private func createDirectChat() async {
guard let userProfile = state.userProfile else { fatalError() }

showLoadingIndicator(allowsInteraction: false)
defer { hideLoadingIndicator() }

switch await clientProxy.createDirectRoom(with: userProfile.userID, expectedRoomName: userProfile.displayName) {
case .success(let roomID):
analytics.trackCreatedRoom(isDM: true)
actionsSubject.send(.openDirectChat(roomID: roomID))
case .failure:
state.bindings.alertInfo = .init(id: .failedOpeningDirectChat)
Expand Down
17 changes: 0 additions & 17 deletions ElementX/Sources/Services/Client/ClientProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -341,23 +341,6 @@ class ClientProxy: ClientProxyProtocol {
try? await client.accountUrl(action: action).flatMap(URL.init(string:))
}

func createDirectRoomIfNeeded(with userID: String, expectedRoomName: String?) async -> Result<(roomID: String, isNewRoom: Bool), ClientProxyError> {
let currentDirectRoom = await directRoomForUserID(userID)
switch currentDirectRoom {
case .success(.some(let roomID)):
return .success((roomID: roomID, isNewRoom: false))
case .success(.none):
switch await createDirectRoom(with: userID, expectedRoomName: expectedRoomName) {
case .success(let roomID):
return .success((roomID: roomID, isNewRoom: true))
case .failure(let error):
return .failure(.sdkError(error))
}
case .failure(let error):
return .failure(.sdkError(error))
}
}

func directRoomForUserID(_ userID: String) async -> Result<String?, ClientProxyError> {
await Task.dispatch(on: clientQueue) {
do {
Expand Down
2 changes: 0 additions & 2 deletions ElementX/Sources/Services/Client/ClientProxyProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,6 @@ protocol ClientProxyProtocol: AnyObject, MediaLoaderProtocol {

func accountURL(action: AccountManagementAction) async -> URL?

func createDirectRoomIfNeeded(with userID: String, expectedRoomName: String?) async -> Result<(roomID: String, isNewRoom: Bool), ClientProxyError>

func directRoomForUserID(_ userID: String) async -> Result<String?, ClientProxyError>

func createDirectRoom(with userID: String, expectedRoomName: String?) async -> Result<String, ClientProxyError>
Expand Down

0 comments on commit a331a64

Please sign in to comment.