delete contact/conversation

This commit is contained in:
spaced4ndy
2024-05-07 16:34:39 +04:00
parent e78dffc358
commit d7bc183066
4 changed files with 98 additions and 25 deletions

View File

@@ -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)

View File

@@ -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))")

View File

@@ -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)

View File

@@ -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 } }