mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-05-25 12:04:22 +00:00
core, ui: prohibit changing profile for prepared entity when first attempt to connect failed (#6037)
* core: prohibit changing profile for prepared entity when first attempt to connect failed * reuse incognito * schema * ios * postgres schema * ios * reenable tests * kotlin * update alert * rename predicate, combine queries * send the correct incognito mode, fail on attempt to change mode for prepared connection * query plans * ui: show group connecting status --------- Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
+25
-2
@@ -1288,6 +1288,8 @@ interface SomeChat {
|
||||
val ready: Boolean
|
||||
val chatDeleted: Boolean
|
||||
val nextConnect: Boolean
|
||||
val nextConnectPrepared: Boolean
|
||||
val profileChangeProhibited: Boolean
|
||||
val incognito: Boolean
|
||||
fun featureEnabled(feature: ChatFeature): Boolean
|
||||
val timedMessagesTTL: Int?
|
||||
@@ -1368,6 +1370,8 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val ready get() = contact.ready
|
||||
override val chatDeleted get() = contact.chatDeleted
|
||||
override val nextConnect get() = contact.nextConnect
|
||||
override val nextConnectPrepared get() = contact.nextConnectPrepared
|
||||
override val profileChangeProhibited get() = contact.profileChangeProhibited
|
||||
override val incognito get() = contact.incognito
|
||||
override fun featureEnabled(feature: ChatFeature) = contact.featureEnabled(feature)
|
||||
override val timedMessagesTTL: Int? get() = contact.timedMessagesTTL
|
||||
@@ -1393,6 +1397,8 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val ready get() = groupInfo.ready
|
||||
override val chatDeleted get() = groupInfo.chatDeleted
|
||||
override val nextConnect get() = groupInfo.nextConnect
|
||||
override val nextConnectPrepared get() = groupInfo.nextConnectPrepared
|
||||
override val profileChangeProhibited get() = groupInfo.profileChangeProhibited
|
||||
override val incognito get() = groupInfo.incognito
|
||||
override fun featureEnabled(feature: ChatFeature) = groupInfo.featureEnabled(feature)
|
||||
override val timedMessagesTTL: Int? get() = groupInfo.timedMessagesTTL
|
||||
@@ -1417,6 +1423,8 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val ready get() = noteFolder.ready
|
||||
override val chatDeleted get() = noteFolder.chatDeleted
|
||||
override val nextConnect get() = noteFolder.nextConnect
|
||||
override val nextConnectPrepared get() = noteFolder.nextConnectPrepared
|
||||
override val profileChangeProhibited get() = noteFolder.profileChangeProhibited
|
||||
override val incognito get() = noteFolder.incognito
|
||||
override fun featureEnabled(feature: ChatFeature) = noteFolder.featureEnabled(feature)
|
||||
override val timedMessagesTTL: Int? get() = noteFolder.timedMessagesTTL
|
||||
@@ -1441,6 +1449,8 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val ready get() = contactRequest.ready
|
||||
override val chatDeleted get() = contactRequest.chatDeleted
|
||||
override val nextConnect get() = contactRequest.nextConnect
|
||||
override val nextConnectPrepared get() = contactRequest.nextConnectPrepared
|
||||
override val profileChangeProhibited get() = contactRequest.profileChangeProhibited
|
||||
override val incognito get() = contactRequest.incognito
|
||||
override fun featureEnabled(feature: ChatFeature) = contactRequest.featureEnabled(feature)
|
||||
override val timedMessagesTTL: Int? get() = contactRequest.timedMessagesTTL
|
||||
@@ -1465,6 +1475,8 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val ready get() = contactConnection.ready
|
||||
override val chatDeleted get() = contactConnection.chatDeleted
|
||||
override val nextConnect get() = contactConnection.nextConnect
|
||||
override val nextConnectPrepared get() = contactConnection.nextConnectPrepared
|
||||
override val profileChangeProhibited get() = contactConnection.profileChangeProhibited
|
||||
override val incognito get() = contactConnection.incognito
|
||||
override fun featureEnabled(feature: ChatFeature) = contactConnection.featureEnabled(feature)
|
||||
override val timedMessagesTTL: Int? get() = contactConnection.timedMessagesTTL
|
||||
@@ -1494,6 +1506,8 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
override val ready get() = false
|
||||
override val chatDeleted get() = false
|
||||
override val nextConnect get() = false
|
||||
override val nextConnectPrepared get() = false
|
||||
override val profileChangeProhibited get() = false
|
||||
override val incognito get() = false
|
||||
override fun featureEnabled(feature: ChatFeature) = false
|
||||
override val timedMessagesTTL: Int? get() = null
|
||||
@@ -1688,7 +1702,8 @@ data class Contact(
|
||||
val active get() = contactStatus == ContactStatus.Active
|
||||
override val nextConnect get() = sendMsgToConnect
|
||||
val nextSendGrpInv get() = contactGroupMemberId != null && !contactGrpInvSent
|
||||
val nextConnectPrepared get() = preparedContact != null && (activeConn == null || activeConn.connStatus == ConnStatus.Prepared)
|
||||
override val nextConnectPrepared get() = preparedContact != null && (activeConn == null || activeConn.connStatus == ConnStatus.Prepared)
|
||||
override val profileChangeProhibited get() = activeConn != null
|
||||
val nextAcceptContactRequest get() = contactRequestId != null && (activeConn == null || activeConn.connStatus == ConnStatus.New)
|
||||
val sendMsgToConnect get() = nextSendGrpInv || nextConnectPrepared
|
||||
override val incognito get() = contactConnIncognito
|
||||
@@ -1942,7 +1957,8 @@ data class GroupInfo (
|
||||
override val apiId get() = groupId
|
||||
override val ready get() = membership.memberActive
|
||||
override val nextConnect get() = nextConnectPrepared
|
||||
val nextConnectPrepared = if (preparedGroup != null) !preparedGroup.connLinkStartedConnection else false
|
||||
override val nextConnectPrepared = if (preparedGroup != null) !preparedGroup.connLinkStartedConnection else false
|
||||
override val profileChangeProhibited get() = preparedGroup?.connLinkPreparedConnection ?: false
|
||||
override val chatDeleted get() = false
|
||||
override val incognito get() = membership.memberIncognito
|
||||
override fun featureEnabled(feature: ChatFeature) = when (feature) {
|
||||
@@ -2015,6 +2031,7 @@ data class GroupInfo (
|
||||
@Serializable
|
||||
data class PreparedGroup (
|
||||
val connLinkToConnect: CreatedConnLink,
|
||||
val connLinkPreparedConnection: Boolean,
|
||||
val connLinkStartedConnection: Boolean
|
||||
)
|
||||
|
||||
@@ -2396,6 +2413,8 @@ class NoteFolder(
|
||||
override val chatDeleted get() = false
|
||||
override val ready get() = true
|
||||
override val nextConnect get() = false
|
||||
override val nextConnectPrepared get() = false
|
||||
override val profileChangeProhibited get() = false
|
||||
override val incognito get() = false
|
||||
override fun featureEnabled(feature: ChatFeature) = feature == ChatFeature.Voice
|
||||
override val timedMessagesTTL: Int? get() = null
|
||||
@@ -2432,6 +2451,8 @@ class UserContactRequest (
|
||||
override val chatDeleted get() = false
|
||||
override val ready get() = true
|
||||
override val nextConnect get() = false
|
||||
override val nextConnectPrepared get() = false
|
||||
override val profileChangeProhibited get() = false
|
||||
override val incognito get() = false
|
||||
override fun featureEnabled(feature: ChatFeature) = false
|
||||
override val timedMessagesTTL: Int? get() = null
|
||||
@@ -2473,6 +2494,8 @@ class PendingContactConnection(
|
||||
override val chatDeleted get() = false
|
||||
override val ready get() = false
|
||||
override val nextConnect get() = false
|
||||
override val nextConnectPrepared get() = false
|
||||
override val profileChangeProhibited get() = false
|
||||
override val incognito get() = customUserProfileId != null
|
||||
override fun featureEnabled(feature: ChatFeature) = false
|
||||
override val timedMessagesTTL: Int? get() = null
|
||||
|
||||
+9
@@ -2510,6 +2510,12 @@ object ChatController {
|
||||
chatModel.networkStatuses[s.agentConnId] = s.networkStatus
|
||||
}
|
||||
}
|
||||
is CR.ChatInfoUpdated ->
|
||||
if (active(r.user)) {
|
||||
withContext(Dispatchers.Main) {
|
||||
chatModel.chatsContext.updateChatInfo(rhId, r.chatInfo)
|
||||
}
|
||||
}
|
||||
is CR.NewChatItems -> withBGApi {
|
||||
r.chatItems.forEach { chatItem ->
|
||||
val cInfo = chatItem.chatInfo
|
||||
@@ -5959,6 +5965,7 @@ sealed class CR {
|
||||
// TODO remove above
|
||||
@Serializable @SerialName("networkStatus") class NetworkStatusResp(val networkStatus: NetworkStatus, val connections: List<String>): CR()
|
||||
@Serializable @SerialName("networkStatuses") class NetworkStatuses(val user_: UserRef?, val networkStatuses: List<ConnNetworkStatus>): CR()
|
||||
@Serializable @SerialName("chatInfoUpdated") class ChatInfoUpdated(val user: UserRef, val chatInfo: ChatInfo): CR()
|
||||
@Serializable @SerialName("newChatItems") class NewChatItems(val user: UserRef, val chatItems: List<AChatItem>): CR()
|
||||
@Serializable @SerialName("chatItemsStatusesUpdated") class ChatItemsStatusesUpdated(val user: UserRef, val chatItems: List<AChatItem>): CR()
|
||||
@Serializable @SerialName("chatItemUpdated") class ChatItemUpdated(val user: UserRef, val chatItem: AChatItem): CR()
|
||||
@@ -6144,6 +6151,7 @@ sealed class CR {
|
||||
is ContactSubSummary -> "contactSubSummary"
|
||||
is NetworkStatusResp -> "networkStatus"
|
||||
is NetworkStatuses -> "networkStatuses"
|
||||
is ChatInfoUpdated -> "chatInfoUpdated"
|
||||
is NewChatItems -> "newChatItems"
|
||||
is ChatItemsStatusesUpdated -> "chatItemsStatusesUpdated"
|
||||
is ChatItemUpdated -> "chatItemUpdated"
|
||||
@@ -6321,6 +6329,7 @@ sealed class CR {
|
||||
is ContactSubSummary -> withUser(user, json.encodeToString(contactSubscriptions))
|
||||
is NetworkStatusResp -> "networkStatus $networkStatus\nconnections: $connections"
|
||||
is NetworkStatuses -> withUser(user_, json.encodeToString(networkStatuses))
|
||||
is ChatInfoUpdated -> withUser(user, json.encodeToString(chatInfo))
|
||||
is NewChatItems -> withUser(user, chatItems.joinToString("\n") { json.encodeToString(it) })
|
||||
is ChatItemsStatusesUpdated -> withUser(user, chatItems.joinToString("\n") { json.encodeToString(it) })
|
||||
is ChatItemUpdated -> withUser(user, json.encodeToString(chatItem))
|
||||
|
||||
+2
-1
@@ -729,7 +729,8 @@ private fun connectingText(chatInfo: ChatInfo): String? {
|
||||
|
||||
is ChatInfo.Group ->
|
||||
when (chatInfo.groupInfo.membership.memberStatus) {
|
||||
GroupMemberStatus.MemAccepted -> generalGetString(MR.strings.group_connection_pending) // TODO [short links] add member status to show transition from prepared group to started connection earlier?
|
||||
GroupMemberStatus.MemUnknown -> if (chatInfo.groupInfo.preparedGroup?.connLinkStartedConnection == true) generalGetString(MR.strings.group_connection_pending) else null
|
||||
GroupMemberStatus.MemAccepted -> generalGetString(MR.strings.group_connection_pending)
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
+38
-17
@@ -65,7 +65,7 @@ fun ComposeContextProfilePickerView(
|
||||
Modifier.size(20.dp),
|
||||
tint = MaterialTheme.colors.secondary,
|
||||
)
|
||||
} else {
|
||||
} else if (!chat.chatInfo.profileChangeProhibited) {
|
||||
Icon(
|
||||
painterResource(
|
||||
MR.images.ic_chevron_up
|
||||
@@ -103,14 +103,21 @@ fun ComposeContextProfilePickerView(
|
||||
keepingChatId = chat.id
|
||||
)
|
||||
if (chatModel.currentUser.value?.userId != newUser.userId) {
|
||||
AlertManager.shared.showAlertMsg(generalGetString(
|
||||
MR.strings.switching_profile_error_title),
|
||||
AlertManager.shared.showAlertMsg(
|
||||
generalGetString(MR.strings.switching_profile_error_title),
|
||||
String.format(generalGetString(MR.strings.switching_profile_error_message), newUser.chatViewName)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showCantChangeProfileAlert() {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
generalGetString(MR.strings.context_user_picker_cant_change_profile_alert_title),
|
||||
generalGetString(MR.strings.context_user_picker_cant_change_profile_alert_message)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ProfilePickerUserOption(user: User) {
|
||||
Row(
|
||||
@@ -118,15 +125,19 @@ fun ComposeContextProfilePickerView(
|
||||
.fillMaxWidth()
|
||||
.sizeIn(minHeight = DEFAULT_MIN_SECTION_ITEM_HEIGHT + 8.dp)
|
||||
.clickable(onClick = {
|
||||
if (selectedUser.value.userId == user.userId) {
|
||||
if (!incognitoDefault) {
|
||||
listExpanded.value = !listExpanded.value
|
||||
if (!chat.chatInfo.profileChangeProhibited) {
|
||||
if (selectedUser.value.userId == user.userId) {
|
||||
if (!incognitoDefault) {
|
||||
listExpanded.value = !listExpanded.value
|
||||
} else {
|
||||
chatModel.controller.appPrefs.incognito.set(false)
|
||||
listExpanded.value = false
|
||||
}
|
||||
} else {
|
||||
chatModel.controller.appPrefs.incognito.set(false)
|
||||
listExpanded.value = false
|
||||
changeProfile(user)
|
||||
}
|
||||
} else {
|
||||
changeProfile(user)
|
||||
showCantChangeProfileAlert()
|
||||
}
|
||||
})
|
||||
.padding(horizontal = DEFAULT_PADDING_HALF, vertical = 4.dp),
|
||||
@@ -156,11 +167,15 @@ fun ComposeContextProfilePickerView(
|
||||
.fillMaxWidth()
|
||||
.sizeIn(minHeight = DEFAULT_MIN_SECTION_ITEM_HEIGHT + 8.dp)
|
||||
.clickable(onClick = {
|
||||
if (incognitoDefault) {
|
||||
listExpanded.value = !listExpanded.value
|
||||
if (!chat.chatInfo.profileChangeProhibited) {
|
||||
if (incognitoDefault) {
|
||||
listExpanded.value = !listExpanded.value
|
||||
} else {
|
||||
chatModel.controller.appPrefs.incognito.set(true)
|
||||
listExpanded.value = false
|
||||
}
|
||||
} else {
|
||||
chatModel.controller.appPrefs.incognito.set(true)
|
||||
listExpanded.value = false
|
||||
showCantChangeProfileAlert()
|
||||
}
|
||||
})
|
||||
.padding(horizontal = DEFAULT_PADDING_HALF, vertical = 4.dp),
|
||||
@@ -265,7 +280,13 @@ fun ComposeContextProfilePickerView(
|
||||
color = MaterialTheme.colors.secondary
|
||||
)
|
||||
|
||||
if (incognitoDefault) {
|
||||
if (chat.chatInfo.profileChangeProhibited) {
|
||||
if (chat.chatInfo.incognito) {
|
||||
IncognitoOption()
|
||||
} else {
|
||||
ProfilePickerUserOption(selectedUser.value)
|
||||
}
|
||||
} else if (incognitoDefault) {
|
||||
IncognitoOption()
|
||||
} else {
|
||||
ProfilePickerUserOption(selectedUser.value)
|
||||
@@ -273,9 +294,9 @@ fun ComposeContextProfilePickerView(
|
||||
}
|
||||
}
|
||||
|
||||
if (listExpanded.value) {
|
||||
ProfilePicker()
|
||||
} else {
|
||||
if (!listExpanded.value || chat.chatInfo.profileChangeProhibited) {
|
||||
CurrentSelection()
|
||||
} else {
|
||||
ProfilePicker()
|
||||
}
|
||||
}
|
||||
|
||||
+5
-8
@@ -532,10 +532,11 @@ fun ComposeView(
|
||||
suspend fun sendConnectPreparedContact() {
|
||||
val mc = checkLinkPreview()
|
||||
sending()
|
||||
val incognito = if (chat.chatInfo.profileChangeProhibited) chat.chatInfo.incognito else chatModel.controller.appPrefs.incognito.get()
|
||||
val contact = chatModel.controller.apiConnectPreparedContact(
|
||||
rh = chat.remoteHostId,
|
||||
contactId = chat.chatInfo.apiId,
|
||||
incognito = chatModel.controller.appPrefs.incognito.get(),
|
||||
incognito = incognito,
|
||||
msg = mc
|
||||
)
|
||||
if (contact != null) {
|
||||
@@ -573,10 +574,11 @@ fun ComposeView(
|
||||
suspend fun connectPreparedGroup() {
|
||||
val mc = checkLinkPreview()
|
||||
sending()
|
||||
val incognito = if (chat.chatInfo.profileChangeProhibited) chat.chatInfo.incognito else chatModel.controller.appPrefs.incognito.get()
|
||||
val groupInfo = chatModel.controller.apiConnectPreparedGroup(
|
||||
rh = chat.remoteHostId,
|
||||
groupId = chat.chatInfo.apiId,
|
||||
incognito = chatModel.controller.appPrefs.incognito.get(),
|
||||
incognito = incognito,
|
||||
msg = mc
|
||||
)
|
||||
if (groupInfo != null) {
|
||||
@@ -1328,12 +1330,7 @@ fun ComposeView(
|
||||
|
||||
Column {
|
||||
val currentUser = chatModel.currentUser.value
|
||||
if ((
|
||||
(chat.chatInfo is ChatInfo.Direct && chat.chatInfo.contact.nextConnectPrepared)
|
||||
|| (chat.chatInfo is ChatInfo.Group && chat.chatInfo.groupInfo.nextConnectPrepared)
|
||||
)
|
||||
&& currentUser != null
|
||||
) {
|
||||
if (chat.chatInfo.nextConnectPrepared && currentUser != null) {
|
||||
ComposeContextProfilePickerView(
|
||||
rhId = rhId,
|
||||
chat = chat,
|
||||
|
||||
@@ -870,6 +870,8 @@
|
||||
|
||||
<!-- ComposeContextProfilePickerView.kt -->
|
||||
<string name="context_user_picker_your_profile">Your profile</string>
|
||||
<string name="context_user_picker_cant_change_profile_alert_title">Can\'t change profile</string>
|
||||
<string name="context_user_picker_cant_change_profile_alert_message">To use another profile after connection attempt, delete the chat and use the link again.</string>
|
||||
|
||||
<!-- ScanCodeView.kt -->
|
||||
<string name="scan_code">Scan code</string>
|
||||
|
||||
Reference in New Issue
Block a user