android, desktop: notify contact about contact deletion (#3139)
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
This commit is contained in:
parent
957f3b3eb0
commit
682dfe503c
@ -797,6 +797,7 @@ data class Contact(
|
||||
val activeConn: Connection,
|
||||
val viaGroup: Long? = null,
|
||||
val contactUsed: Boolean,
|
||||
val contactStatus: ContactStatus,
|
||||
val chatSettings: ChatSettings,
|
||||
val userPreferences: ChatPreferences,
|
||||
val mergedPreferences: ContactUserPreferences,
|
||||
@ -809,8 +810,9 @@ data class Contact(
|
||||
override val id get() = "@$contactId"
|
||||
override val apiId get() = contactId
|
||||
override val ready get() = activeConn.connStatus == ConnStatus.Ready
|
||||
val active get() = contactStatus == ContactStatus.Active
|
||||
override val sendMsgEnabled get() =
|
||||
(ready && !(activeConn.connectionStats?.ratchetSyncSendProhibited ?: false))
|
||||
(ready && active && !(activeConn.connectionStats?.ratchetSyncSendProhibited ?: false))
|
||||
|| nextSendGrpInv
|
||||
val nextSendGrpInv get() = contactGroupMemberId != null && !contactGrpInvSent
|
||||
override val ntfsEnabled get() = chatSettings.enableNtfs
|
||||
@ -859,6 +861,7 @@ data class Contact(
|
||||
profile = LocalProfile.sampleData,
|
||||
activeConn = Connection.sampleData,
|
||||
contactUsed = true,
|
||||
contactStatus = ContactStatus.Active,
|
||||
chatSettings = ChatSettings(enableNtfs = true, sendRcpts = null, favorite = false),
|
||||
userPreferences = ChatPreferences.sampleData,
|
||||
mergedPreferences = ContactUserPreferences.sampleData,
|
||||
@ -869,6 +872,12 @@ data class Contact(
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class ContactStatus {
|
||||
@SerialName("active") Active,
|
||||
@SerialName("deleted") Deleted;
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ContactRef(
|
||||
val contactId: Long,
|
||||
@ -1471,6 +1480,7 @@ data class ChatItem (
|
||||
is CIContent.RcvDecryptionError -> showNtfDir
|
||||
is CIContent.RcvGroupInvitation -> showNtfDir
|
||||
is CIContent.SndGroupInvitation -> showNtfDir
|
||||
is CIContent.RcvDirectEventContent -> false
|
||||
is CIContent.RcvGroupEventContent -> when (content.rcvGroupEvent) {
|
||||
is RcvGroupEvent.MemberAdded -> false
|
||||
is RcvGroupEvent.MemberConnected -> false
|
||||
@ -1854,6 +1864,7 @@ sealed class CIContent: ItemContent {
|
||||
@Serializable @SerialName("rcvDecryptionError") class RcvDecryptionError(val msgDecryptError: MsgDecryptError, val msgCount: UInt): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvGroupInvitation") class RcvGroupInvitation(val groupInvitation: CIGroupInvitation, val memberRole: GroupMemberRole): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("sndGroupInvitation") class SndGroupInvitation(val groupInvitation: CIGroupInvitation, val memberRole: GroupMemberRole): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvDirectEvent") class RcvDirectEventContent(val rcvDirectEvent: RcvDirectEvent): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvGroupEvent") class RcvGroupEventContent(val rcvGroupEvent: RcvGroupEvent): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("sndGroupEvent") class SndGroupEventContent(val sndGroupEvent: SndGroupEvent): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@Serializable @SerialName("rcvConnEvent") class RcvConnEventContent(val rcvConnEvent: RcvConnEvent): CIContent() { override val msgContent: MsgContent? get() = null }
|
||||
@ -1881,6 +1892,7 @@ sealed class CIContent: ItemContent {
|
||||
is RcvDecryptionError -> msgDecryptError.text
|
||||
is RcvGroupInvitation -> groupInvitation.text
|
||||
is SndGroupInvitation -> groupInvitation.text
|
||||
is RcvDirectEventContent -> rcvDirectEvent.text
|
||||
is RcvGroupEventContent -> rcvGroupEvent.text
|
||||
is SndGroupEventContent -> sndGroupEvent.text
|
||||
is RcvConnEventContent -> rcvConnEvent.text
|
||||
@ -2487,6 +2499,15 @@ sealed class MsgErrorType() {
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
sealed class RcvDirectEvent() {
|
||||
@Serializable @SerialName("contactDeleted") class ContactDeleted(): RcvDirectEvent()
|
||||
|
||||
val text: String get() = when (this) {
|
||||
is ContactDeleted -> generalGetString(MR.strings.rcv_direct_event_contact_deleted)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
sealed class RcvGroupEvent() {
|
||||
@Serializable @SerialName("memberAdded") class MemberAdded(val groupMemberId: Long, val profile: Profile): RcvGroupEvent()
|
||||
|
@ -1366,6 +1366,11 @@ object ChatController {
|
||||
chatModel.removeChat(r.connection.id)
|
||||
}
|
||||
}
|
||||
is CR.ContactDeletedByContact -> {
|
||||
if (active(r.user) && r.contact.directOrUsed) {
|
||||
chatModel.updateContact(r.contact)
|
||||
}
|
||||
}
|
||||
is CR.ContactConnected -> {
|
||||
if (active(r.user) && r.contact.directOrUsed) {
|
||||
chatModel.updateContact(r.contact)
|
||||
@ -3304,6 +3309,7 @@ sealed class CR {
|
||||
@Serializable @SerialName("contactAlreadyExists") class ContactAlreadyExists(val user: UserRef, val contact: Contact): CR()
|
||||
@Serializable @SerialName("contactRequestAlreadyAccepted") class ContactRequestAlreadyAccepted(val user: UserRef, val contact: Contact): CR()
|
||||
@Serializable @SerialName("contactDeleted") class ContactDeleted(val user: UserRef, val contact: Contact): CR()
|
||||
@Serializable @SerialName("contactDeletedByContact") class ContactDeletedByContact(val user: UserRef, val contact: Contact): CR()
|
||||
@Serializable @SerialName("chatCleared") class ChatCleared(val user: UserRef, val chatInfo: ChatInfo): CR()
|
||||
@Serializable @SerialName("userProfileNoChange") class UserProfileNoChange(val user: User): CR()
|
||||
@Serializable @SerialName("userProfileUpdated") class UserProfileUpdated(val user: User, val fromProfile: Profile, val toProfile: Profile, val updateSummary: UserProfileUpdateSummary): CR()
|
||||
@ -3435,6 +3441,7 @@ sealed class CR {
|
||||
is ContactAlreadyExists -> "contactAlreadyExists"
|
||||
is ContactRequestAlreadyAccepted -> "contactRequestAlreadyAccepted"
|
||||
is ContactDeleted -> "contactDeleted"
|
||||
is ContactDeletedByContact -> "contactDeletedByContact"
|
||||
is ChatCleared -> "chatCleared"
|
||||
is UserProfileNoChange -> "userProfileNoChange"
|
||||
is UserProfileUpdated -> "userProfileUpdated"
|
||||
@ -3563,6 +3570,7 @@ sealed class CR {
|
||||
is ContactAlreadyExists -> withUser(user, json.encodeToString(contact))
|
||||
is ContactRequestAlreadyAccepted -> withUser(user, json.encodeToString(contact))
|
||||
is ContactDeleted -> withUser(user, json.encodeToString(contact))
|
||||
is ContactDeletedByContact -> withUser(user, json.encodeToString(contact))
|
||||
is ChatCleared -> withUser(user, json.encodeToString(chatInfo))
|
||||
is UserProfileNoChange -> withUser(user, noDetails())
|
||||
is UserProfileUpdated -> withUser(user, json.encodeToString(toProfile))
|
||||
@ -3831,6 +3839,7 @@ sealed class ChatErrorType {
|
||||
is InvalidConnReq -> "invalidConnReq"
|
||||
is InvalidChatMessage -> "invalidChatMessage"
|
||||
is ContactNotReady -> "contactNotReady"
|
||||
is ContactNotActive -> "contactNotActive"
|
||||
is ContactDisabled -> "contactDisabled"
|
||||
is ConnectionDisabled -> "connectionDisabled"
|
||||
is GroupUserRole -> "groupUserRole"
|
||||
@ -3906,6 +3915,7 @@ sealed class ChatErrorType {
|
||||
@Serializable @SerialName("invalidConnReq") object InvalidConnReq: ChatErrorType()
|
||||
@Serializable @SerialName("invalidChatMessage") class InvalidChatMessage(val connection: Connection, val message: String): ChatErrorType()
|
||||
@Serializable @SerialName("contactNotReady") class ContactNotReady(val contact: Contact): ChatErrorType()
|
||||
@Serializable @SerialName("contactNotActive") class ContactNotActive(val contact: Contact): ChatErrorType()
|
||||
@Serializable @SerialName("contactDisabled") class ContactDisabled(val contact: Contact): ChatErrorType()
|
||||
@Serializable @SerialName("connectionDisabled") class ConnectionDisabled(val connection: Connection): ChatErrorType()
|
||||
@Serializable @SerialName("groupUserRole") class GroupUserRole(val groupInfo: GroupInfo, val requiredRole: GroupMemberRole): ChatErrorType()
|
||||
|
@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.*
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@ -291,7 +290,7 @@ fun ChatInfoLayout(
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
if (contact.ready) {
|
||||
if (contact.ready && contact.active) {
|
||||
SectionView {
|
||||
if (connectionCode != null) {
|
||||
VerifyCodeButton(contact.verified, verifyClicked)
|
||||
@ -318,7 +317,7 @@ fun ChatInfoLayout(
|
||||
SectionDividerSpaced()
|
||||
}
|
||||
|
||||
if (contact.ready) {
|
||||
if (contact.ready && contact.active) {
|
||||
SectionView(title = stringResource(MR.strings.conn_stats_section_title_servers)) {
|
||||
SectionItemView({
|
||||
AlertManager.shared.showAlertMsg(
|
||||
|
@ -118,7 +118,12 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
|
||||
Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
if (chat.chatInfo is ChatInfo.Direct && !chat.chatInfo.contact.ready && !chat.chatInfo.contact.nextSendGrpInv) {
|
||||
if (
|
||||
chat.chatInfo is ChatInfo.Direct
|
||||
&& !chat.chatInfo.contact.ready
|
||||
&& chat.chatInfo.contact.active
|
||||
&& !chat.chatInfo.contact.nextSendGrpInv
|
||||
) {
|
||||
Text(
|
||||
generalGetString(MR.strings.contact_connection_pending),
|
||||
Modifier.padding(top = 4.dp),
|
||||
@ -550,15 +555,15 @@ fun ChatInfoToolbar(
|
||||
showMenu.value = false
|
||||
startCall(CallMediaType.Audio)
|
||||
},
|
||||
enabled = chat.chatInfo.contact.ready) {
|
||||
enabled = chat.chatInfo.contact.ready && chat.chatInfo.contact.active) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_call_500),
|
||||
stringResource(MR.strings.icon_descr_more_button),
|
||||
tint = if (chat.chatInfo.contact.ready) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
|
||||
tint = if (chat.chatInfo.contact.ready && chat.chatInfo.contact.active) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
if (chat.chatInfo.contact.ready) {
|
||||
if (chat.chatInfo.contact.ready && chat.chatInfo.contact.active) {
|
||||
menuItems.add {
|
||||
ItemAction(stringResource(MR.strings.icon_descr_video_call).capitalize(Locale.current), painterResource(MR.images.ic_videocam), onClick = {
|
||||
showMenu.value = false
|
||||
@ -576,7 +581,7 @@ fun ChatInfoToolbar(
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((chat.chatInfo is ChatInfo.Direct && chat.chatInfo.contact.ready) || chat.chatInfo is ChatInfo.Group) {
|
||||
if ((chat.chatInfo is ChatInfo.Direct && chat.chatInfo.contact.ready && chat.chatInfo.contact.active) || chat.chatInfo is ChatInfo.Group) {
|
||||
val ntfsEnabled = remember { mutableStateOf(chat.chatInfo.ntfsEnabled) }
|
||||
menuItems.add {
|
||||
ItemAction(
|
||||
|
@ -352,6 +352,7 @@ fun ChatItemView(
|
||||
is CIContent.RcvDecryptionError -> CIRcvDecryptionError(c.msgDecryptError, c.msgCount, cInfo, cItem, updateContactStats = updateContactStats, updateMemberStats = updateMemberStats, syncContactConnection = syncContactConnection, syncMemberConnection = syncMemberConnection, findModelChat = findModelChat, findModelMember = findModelMember)
|
||||
is CIContent.RcvGroupInvitation -> CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito)
|
||||
is CIContent.SndGroupInvitation -> CIGroupInvitationView(cItem, c.groupInvitation, c.memberRole, joinGroup = joinGroup, chatIncognito = cInfo.incognito)
|
||||
is CIContent.RcvDirectEventContent -> EventItemView()
|
||||
is CIContent.RcvGroupEventContent -> when (c.rcvGroupEvent) {
|
||||
is RcvGroupEvent.MemberConnected -> CIEventView(membersConnectedItemText())
|
||||
is RcvGroupEvent.MemberCreatedContact -> CIMemberCreatedContactView(cItem, openDirectChat)
|
||||
|
@ -42,7 +42,7 @@ fun ChatPreviewView(
|
||||
val cInfo = chat.chatInfo
|
||||
|
||||
@Composable
|
||||
fun groupInactiveIcon() {
|
||||
fun inactiveIcon() {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_cancel_filled),
|
||||
stringResource(MR.strings.icon_descr_group_inactive),
|
||||
@ -53,13 +53,19 @@ fun ChatPreviewView(
|
||||
|
||||
@Composable
|
||||
fun chatPreviewImageOverlayIcon() {
|
||||
if (cInfo is ChatInfo.Group) {
|
||||
when (cInfo.groupInfo.membership.memberStatus) {
|
||||
GroupMemberStatus.MemLeft -> groupInactiveIcon()
|
||||
GroupMemberStatus.MemRemoved -> groupInactiveIcon()
|
||||
GroupMemberStatus.MemGroupDeleted -> groupInactiveIcon()
|
||||
else -> {}
|
||||
when (cInfo) {
|
||||
is ChatInfo.Direct ->
|
||||
if (!cInfo.contact.active) {
|
||||
inactiveIcon()
|
||||
}
|
||||
is ChatInfo.Group ->
|
||||
when (cInfo.groupInfo.membership.memberStatus) {
|
||||
GroupMemberStatus.MemLeft -> inactiveIcon()
|
||||
GroupMemberStatus.MemRemoved -> inactiveIcon()
|
||||
GroupMemberStatus.MemGroupDeleted -> inactiveIcon()
|
||||
else -> {}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +131,7 @@ fun ChatPreviewView(
|
||||
if (cInfo.contact.verified) {
|
||||
VerifiedIcon()
|
||||
}
|
||||
chatPreviewTitleText(if (cInfo.ready) Color.Unspecified else MaterialTheme.colors.secondary)
|
||||
chatPreviewTitleText()
|
||||
}
|
||||
is ChatInfo.Group ->
|
||||
when (cInfo.groupInfo.membership.memberStatus) {
|
||||
@ -174,7 +180,7 @@ fun ChatPreviewView(
|
||||
is ChatInfo.Direct ->
|
||||
if (cInfo.contact.nextSendGrpInv) {
|
||||
Text(stringResource(MR.strings.member_contact_send_direct_message), color = MaterialTheme.colors.secondary)
|
||||
} else if (!cInfo.ready) {
|
||||
} else if (!cInfo.ready && cInfo.contact.active) {
|
||||
Text(stringResource(MR.strings.contact_connection_pending), color = MaterialTheme.colors.secondary)
|
||||
}
|
||||
is ChatInfo.Group ->
|
||||
@ -191,28 +197,32 @@ fun ChatPreviewView(
|
||||
@Composable
|
||||
fun chatStatusImage() {
|
||||
if (cInfo is ChatInfo.Direct) {
|
||||
val descr = contactNetworkStatus?.statusString
|
||||
when (contactNetworkStatus) {
|
||||
is NetworkStatus.Connected ->
|
||||
IncognitoIcon(chat.chatInfo.incognito)
|
||||
if (cInfo.contact.active) {
|
||||
val descr = contactNetworkStatus?.statusString
|
||||
when (contactNetworkStatus) {
|
||||
is NetworkStatus.Connected ->
|
||||
IncognitoIcon(chat.chatInfo.incognito)
|
||||
|
||||
is NetworkStatus.Error ->
|
||||
Icon(
|
||||
painterResource(MR.images.ic_error),
|
||||
contentDescription = descr,
|
||||
tint = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier
|
||||
.size(19.dp)
|
||||
)
|
||||
is NetworkStatus.Error ->
|
||||
Icon(
|
||||
painterResource(MR.images.ic_error),
|
||||
contentDescription = descr,
|
||||
tint = MaterialTheme.colors.secondary,
|
||||
modifier = Modifier
|
||||
.size(19.dp)
|
||||
)
|
||||
|
||||
else ->
|
||||
CircularProgressIndicator(
|
||||
Modifier
|
||||
.padding(horizontal = 2.dp)
|
||||
.size(15.dp),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
strokeWidth = 1.5.dp
|
||||
)
|
||||
else ->
|
||||
CircularProgressIndicator(
|
||||
Modifier
|
||||
.padding(horizontal = 2.dp)
|
||||
.size(15.dp),
|
||||
color = MaterialTheme.colors.secondary,
|
||||
strokeWidth = 1.5.dp
|
||||
)
|
||||
}
|
||||
} else {
|
||||
IncognitoIcon(chat.chatInfo.incognito)
|
||||
}
|
||||
} else {
|
||||
IncognitoIcon(chat.chatInfo.incognito)
|
||||
|
@ -1105,6 +1105,9 @@
|
||||
<string name="you_rejected_group_invitation">You rejected group invitation</string>
|
||||
<string name="group_invitation_expired">Group invitation expired</string>
|
||||
|
||||
<!-- Direct event chat items -->
|
||||
<string name="rcv_direct_event_contact_deleted">deleted contact</string>
|
||||
|
||||
<!-- Group event chat items -->
|
||||
<string name="rcv_group_event_member_added">invited %1$s</string>
|
||||
<string name="rcv_group_event_member_connected">connected</string>
|
||||
|
Loading…
Reference in New Issue
Block a user