ios: notify contact about contact deletion (#3135)
This commit is contained in:
parent
c64d1e8361
commit
bbe329072e
@ -1285,6 +1285,12 @@ func processReceivedMsg(_ res: ChatResponse) async {
|
||||
m.removeChat(connection.id)
|
||||
}
|
||||
}
|
||||
case let .contactDeletedByContact(user, contact):
|
||||
if active(user) && contact.directOrUsed {
|
||||
await MainActor.run {
|
||||
m.updateContact(contact)
|
||||
}
|
||||
}
|
||||
case let .contactConnected(user, contact, _):
|
||||
if active(user) && contact.directOrUsed {
|
||||
await MainActor.run {
|
||||
|
@ -164,7 +164,7 @@ struct ChatInfoView: View {
|
||||
// synchronizeConnectionButtonForce()
|
||||
// }
|
||||
}
|
||||
.disabled(!contact.ready)
|
||||
.disabled(!contact.ready || !contact.active)
|
||||
|
||||
if let contactLink = contact.contactLink {
|
||||
Section {
|
||||
@ -181,7 +181,7 @@ struct ChatInfoView: View {
|
||||
}
|
||||
}
|
||||
|
||||
if contact.ready {
|
||||
if contact.ready && contact.active {
|
||||
Section("Servers") {
|
||||
networkStatusRow()
|
||||
.onTapGesture {
|
||||
@ -192,8 +192,7 @@ struct ChatInfoView: View {
|
||||
alert = .switchAddressAlert
|
||||
}
|
||||
.disabled(
|
||||
!contact.ready
|
||||
|| connStats.rcvQueuesInfo.contains { $0.rcvSwitchStatus != nil }
|
||||
connStats.rcvQueuesInfo.contains { $0.rcvSwitchStatus != nil }
|
||||
|| connStats.ratchetSyncSendProhibited
|
||||
)
|
||||
if connStats.rcvQueuesInfo.contains(where: { $0.rcvSwitchStatus != nil }) {
|
||||
|
@ -79,6 +79,7 @@ struct ChatItemContentView<Content: View>: View {
|
||||
case let .rcvDecryptionError(msgDecryptError, msgCount): CIRcvDecryptionError(msgDecryptError: msgDecryptError, msgCount: msgCount, chatItem: chatItem)
|
||||
case let .rcvGroupInvitation(groupInvitation, memberRole): groupInvitationItemView(groupInvitation, memberRole)
|
||||
case let .sndGroupInvitation(groupInvitation, memberRole): groupInvitationItemView(groupInvitation, memberRole)
|
||||
case .rcvDirectEvent: eventItemView()
|
||||
case .rcvGroupEvent(.memberConnected): CIEventView(eventText: membersConnectedItemText)
|
||||
case .rcvGroupEvent(.memberCreatedContact): CIMemberCreatedContactView(chatItem: chatItem)
|
||||
case .rcvGroupEvent: eventItemView()
|
||||
|
@ -150,7 +150,7 @@ struct ChatView: View {
|
||||
HStack {
|
||||
if contact.allowsFeature(.calls) {
|
||||
callButton(contact, .audio, imageName: "phone")
|
||||
.disabled(!contact.ready)
|
||||
.disabled(!contact.ready || !contact.active)
|
||||
}
|
||||
Menu {
|
||||
if contact.allowsFeature(.calls) {
|
||||
@ -159,11 +159,11 @@ struct ChatView: View {
|
||||
} label: {
|
||||
Label("Video call", systemImage: "video")
|
||||
}
|
||||
.disabled(!contact.ready)
|
||||
.disabled(!contact.ready || !contact.active)
|
||||
}
|
||||
searchButton()
|
||||
toggleNtfsButton(chat)
|
||||
.disabled(!contact.ready)
|
||||
.disabled(!contact.ready || !contact.active)
|
||||
} label: {
|
||||
Image(systemName: "ellipsis")
|
||||
}
|
||||
@ -321,6 +321,7 @@ struct ChatView: View {
|
||||
@ViewBuilder private func connectingText() -> some View {
|
||||
if case let .direct(contact) = chat.chatInfo,
|
||||
!contact.ready,
|
||||
contact.active,
|
||||
!contact.nextSendGrpInv {
|
||||
Text("connecting…")
|
||||
.font(.caption)
|
||||
|
@ -65,7 +65,7 @@ struct ChatListNavLink: View {
|
||||
}
|
||||
Button {
|
||||
AlertManager.shared.showAlert(
|
||||
contact.ready
|
||||
contact.ready || !contact.active
|
||||
? deleteContactAlert(chat.chatInfo)
|
||||
: deletePendingContactAlert(chat, contact)
|
||||
)
|
||||
|
@ -57,19 +57,26 @@ struct ChatPreviewView: View {
|
||||
}
|
||||
|
||||
@ViewBuilder private func chatPreviewImageOverlayIcon() -> some View {
|
||||
if case let .group(groupInfo) = chat.chatInfo {
|
||||
switch chat.chatInfo {
|
||||
case let .direct(contact):
|
||||
if !contact.active {
|
||||
inactiveIcon()
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
case let .group(groupInfo):
|
||||
switch (groupInfo.membership.memberStatus) {
|
||||
case .memLeft: groupInactiveIcon()
|
||||
case .memRemoved: groupInactiveIcon()
|
||||
case .memGroupDeleted: groupInactiveIcon()
|
||||
case .memLeft: inactiveIcon()
|
||||
case .memRemoved: inactiveIcon()
|
||||
case .memGroupDeleted: inactiveIcon()
|
||||
default: EmptyView()
|
||||
}
|
||||
} else {
|
||||
default:
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private func groupInactiveIcon() -> some View {
|
||||
@ViewBuilder private func inactiveIcon() -> some View {
|
||||
Image(systemName: "multiply.circle.fill")
|
||||
.foregroundColor(.secondary.opacity(0.65))
|
||||
.background(Circle().foregroundColor(Color(uiColor: .systemBackground)))
|
||||
@ -80,7 +87,6 @@ struct ChatPreviewView: View {
|
||||
switch chat.chatInfo {
|
||||
case let .direct(contact):
|
||||
previewTitle(contact.verified == true ? verifiedIcon + t : t)
|
||||
.foregroundColor(chat.chatInfo.ready ? .primary : .secondary)
|
||||
case let .group(groupInfo):
|
||||
let v = previewTitle(t)
|
||||
switch (groupInfo.membership.memberStatus) {
|
||||
@ -183,7 +189,7 @@ struct ChatPreviewView: View {
|
||||
if !contact.ready {
|
||||
if contact.nextSendGrpInv {
|
||||
chatPreviewInfoText("send direct message")
|
||||
} else {
|
||||
} else if contact.active {
|
||||
chatPreviewInfoText("connecting…")
|
||||
}
|
||||
}
|
||||
@ -228,16 +234,20 @@ struct ChatPreviewView: View {
|
||||
@ViewBuilder private func chatStatusImage() -> some View {
|
||||
switch chat.chatInfo {
|
||||
case let .direct(contact):
|
||||
switch (chatModel.contactNetworkStatus(contact)) {
|
||||
case .connected: incognitoIcon(chat.chatInfo.incognito)
|
||||
case .error:
|
||||
Image(systemName: "exclamationmark.circle")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 17, height: 17)
|
||||
.foregroundColor(.secondary)
|
||||
default:
|
||||
ProgressView()
|
||||
if contact.active {
|
||||
switch (chatModel.contactNetworkStatus(contact)) {
|
||||
case .connected: incognitoIcon(chat.chatInfo.incognito)
|
||||
case .error:
|
||||
Image(systemName: "exclamationmark.circle")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 17, height: 17)
|
||||
.foregroundColor(.secondary)
|
||||
default:
|
||||
ProgressView()
|
||||
}
|
||||
} else {
|
||||
incognitoIcon(chat.chatInfo.incognito)
|
||||
}
|
||||
default:
|
||||
incognitoIcon(chat.chatInfo.incognito)
|
||||
|
@ -462,6 +462,7 @@ public enum ChatResponse: Decodable, Error {
|
||||
case contactAlreadyExists(user: UserRef, contact: Contact)
|
||||
case contactRequestAlreadyAccepted(user: UserRef, contact: Contact)
|
||||
case contactDeleted(user: UserRef, contact: Contact)
|
||||
case contactDeletedByContact(user: UserRef, contact: Contact)
|
||||
case chatCleared(user: UserRef, chatInfo: ChatInfo)
|
||||
case userProfileNoChange(user: User)
|
||||
case userProfileUpdated(user: User, fromProfile: Profile, toProfile: Profile, updateSummary: UserProfileUpdateSummary)
|
||||
@ -599,6 +600,7 @@ public enum ChatResponse: Decodable, Error {
|
||||
case .contactAlreadyExists: return "contactAlreadyExists"
|
||||
case .contactRequestAlreadyAccepted: return "contactRequestAlreadyAccepted"
|
||||
case .contactDeleted: return "contactDeleted"
|
||||
case .contactDeletedByContact: return "contactDeletedByContact"
|
||||
case .chatCleared: return "chatCleared"
|
||||
case .userProfileNoChange: return "userProfileNoChange"
|
||||
case .userProfileUpdated: return "userProfileUpdated"
|
||||
@ -735,6 +737,7 @@ public enum ChatResponse: Decodable, Error {
|
||||
case let .contactAlreadyExists(u, contact): return withUser(u, String(describing: contact))
|
||||
case let .contactRequestAlreadyAccepted(u, contact): return withUser(u, String(describing: contact))
|
||||
case let .contactDeleted(u, contact): return withUser(u, String(describing: contact))
|
||||
case let .contactDeletedByContact(u, contact): return withUser(u, String(describing: contact))
|
||||
case let .chatCleared(u, chatInfo): return withUser(u, String(describing: chatInfo))
|
||||
case .userProfileNoChange: return noDetails
|
||||
case let .userProfileUpdated(u, _, toProfile, _): return withUser(u, String(describing: toProfile))
|
||||
@ -1420,6 +1423,7 @@ public enum ChatErrorType: Decodable {
|
||||
case invalidConnReq
|
||||
case invalidChatMessage(connection: Connection, message: String)
|
||||
case contactNotReady(contact: Contact)
|
||||
case contactNotActive(contact: Contact)
|
||||
case contactDisabled(contact: Contact)
|
||||
case connectionDisabled(connection: Connection)
|
||||
case groupUserRole(groupInfo: GroupInfo, requiredRole: GroupMemberRole)
|
||||
|
@ -1373,6 +1373,7 @@ public struct Contact: Identifiable, Decodable, NamedChat {
|
||||
public var activeConn: Connection
|
||||
public var viaGroup: Int64?
|
||||
public var contactUsed: Bool
|
||||
public var contactStatus: ContactStatus
|
||||
public var chatSettings: ChatSettings
|
||||
public var userPreferences: Preferences
|
||||
public var mergedPreferences: ContactUserPreferences
|
||||
@ -1384,8 +1385,9 @@ public struct Contact: Identifiable, Decodable, NamedChat {
|
||||
public var id: ChatId { get { "@\(contactId)" } }
|
||||
public var apiId: Int64 { get { contactId } }
|
||||
public var ready: Bool { get { activeConn.connStatus == .ready } }
|
||||
public var active: Bool { get { contactStatus == .active } }
|
||||
public var sendMsgEnabled: Bool { get {
|
||||
(ready && !(activeConn.connectionStats?.ratchetSyncSendProhibited ?? false))
|
||||
(ready && active && !(activeConn.connectionStats?.ratchetSyncSendProhibited ?? false))
|
||||
|| nextSendGrpInv
|
||||
} }
|
||||
public var nextSendGrpInv: Bool { get { contactGroupMemberId != nil && !contactGrpInvSent } }
|
||||
@ -1430,6 +1432,7 @@ public struct Contact: Identifiable, Decodable, NamedChat {
|
||||
profile: LocalProfile.sampleData,
|
||||
activeConn: Connection.sampleData,
|
||||
contactUsed: true,
|
||||
contactStatus: .active,
|
||||
chatSettings: ChatSettings.defaults,
|
||||
userPreferences: Preferences.sampleData,
|
||||
mergedPreferences: ContactUserPreferences.sampleData,
|
||||
@ -1439,6 +1442,11 @@ public struct Contact: Identifiable, Decodable, NamedChat {
|
||||
)
|
||||
}
|
||||
|
||||
public enum ContactStatus: String, Decodable {
|
||||
case active = "active"
|
||||
case deleted = "deleted"
|
||||
}
|
||||
|
||||
public struct ContactRef: Decodable, Equatable {
|
||||
var contactId: Int64
|
||||
public var agentConnId: String
|
||||
@ -2091,6 +2099,7 @@ public struct ChatItem: Identifiable, Decodable {
|
||||
case .rcvDecryptionError: return showNtfDir
|
||||
case .rcvGroupInvitation: return showNtfDir
|
||||
case .sndGroupInvitation: return showNtfDir
|
||||
case .rcvDirectEvent: return false
|
||||
case .rcvGroupEvent(rcvGroupEvent: let rcvGroupEvent):
|
||||
switch rcvGroupEvent {
|
||||
case .groupUpdated: return false
|
||||
@ -2513,6 +2522,7 @@ public enum CIContent: Decodable, ItemContent {
|
||||
case rcvDecryptionError(msgDecryptError: MsgDecryptError, msgCount: UInt32)
|
||||
case rcvGroupInvitation(groupInvitation: CIGroupInvitation, memberRole: GroupMemberRole)
|
||||
case sndGroupInvitation(groupInvitation: CIGroupInvitation, memberRole: GroupMemberRole)
|
||||
case rcvDirectEvent(rcvDirectEvent: RcvDirectEvent)
|
||||
case rcvGroupEvent(rcvGroupEvent: RcvGroupEvent)
|
||||
case sndGroupEvent(sndGroupEvent: SndGroupEvent)
|
||||
case rcvConnEvent(rcvConnEvent: RcvConnEvent)
|
||||
@ -2542,6 +2552,7 @@ public enum CIContent: Decodable, ItemContent {
|
||||
case let .rcvDecryptionError(msgDecryptError, _): return msgDecryptError.text
|
||||
case let .rcvGroupInvitation(groupInvitation, _): return groupInvitation.text
|
||||
case let .sndGroupInvitation(groupInvitation, _): return groupInvitation.text
|
||||
case let .rcvDirectEvent(rcvDirectEvent): return rcvDirectEvent.text
|
||||
case let .rcvGroupEvent(rcvGroupEvent): return rcvGroupEvent.text
|
||||
case let .sndGroupEvent(sndGroupEvent): return sndGroupEvent.text
|
||||
case let .rcvConnEvent(rcvConnEvent): return rcvConnEvent.text
|
||||
@ -3195,6 +3206,16 @@ public enum CIGroupInvitationStatus: String, Decodable {
|
||||
case expired
|
||||
}
|
||||
|
||||
public enum RcvDirectEvent: Decodable {
|
||||
case contactDeleted
|
||||
|
||||
var text: String {
|
||||
switch self {
|
||||
case .contactDeleted: return NSLocalizedString("deleted contact", comment: "rcv direct event chat item")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum RcvGroupEvent: Decodable {
|
||||
case memberAdded(groupMemberId: Int64, profile: Profile)
|
||||
case memberConnected
|
||||
|
Loading…
Reference in New Issue
Block a user