mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-22 17:31:55 +00:00
Merge branch 'master' into group-knocking
This commit is contained in:
54 files changed
+2194
-2244
No files matched your search
+9
-5
@@ -38,6 +38,7 @@ import java.net.URI
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.random.Random
|
||||
import kotlin.time.*
|
||||
@@ -1479,19 +1480,21 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
}
|
||||
|
||||
@Serializable @SerialName("invalidJSON")
|
||||
class InvalidJSON(val json: String): ChatInfo() {
|
||||
class InvalidJSON(
|
||||
val json: String,
|
||||
override val apiId: Long = -idGenerator.getAndIncrement(),
|
||||
override val createdAt: Instant = Clock.System.now(),
|
||||
override val updatedAt: Instant = Clock.System.now()
|
||||
): ChatInfo() {
|
||||
override val chatType get() = ChatType.Direct
|
||||
override val localDisplayName get() = invalidChatName
|
||||
override val id get() = ""
|
||||
override val apiId get() = 0L
|
||||
override val id get() = "?$apiId"
|
||||
override val ready get() = false
|
||||
override val chatDeleted get() = false
|
||||
override val sendMsgEnabled get() = false
|
||||
override val incognito get() = false
|
||||
override fun featureEnabled(feature: ChatFeature) = false
|
||||
override val timedMessagesTTL: Int? get() = null
|
||||
override val createdAt get() = Clock.System.now()
|
||||
override val updatedAt get() = Clock.System.now()
|
||||
override val displayName get() = invalidChatName
|
||||
override val fullName get() = invalidChatName
|
||||
override val image get() = null
|
||||
@@ -1499,6 +1502,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
|
||||
companion object {
|
||||
private val invalidChatName = generalGetString(MR.strings.invalid_chat)
|
||||
private val idGenerator = AtomicLong(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+548
-594
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -48,7 +48,7 @@ private fun sendCommand(chatModel: ChatModel, composeState: MutableState<Compose
|
||||
val prefPerformLA = chatModel.controller.appPrefs.performLA.get()
|
||||
val s = composeState.value.message
|
||||
if (s.text.startsWith("/sql") && (!prefPerformLA || !developerTools)) {
|
||||
val resp = CR.ChatCmdError(null, ChatError.ChatErrorChat(ChatErrorType.CommandError("Failed reading: empty")))
|
||||
val resp = API.Error(null, ChatError.ChatErrorChat(ChatErrorType.CommandError("Failed reading: empty")))
|
||||
chatModel.addTerminalItem(TerminalItem.cmd(null, CC.Console(s.text)))
|
||||
chatModel.addTerminalItem(TerminalItem.resp(null, resp))
|
||||
composeState.value = ComposeState(useLinkPreviews = false)
|
||||
|
||||
+5
-5
@@ -10,13 +10,13 @@ import kotlinx.coroutines.*
|
||||
expect fun ActiveCallView()
|
||||
|
||||
fun activeCallWaitDeliveryReceipt(scope: CoroutineScope) = scope.launch(Dispatchers.Default) {
|
||||
for (apiResp in controller.messagesChannel) {
|
||||
for (msg in controller.messagesChannel) {
|
||||
val call = chatModel.activeCall.value
|
||||
if (call == null || call.callState > CallState.InvitationSent) break
|
||||
val msg = apiResp.resp
|
||||
if (apiResp.remoteHostId == call.remoteHostId &&
|
||||
msg is CR.ChatItemsStatusesUpdated &&
|
||||
msg.chatItems.any {
|
||||
if (msg.rhId == call.remoteHostId &&
|
||||
msg is API.Result &&
|
||||
msg.res is CR.ChatItemsStatusesUpdated &&
|
||||
msg.res.chatItems.any {
|
||||
it.chatInfo.id == call.contact.id && it.chatItem.content is CIContent.SndCall && it.chatItem.meta.itemStatus is CIStatus.SndRcvd
|
||||
}
|
||||
) {
|
||||
|
||||
+5
-5
@@ -600,11 +600,11 @@ fun ChatView(
|
||||
ChatItemInfoView(chatRh, cItem, ciInfo, devTools = chatModel.controller.appPrefs.developerTools.get(), chatInfo)
|
||||
LaunchedEffect(cItem.id) {
|
||||
withContext(Dispatchers.Default) {
|
||||
for (apiResp in controller.messagesChannel) {
|
||||
val msg = apiResp.resp
|
||||
if (apiResp.remoteHostId == chatRh &&
|
||||
msg is CR.ChatItemsStatusesUpdated &&
|
||||
msg.chatItems.any { it.chatItem.id == cItem.id }
|
||||
for (msg in controller.messagesChannel) {
|
||||
if (msg.rhId == chatRh &&
|
||||
msg is API.Result &&
|
||||
msg.res is CR.ChatItemsStatusesUpdated &&
|
||||
msg.res.chatItems.any { it.chatItem.id == cItem.id }
|
||||
) {
|
||||
ciInfo = loadChatItemInfo() ?: return@withContext
|
||||
initialCiInfo = ciInfo
|
||||
|
||||
+2
-2
@@ -435,7 +435,7 @@ suspend fun encryptDatabase(
|
||||
}
|
||||
val error = m.controller.apiStorageEncryption(currentKey.value, newKey.value)
|
||||
appPrefs.encryptionStartedAt.set(null)
|
||||
val sqliteError = ((error?.chatError as? ChatError.ChatErrorDatabase)?.databaseError as? DatabaseError.ErrorExport)?.sqliteError
|
||||
val sqliteError = ((error as? ChatError.ChatErrorDatabase)?.databaseError as? DatabaseError.ErrorExport)?.sqliteError
|
||||
when {
|
||||
sqliteError is SQLiteError.ErrorNotADatabase -> {
|
||||
operationEnded(m, progressIndicator) {
|
||||
@@ -449,7 +449,7 @@ suspend fun encryptDatabase(
|
||||
error != null -> {
|
||||
operationEnded(m, progressIndicator) {
|
||||
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_encrypting_database),
|
||||
"failed to set storage encryption: ${error.responseType} ${error.details}"
|
||||
"failed to set storage encryption: error ${error.string}"
|
||||
)
|
||||
}
|
||||
false
|
||||
|
||||
+13
-13
@@ -468,12 +468,12 @@ private suspend fun MutableState<MigrationFromState>.verifyDatabasePassphrase(db
|
||||
val error = controller.testStorageEncryption(dbKey)
|
||||
if (error == null) {
|
||||
state = MigrationFromState.UploadConfirmation
|
||||
} else if (((error.chatError as? ChatError.ChatErrorDatabase)?.databaseError as? DatabaseError.ErrorOpen)?.sqliteError is SQLiteError.ErrorNotADatabase) {
|
||||
} else if (((error as? ChatError.ChatErrorDatabase)?.databaseError as? DatabaseError.ErrorOpen)?.sqliteError is SQLiteError.ErrorNotADatabase) {
|
||||
showErrorOnMigrationIfNeeded(DBMigrationResult.ErrorNotADatabase(""))
|
||||
} else {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.error),
|
||||
text = generalGetString(MR.strings.migrate_from_device_error_verifying_passphrase) + " " + error.details
|
||||
text = generalGetString(MR.strings.migrate_from_device_error_verifying_passphrase) + " " + error.string
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -556,11 +556,12 @@ private fun MutableState<MigrationFromState>.startUploading(
|
||||
) {
|
||||
withBGApi {
|
||||
chatReceiver.value = MigrationFromChatReceiver(ctrl, tempDatabaseFile) { msg ->
|
||||
when (msg) {
|
||||
val r = msg.result
|
||||
when (r) {
|
||||
is CR.SndFileProgressXFTP -> {
|
||||
val s = state
|
||||
if (s is MigrationFromState.UploadProgress && s.uploadedBytes != s.totalBytes) {
|
||||
state = MigrationFromState.UploadProgress(msg.sentSize, msg.totalSize, msg.fileTransferMeta.fileId, archivePath, ctrl, user)
|
||||
state = MigrationFromState.UploadProgress(r.sentSize, r.totalSize, r.fileTransferMeta.fileId, archivePath, ctrl, user)
|
||||
}
|
||||
}
|
||||
is CR.SndFileRedirectStartXFTP -> {
|
||||
@@ -578,7 +579,7 @@ private fun MutableState<MigrationFromState>.startUploading(
|
||||
requiredHostMode = cfg.requiredHostMode
|
||||
)
|
||||
)
|
||||
state = MigrationFromState.LinkShown(msg.fileTransferMeta.fileId, data.addToLink(msg.rcvURIs[0]), ctrl)
|
||||
state = MigrationFromState.LinkShown(r.fileTransferMeta.fileId, data.addToLink(r.rcvURIs[0]), ctrl)
|
||||
}
|
||||
is CR.SndFileError -> {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
@@ -692,7 +693,7 @@ private class MigrationFromChatReceiver(
|
||||
val ctrl: ChatCtrl,
|
||||
val databaseUrl: File,
|
||||
var receiveMessages: Boolean = true,
|
||||
val processReceivedMsg: suspend (CR) -> Unit
|
||||
val processReceivedMsg: suspend (API) -> Unit
|
||||
) {
|
||||
fun start() {
|
||||
Log.d(TAG, "MigrationChatReceiver startReceiver")
|
||||
@@ -701,19 +702,18 @@ private class MigrationFromChatReceiver(
|
||||
try {
|
||||
val msg = ChatController.recvMsg(ctrl)
|
||||
if (msg != null && receiveMessages) {
|
||||
val r = msg.resp
|
||||
val rhId = msg.remoteHostId
|
||||
Log.d(TAG, "processReceivedMsg: ${r.responseType}")
|
||||
chatModel.addTerminalItem(TerminalItem.resp(rhId, r))
|
||||
val rhId = msg.rhId
|
||||
Log.d(TAG, "processReceivedMsg: ${msg.responseType}")
|
||||
chatModel.addTerminalItem(TerminalItem.resp(rhId, msg))
|
||||
val finishedWithoutTimeout = withTimeoutOrNull(60_000L) {
|
||||
processReceivedMsg(r)
|
||||
processReceivedMsg(msg)
|
||||
}
|
||||
if (finishedWithoutTimeout == null) {
|
||||
Log.e(TAG, "Timeout reached while processing received message: " + msg.resp.responseType)
|
||||
Log.e(TAG, "Timeout reached while processing received message: " + msg.responseType)
|
||||
if (appPreferences.developerTools.get() && appPreferences.showSlowApiCalls.get()) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.possible_slow_function_title),
|
||||
text = generalGetString(MR.strings.possible_slow_function_desc).format(60, msg.resp.responseType + "\n" + Exception().stackTraceToString()),
|
||||
text = generalGetString(MR.strings.possible_slow_function_desc).format(60, msg.responseType + "\n" + Exception().stackTraceToString()),
|
||||
shareText = true
|
||||
)
|
||||
}
|
||||
|
||||
+16
-16
@@ -580,12 +580,13 @@ private fun MutableState<MigrationToState?>.startDownloading(
|
||||
) {
|
||||
withBGApi {
|
||||
chatReceiver.value = MigrationToChatReceiver(ctrl, tempDatabaseFile) { msg ->
|
||||
when (msg) {
|
||||
is CR.RcvFileProgressXFTP -> {
|
||||
state = MigrationToState.DownloadProgress(msg.receivedSize, msg.totalSize, msg.rcvFileTransfer.fileId, link, archivePath, netCfg, networkProxy, ctrl)
|
||||
val r = msg.result
|
||||
when {
|
||||
r is CR.RcvFileProgressXFTP -> {
|
||||
state = MigrationToState.DownloadProgress(r.receivedSize, r.totalSize, r.rcvFileTransfer.fileId, link, archivePath, netCfg, networkProxy, ctrl)
|
||||
MigrationToDeviceState.save(MigrationToDeviceState.DownloadProgress(link, File(archivePath).name, netCfg, networkProxy))
|
||||
}
|
||||
is CR.RcvStandaloneFileComplete -> {
|
||||
r is CR.RcvStandaloneFileComplete -> {
|
||||
delay(500)
|
||||
// User closed the whole screen before new state was saved
|
||||
if (state == null) {
|
||||
@@ -595,22 +596,22 @@ private fun MutableState<MigrationToState?>.startDownloading(
|
||||
MigrationToDeviceState.save(MigrationToDeviceState.ArchiveImport(File(archivePath).name, netCfg, networkProxy))
|
||||
}
|
||||
}
|
||||
is CR.RcvFileError -> {
|
||||
r is CR.RcvFileError -> {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
generalGetString(MR.strings.migrate_to_device_download_failed),
|
||||
generalGetString(MR.strings.migrate_to_device_file_delete_or_link_invalid)
|
||||
)
|
||||
state = MigrationToState.DownloadFailed(totalBytes, link, archivePath, netCfg, networkProxy)
|
||||
}
|
||||
is CR.ChatRespError -> {
|
||||
if (msg.chatError is ChatError.ChatErrorChat && msg.chatError.errorType is ChatErrorType.NoRcvFileUser) {
|
||||
msg is API.Error -> {
|
||||
if (msg.err is ChatError.ChatErrorChat && msg.err.errorType is ChatErrorType.NoRcvFileUser) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
generalGetString(MR.strings.migrate_to_device_download_failed),
|
||||
generalGetString(MR.strings.migrate_to_device_file_delete_or_link_invalid)
|
||||
)
|
||||
state = MigrationToState.DownloadFailed(totalBytes, link, archivePath, netCfg, networkProxy)
|
||||
} else {
|
||||
Log.d(TAG, "unsupported error: ${msg.responseType}, ${json.encodeToString(msg.chatError)}")
|
||||
Log.d(TAG, "unsupported error: ${msg.responseType}, ${json.encodeToString(msg.err)}")
|
||||
}
|
||||
}
|
||||
else -> Log.d(TAG, "unsupported event: ${msg.responseType}")
|
||||
@@ -739,7 +740,7 @@ private class MigrationToChatReceiver(
|
||||
val ctrl: ChatCtrl,
|
||||
val databaseUrl: File,
|
||||
var receiveMessages: Boolean = true,
|
||||
val processReceivedMsg: suspend (CR) -> Unit
|
||||
val processReceivedMsg: suspend (API) -> Unit
|
||||
) {
|
||||
fun start() {
|
||||
Log.d(TAG, "MigrationChatReceiver startReceiver")
|
||||
@@ -748,19 +749,18 @@ private class MigrationToChatReceiver(
|
||||
try {
|
||||
val msg = ChatController.recvMsg(ctrl)
|
||||
if (msg != null && receiveMessages) {
|
||||
val r = msg.resp
|
||||
val rhId = msg.remoteHostId
|
||||
Log.d(TAG, "processReceivedMsg: ${r.responseType}")
|
||||
chatModel.addTerminalItem(TerminalItem.resp(rhId, r))
|
||||
val rhId = msg.rhId
|
||||
Log.d(TAG, "processReceivedMsg: ${msg.responseType}")
|
||||
chatModel.addTerminalItem(TerminalItem.resp(rhId, msg))
|
||||
val finishedWithoutTimeout = withTimeoutOrNull(60_000L) {
|
||||
processReceivedMsg(r)
|
||||
processReceivedMsg(msg)
|
||||
}
|
||||
if (finishedWithoutTimeout == null) {
|
||||
Log.e(TAG, "Timeout reached while processing received message: " + msg.resp.responseType)
|
||||
Log.e(TAG, "Timeout reached while processing received message: " + msg.responseType)
|
||||
if (appPreferences.developerTools.get() && appPreferences.showSlowApiCalls.get()) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.possible_slow_function_title),
|
||||
text = generalGetString(MR.strings.possible_slow_function_desc).format(60, msg.resp.responseType + "\n" + Exception().stackTraceToString()),
|
||||
text = generalGetString(MR.strings.possible_slow_function_desc).format(60, msg.responseType + "\n" + Exception().stackTraceToString()),
|
||||
shareText = true
|
||||
)
|
||||
}
|
||||
|
||||
+7
-7
@@ -492,7 +492,7 @@ private suspend fun connectDesktopAddress(sessionAddress: MutableState<String>,
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun connectDesktop(sessionAddress: MutableState<String>, connect: suspend () -> Pair<SomeRemoteCtrl?, CR.ChatCmdError?>): Boolean {
|
||||
private suspend fun connectDesktop(sessionAddress: MutableState<String>, connect: suspend () -> Pair<SomeRemoteCtrl?, ChatError?>): Boolean {
|
||||
val res = connect()
|
||||
if (res.first != null) {
|
||||
val (rc_, ctrlAppInfo, v) = res.first!!
|
||||
@@ -505,13 +505,13 @@ private suspend fun connectDesktop(sessionAddress: MutableState<String>, connect
|
||||
} else {
|
||||
val e = res.second ?: return false
|
||||
when {
|
||||
e.chatError is ChatError.ChatErrorRemoteCtrl && e.chatError.remoteCtrlError is RemoteCtrlError.BadInvitation -> showBadInvitationErrorAlert()
|
||||
e.chatError is ChatError.ChatErrorChat && e.chatError.errorType is ChatErrorType.CommandError -> showBadInvitationErrorAlert()
|
||||
e.chatError is ChatError.ChatErrorRemoteCtrl && e.chatError.remoteCtrlError is RemoteCtrlError.BadVersion -> showBadVersionAlert(v = e.chatError.remoteCtrlError.appVersion)
|
||||
e.chatError is ChatError.ChatErrorAgent && e.chatError.agentError is AgentErrorType.RCP && e.chatError.agentError.rcpErr is RCErrorType.VERSION -> showBadVersionAlert(v = null)
|
||||
e.chatError is ChatError.ChatErrorAgent && e.chatError.agentError is AgentErrorType.RCP && e.chatError.agentError.rcpErr is RCErrorType.CTRL_AUTH -> showDesktopDisconnectedErrorAlert()
|
||||
e is ChatError.ChatErrorRemoteCtrl && e.remoteCtrlError is RemoteCtrlError.BadInvitation -> showBadInvitationErrorAlert()
|
||||
e is ChatError.ChatErrorChat && e.errorType is ChatErrorType.CommandError -> showBadInvitationErrorAlert()
|
||||
e is ChatError.ChatErrorRemoteCtrl && e.remoteCtrlError is RemoteCtrlError.BadVersion -> showBadVersionAlert(v = e.remoteCtrlError.appVersion)
|
||||
e is ChatError.ChatErrorAgent && e.agentError is AgentErrorType.RCP && e.agentError.rcpErr is RCErrorType.VERSION -> showBadVersionAlert(v = null)
|
||||
e is ChatError.ChatErrorAgent && e.agentError is AgentErrorType.RCP && e.agentError.rcpErr is RCErrorType.CTRL_AUTH -> showDesktopDisconnectedErrorAlert()
|
||||
else -> {
|
||||
val errMsg = "${e.responseType}: ${e.details}"
|
||||
val errMsg = "error: ${e.string}"
|
||||
Log.e(TAG, "bad response: $errMsg")
|
||||
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error), errMsg)
|
||||
}
|
||||
|
||||
+2
-2
@@ -291,7 +291,7 @@ private fun DeliveryReceiptsSection(
|
||||
SectionView(stringResource(MR.strings.settings_section_title_delivery_receipts)) {
|
||||
SettingsActionItemWithContent(painterResource(MR.images.ic_person), stringResource(MR.strings.receipts_section_contacts)) {
|
||||
DefaultSwitch(
|
||||
checked = currentUser.sendRcptsContacts ?: false,
|
||||
checked = currentUser.sendRcptsContacts,
|
||||
onCheckedChange = { enable ->
|
||||
setOrAskSendReceiptsContacts(enable)
|
||||
}
|
||||
@@ -299,7 +299,7 @@ private fun DeliveryReceiptsSection(
|
||||
}
|
||||
SettingsActionItemWithContent(painterResource(MR.images.ic_group), stringResource(MR.strings.receipts_section_groups)) {
|
||||
DefaultSwitch(
|
||||
checked = currentUser.sendRcptsSmallGroups ?: false,
|
||||
checked = currentUser.sendRcptsSmallGroups,
|
||||
onCheckedChange = { enable ->
|
||||
setOrAskSendReceiptsGroups(enable)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user