mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-04-26 01:02:24 +00:00
delete contact/conversation
This commit is contained in:
@@ -743,6 +743,22 @@ func apiDeleteChat(type: ChatType, id: Int64, chatDeleteMode: ChatDeleteMode = .
|
||||
throw r
|
||||
}
|
||||
|
||||
func apiDeleteContact(id: Int64, chatDeleteMode: ChatDeleteMode = .full(notify: true)) async throws -> Contact {
|
||||
let type: ChatType = .direct
|
||||
let chatId = type.rawValue + id.description
|
||||
if case .full = chatDeleteMode {
|
||||
DispatchQueue.main.async { ChatModel.shared.deletedChats.insert(chatId) }
|
||||
}
|
||||
defer {
|
||||
if case .full = chatDeleteMode {
|
||||
DispatchQueue.main.async { ChatModel.shared.deletedChats.remove(chatId) }
|
||||
}
|
||||
}
|
||||
let r = await chatSendCmd(.apiDeleteChat(type: type, id: id, chatDeleteMode: chatDeleteMode), bgTask: false)
|
||||
if case let .contactDeleted(_, contact) = r { return contact }
|
||||
throw r
|
||||
}
|
||||
|
||||
func deleteChat(_ chat: Chat, chatDeleteMode: ChatDeleteMode = .full(notify: true)) async {
|
||||
do {
|
||||
let cInfo = chat.chatInfo
|
||||
@@ -1607,6 +1623,11 @@ func processReceivedMsg(_ res: ChatResponse) async {
|
||||
let cItem = aChatItem.chatItem
|
||||
await MainActor.run {
|
||||
if active(user) {
|
||||
if case let .direct(contact) = cInfo, contact.chatDeleted {
|
||||
var updatedContact = contact
|
||||
updatedContact.chatDeleted = false
|
||||
m.updateContact(updatedContact)
|
||||
}
|
||||
m.addChatItem(cInfo, cItem)
|
||||
} else if cItem.isRcvNew && cInfo.ntfsEnabled {
|
||||
m.increaseUnreadCounter(user: user)
|
||||
|
||||
@@ -88,6 +88,18 @@ enum SendReceipts: Identifiable, Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
enum ContactDeleteMode {
|
||||
case full
|
||||
case entity
|
||||
|
||||
public func toChatDeleteMode(notify: Bool) -> ChatDeleteMode {
|
||||
switch self {
|
||||
case .full: .full(notify: notify)
|
||||
case .entity: .entity(notify: notify)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ChatInfoView: View {
|
||||
@EnvironmentObject var chatModel: ChatModel
|
||||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
@@ -99,7 +111,7 @@ struct ChatInfoView: View {
|
||||
@State private var connectionCode: String? = nil
|
||||
@FocusState private var aliasTextFieldFocused: Bool
|
||||
@State private var alert: ChatInfoViewAlert? = nil
|
||||
@State private var showDeleteContactActionSheet = false
|
||||
@State private var actionSheet: ChatInfoViewActionSheet? = nil
|
||||
@State private var sendReceipts = SendReceipts.userDefault(true)
|
||||
@State private var sendReceiptsUserDefault = true
|
||||
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
|
||||
@@ -124,6 +136,18 @@ struct ChatInfoView: View {
|
||||
}
|
||||
}
|
||||
|
||||
enum ChatInfoViewActionSheet: Identifiable {
|
||||
case deleteContactActionSheet
|
||||
case notifyDeleteContactActionSheet(contactDeleteMode: ContactDeleteMode)
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
case .deleteContactActionSheet: return "deleteContactActionSheet"
|
||||
case .notifyDeleteContactActionSheet: return "notifyDeleteContactActionSheet"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List {
|
||||
@@ -263,24 +287,37 @@ struct ChatInfoView: View {
|
||||
case let .error(title, error): return mkAlert(title: title, message: error)
|
||||
}
|
||||
}
|
||||
.actionSheet(isPresented: $showDeleteContactActionSheet) {
|
||||
if contact.ready && contact.active {
|
||||
.actionSheet(item: $actionSheet) { sheet in
|
||||
switch(sheet) {
|
||||
case .deleteContactActionSheet:
|
||||
return ActionSheet(
|
||||
title: Text("Delete contact?\nThis cannot be undone!"),
|
||||
title: Text("Delete contact or conversation?"),
|
||||
buttons: [
|
||||
.destructive(Text("Delete and notify contact")) { deleteContact(chatDeleteMode: .full(notify: true)) },
|
||||
.destructive(Text("Delete")) { deleteContact(chatDeleteMode: .full(notify: false)) },
|
||||
.cancel()
|
||||
]
|
||||
)
|
||||
} else {
|
||||
return ActionSheet(
|
||||
title: Text("Delete contact?\nThis cannot be undone!"),
|
||||
buttons: [
|
||||
.destructive(Text("Delete")) { deleteContact(chatDeleteMode: .full(notify: false)) }, // just a default
|
||||
.destructive(Text("Only delete conversation")) { deleteContact(chatDeleteMode: .messages) },
|
||||
.destructive(Text("Delete contact, keep conversation")) { actionSheet = .notifyDeleteContactActionSheet(contactDeleteMode: .entity) },
|
||||
.destructive(Text("Delete contact and conversation")) { actionSheet = .notifyDeleteContactActionSheet(contactDeleteMode: .full) },
|
||||
.cancel()
|
||||
]
|
||||
)
|
||||
case let .notifyDeleteContactActionSheet(contactDeleteMode):
|
||||
if contact.ready && contact.active {
|
||||
return ActionSheet(
|
||||
title: Text("Notify contact?\nThis cannot be undone!"),
|
||||
buttons: [
|
||||
.destructive(Text("Delete and notify contact")) { deleteContact(chatDeleteMode: contactDeleteMode.toChatDeleteMode(notify: true)) },
|
||||
.destructive(Text("Delete without notification")) { deleteContact(chatDeleteMode: contactDeleteMode.toChatDeleteMode(notify: false)) },
|
||||
.cancel()
|
||||
]
|
||||
)
|
||||
} else {
|
||||
return ActionSheet(
|
||||
title: Text("Confirm contact deletion.\nThis cannot be undone!"),
|
||||
buttons: [
|
||||
.destructive(Text("Delete")) { deleteContact(chatDeleteMode: contactDeleteMode.toChatDeleteMode(notify: false)) },
|
||||
.cancel()
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,9 +491,9 @@ struct ChatInfoView: View {
|
||||
|
||||
private func deleteContactButton() -> some View {
|
||||
Button(role: .destructive) {
|
||||
showDeleteContactActionSheet = true
|
||||
actionSheet = .deleteContactActionSheet
|
||||
} label: {
|
||||
Label("Delete contact", systemImage: "trash")
|
||||
Label("Delete", systemImage: "trash")
|
||||
.foregroundColor(Color.red)
|
||||
}
|
||||
}
|
||||
@@ -473,11 +510,15 @@ struct ChatInfoView: View {
|
||||
private func deleteContact(chatDeleteMode: ChatDeleteMode) {
|
||||
Task {
|
||||
do {
|
||||
try await apiDeleteChat(type: chat.chatInfo.chatType, id: chat.chatInfo.apiId, chatDeleteMode: chatDeleteMode)
|
||||
let ct = try await apiDeleteContact(id: chat.chatInfo.apiId, chatDeleteMode: chatDeleteMode)
|
||||
await MainActor.run {
|
||||
dismiss()
|
||||
chatModel.chatId = nil
|
||||
chatModel.removeChat(chat.chatInfo.id)
|
||||
if case .full = chatDeleteMode {
|
||||
chatModel.removeChat(chat.chatInfo.id)
|
||||
} else {
|
||||
chatModel.updateContact(ct)
|
||||
}
|
||||
}
|
||||
} catch let error {
|
||||
logger.error("deleteContactAlert apiDeleteChat error: \(responseError(error))")
|
||||
|
||||
@@ -105,16 +105,18 @@ struct ChatsView: View {
|
||||
} else {
|
||||
let s = searchString()
|
||||
return s == "" && !showUnreadAndFavorites
|
||||
? chatModel.chats
|
||||
? chatModel.chats.filter { chat in !chat.chatInfo.chatDeleted }
|
||||
: chatModel.chats.filter { chat in
|
||||
let cInfo = chat.chatInfo
|
||||
switch cInfo {
|
||||
case let .direct(contact):
|
||||
return s == ""
|
||||
? filtered(chat)
|
||||
: (viewNameContains(cInfo, s) ||
|
||||
contact.profile.displayName.localizedLowercase.contains(s) ||
|
||||
contact.fullName.localizedLowercase.contains(s))
|
||||
return !contact.chatDeleted && (
|
||||
s == ""
|
||||
? filtered(chat)
|
||||
: (viewNameContains(cInfo, s) ||
|
||||
contact.profile.displayName.localizedLowercase.contains(s) ||
|
||||
contact.fullName.localizedLowercase.contains(s))
|
||||
)
|
||||
case let .group(gInfo):
|
||||
return s == ""
|
||||
? (filtered(chat) || gInfo.membership.memberStatus == .memInvited)
|
||||
|
||||
@@ -1287,6 +1287,15 @@ public enum ChatInfo: Identifiable, Decodable, NamedChat {
|
||||
}
|
||||
}
|
||||
|
||||
public var chatDeleted: Bool {
|
||||
get {
|
||||
switch self {
|
||||
case let .direct(contact): return contact.chatDeleted
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var sendMsgEnabled: Bool {
|
||||
get {
|
||||
switch self {
|
||||
@@ -1504,7 +1513,7 @@ public struct Contact: Identifiable, Decodable, NamedChat {
|
||||
var chatTs: Date?
|
||||
var contactGroupMemberId: Int64?
|
||||
var contactGrpInvSent: Bool
|
||||
var chatDeleted: Bool
|
||||
public var chatDeleted: Bool
|
||||
|
||||
public var id: ChatId { get { "@\(contactId)" } }
|
||||
public var apiId: Int64 { get { contactId } }
|
||||
|
||||
Reference in New Issue
Block a user