From 037655e30f32ad328599dd5b864ed4c51a86bd98 Mon Sep 17 00:00:00 2001
From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
Date: Thu, 30 May 2024 23:04:00 +0700
Subject: [PATCH 01/19] android, desktop: creating wallpapers dir in some
situations (#4254)
---
.../kotlin/chat/simplex/common/views/database/DatabaseView.kt | 2 ++
.../chat/simplex/common/views/migration/MigrateToDevice.kt | 1 +
2 files changed, 3 insertions(+)
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt
index 330003b743..8549f6abe2 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/database/DatabaseView.kt
@@ -537,6 +537,7 @@ suspend fun exportChatArchive(
if (!m.chatDbChanged.value) {
controller.apiSaveAppSettings(AppSettings.current.prepareForExport())
}
+ wallpapersDir.mkdirs()
m.controller.apiExportArchive(config)
if (storagePath == null) {
deleteOldArchive(m)
@@ -592,6 +593,7 @@ private fun importArchive(
withLongRunningApi {
try {
m.controller.apiDeleteStorage()
+ wallpapersDir.mkdirs()
try {
val config = ArchiveConfig(archivePath, parentTempDirectory = databaseExportDir.toString())
val archiveErrors = m.controller.apiImportArchive(config)
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt
index f3a992d451..1a94676f79 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/migration/MigrateToDevice.kt
@@ -594,6 +594,7 @@ private fun MutableState.importArchive(archivePath: String, n
chatInitControllerRemovingDatabases()
}
controller.apiDeleteStorage()
+ wallpapersDir.mkdirs()
try {
val config = ArchiveConfig(archivePath, parentTempDirectory = databaseExportDir.toString())
val archiveErrors = controller.apiImportArchive(config)
From 7b5b747b19c16ffe00192a273e18e4a061e49ea4 Mon Sep 17 00:00:00 2001
From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
Date: Thu, 30 May 2024 23:07:58 +0700
Subject: [PATCH 02/19] desktop: performant drawing of wallpaper (#4249)
* desktop: low quality drawing of wallpaper
* fast drawing
* clean up
* unused
---
.../simplex/common/views/chat/ChatView.kt | 3 +-
.../common/views/helpers/ChatWallpaper.kt | 120 +++++++++++-------
.../common/views/usersettings/Appearance.kt | 6 +-
.../kotlin/chat/simplex/common/DesktopApp.kt | 1 +
.../kotlin/chat/simplex/desktop/Main.kt | 3 +-
5 files changed, 84 insertions(+), 49 deletions(-)
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt
index 03d4e30a6c..71d82b5691 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatView.kt
@@ -12,6 +12,7 @@ import androidx.compose.runtime.saveable.mapSaver
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.*
import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.graphics.*
import androidx.compose.ui.platform.*
import dev.icerock.moko.resources.compose.painterResource
@@ -620,7 +621,7 @@ fun ChatLayout(
.fillMaxSize()
.background(MaterialTheme.colors.background)
.then(if (wallpaperImage != null)
- Modifier.drawBehind { chatViewBackground(wallpaperImage, wallpaperType, backgroundColor, tintColor) }
+ Modifier.drawWithCache { chatViewBackground(wallpaperImage, wallpaperType, backgroundColor, tintColor) }
else
Modifier)
.padding(contentPadding)
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt
index 89796baf4e..8921685cd6 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ChatWallpaper.kt
@@ -1,12 +1,13 @@
package chat.simplex.common.views.helpers
+import androidx.compose.ui.draw.CacheDrawScope
+import androidx.compose.ui.draw.DrawResult
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.*
-import androidx.compose.ui.graphics.drawscope.DrawScope
-import androidx.compose.ui.graphics.drawscope.clipRect
+import androidx.compose.ui.graphics.drawscope.*
import androidx.compose.ui.layout.ContentScale
-import androidx.compose.ui.unit.IntOffset
-import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.*
import chat.simplex.common.model.ChatController.appPrefs
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.*
@@ -352,9 +353,17 @@ sealed class WallpaperType {
}
}
-fun DrawScope.chatViewBackground(image: ImageBitmap, imageType: WallpaperType, background: Color, tint: Color) = clipRect {
- val quality = FilterQuality.High
- fun repeat(imageScale: Float) {
+private fun drawToBitmap(image: ImageBitmap, imageScale: Float, tint: Color, size: Size, density: Float, layoutDirection: LayoutDirection): ImageBitmap {
+ val quality = if (appPlatform.isAndroid) FilterQuality.High else FilterQuality.Low
+ val drawScope = CanvasDrawScope()
+ val bitmap = ImageBitmap(size.width.toInt(), size.height.toInt())
+ val canvas = Canvas(bitmap)
+ drawScope.draw(
+ density = Density(density),
+ layoutDirection = layoutDirection,
+ canvas = canvas,
+ size = size,
+ ) {
val scale = imageScale * density
for (h in 0..(size.height / image.height / scale).roundToInt()) {
for (w in 0..(size.width / image.width / scale).roundToInt()) {
@@ -368,50 +377,71 @@ fun DrawScope.chatViewBackground(image: ImageBitmap, imageType: WallpaperType, b
}
}
}
+ return bitmap
+}
- drawRect(background)
- when (imageType) {
- is WallpaperType.Preset -> repeat((imageType.scale ?: 1f) * imageType.predefinedImageScale)
- is WallpaperType.Image -> when (val scaleType = imageType.scaleType ?: WallpaperScaleType.FILL) {
- WallpaperScaleType.REPEAT -> repeat(imageType.scale ?: 1f)
- WallpaperScaleType.FILL, WallpaperScaleType.FIT -> {
- val scale = scaleType.contentScale.computeScaleFactor(Size(image.width.toFloat(), image.height.toFloat()), Size(size.width, size.height))
- val scaledWidth = (image.width * scale.scaleX).roundToInt()
- val scaledHeight = (image.height * scale.scaleY).roundToInt()
- // Large image will cause freeze
- if (image.width > 4320 || image.height > 4320) return@clipRect
+fun CacheDrawScope.chatViewBackground(image: ImageBitmap, imageType: WallpaperType, background: Color, tint: Color): DrawResult {
+ val imageScale = if (imageType is WallpaperType.Preset) {
+ (imageType.scale ?: 1f) * imageType.predefinedImageScale
+ } else if (imageType is WallpaperType.Image && imageType.scaleType == WallpaperScaleType.REPEAT) {
+ imageType.scale ?: 1f
+ } else {
+ 1f
+ }
+ val image = if (imageType is WallpaperType.Preset || (imageType is WallpaperType.Image && imageType.scaleType == WallpaperScaleType.REPEAT)) {
+ drawToBitmap(image, imageScale, tint, size, density, layoutDirection)
+ } else {
+ image
+ }
- drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
- if (scaleType == WallpaperScaleType.FIT) {
- if (scaledWidth < size.width) {
- // has black lines at left and right sides
- var x = (size.width - scaledWidth) / 2
- while (x > 0) {
- drawImage(image, dstOffset = IntOffset(x = (x - scaledWidth).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
- x -= scaledWidth
- }
- x = size.width - (size.width - scaledWidth) / 2
- while (x < size.width) {
- drawImage(image, dstOffset = IntOffset(x = x.roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
- x += scaledWidth
- }
- } else {
- // has black lines at top and bottom sides
- var y = (size.height - scaledHeight) / 2
- while (y > 0) {
- drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = (y - scaledHeight).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
- y -= scaledHeight
- }
- y = size.height - (size.height - scaledHeight) / 2
- while (y < size.height) {
- drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = y.roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
- y += scaledHeight
+ return onDrawBehind {
+ val quality = if (appPlatform.isAndroid) FilterQuality.High else FilterQuality.Low
+ drawRect(background)
+ when (imageType) {
+ is WallpaperType.Preset -> drawImage(image)
+ is WallpaperType.Image -> when (val scaleType = imageType.scaleType ?: WallpaperScaleType.FILL) {
+ WallpaperScaleType.REPEAT -> drawImage(image)
+ WallpaperScaleType.FILL, WallpaperScaleType.FIT -> {
+ clipRect {
+ val scale = scaleType.contentScale.computeScaleFactor(Size(image.width.toFloat(), image.height.toFloat()), Size(size.width, size.height))
+ val scaledWidth = (image.width * scale.scaleX).roundToInt()
+ val scaledHeight = (image.height * scale.scaleY).roundToInt()
+ // Large image will cause freeze
+ if (image.width > 4320 || image.height > 4320) return@clipRect
+
+ drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
+ if (scaleType == WallpaperScaleType.FIT) {
+ if (scaledWidth < size.width) {
+ // has black lines at left and right sides
+ var x = (size.width - scaledWidth) / 2
+ while (x > 0) {
+ drawImage(image, dstOffset = IntOffset(x = (x - scaledWidth).roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
+ x -= scaledWidth
+ }
+ x = size.width - (size.width - scaledWidth) / 2
+ while (x < size.width) {
+ drawImage(image, dstOffset = IntOffset(x = x.roundToInt(), y = ((size.height - scaledHeight) / 2).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
+ x += scaledWidth
+ }
+ } else {
+ // has black lines at top and bottom sides
+ var y = (size.height - scaledHeight) / 2
+ while (y > 0) {
+ drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = (y - scaledHeight).roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
+ y -= scaledHeight
+ }
+ y = size.height - (size.height - scaledHeight) / 2
+ while (y < size.height) {
+ drawImage(image, dstOffset = IntOffset(x = ((size.width - scaledWidth) / 2).roundToInt(), y = y.roundToInt()), dstSize = IntSize(scaledWidth, scaledHeight), filterQuality = quality)
+ y += scaledHeight
+ }
+ }
}
}
+ drawRect(tint)
}
- drawRect(tint)
}
+ is WallpaperType.Empty -> {}
}
- is WallpaperType.Empty -> {}
}
}
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt
index 8b5fbd523f..84fe333ba8 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/Appearance.kt
@@ -95,11 +95,13 @@ object AppearanceScope {
val backgroundColor = backgroundColor ?: wallpaperType?.defaultBackgroundColor(theme, MaterialTheme.colors.background)
val tintColor = tintColor ?: wallpaperType?.defaultTintColor(theme)
Column(Modifier
- .drawBehind {
+ .drawWithCache {
if (wallpaperImage != null && wallpaperType != null && backgroundColor != null && tintColor != null) {
chatViewBackground(wallpaperImage, wallpaperType, backgroundColor, tintColor)
} else {
- drawRect(themeBackgroundColor)
+ onDrawBehind {
+ drawRect(themeBackgroundColor)
+ }
}
}
.padding(DEFAULT_PADDING_HALF)
diff --git a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt
index 36149c8248..4128982f78 100644
--- a/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt
+++ b/apps/multiplatform/common/src/desktopMain/kotlin/chat/simplex/common/DesktopApp.kt
@@ -115,6 +115,7 @@ private fun ApplicationScope.AppWindow(closedByError: MutableState) {
false
}
}, title = "SimpleX") {
+// val hardwareAccelerationDisabled = remember { listOf(GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT, GraphicsApi.UNKNOWN).contains(window.renderApi) }
simplexWindowState.window = window
AppScreen()
if (simplexWindowState.openDialog.isAwaiting) {
diff --git a/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt b/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt
index 9925a6346b..f69cf817e5 100644
--- a/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt
+++ b/apps/multiplatform/desktop/src/jvmMain/kotlin/chat/simplex/desktop/Main.kt
@@ -3,7 +3,6 @@ package chat.simplex.desktop
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector1D
import androidx.compose.foundation.*
-import androidx.compose.foundation.interaction.*
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
@@ -17,6 +16,8 @@ import kotlinx.coroutines.*
import java.io.File
fun main() {
+ // Disable hardware acceleration
+ //System.setProperty("skiko.renderApi", "SOFTWARE")
initHaskell()
runMigrations()
initApp()
From 5ac521f6d8bbe0172e260e55feafa5e79d62fd94 Mon Sep 17 00:00:00 2001
From: Evgeny Poberezkin
Date: Fri, 31 May 2024 12:45:58 +0100
Subject: [PATCH 03/19] core: commands to debug subscribed SMP queues (#4253)
* core: commands to debug subscribed SMP queues
* getLastRcvMsgInfo
* DESC
* update
* update commands, ui compiles
* update
* ios: fix type
* swap
* simplexmq
* group member queue info
* copy button in the alert
---
apps/ios/Shared/Model/SimpleXAPI.swift | 12 +++++
apps/ios/Shared/Views/Chat/ChatInfoView.swift | 31 ++++++++++++
.../Chat/Group/GroupMemberInfoView.swift | 15 ++++++
apps/ios/SimpleX.xcodeproj/project.pbxproj | 40 +++++++--------
apps/ios/SimpleXChat/APITypes.swift | 50 +++++++++++++++++++
cabal.project | 2 +-
scripts/nix/sha256map.nix | 2 +-
src/Simplex/Chat.hs | 19 +++++++
src/Simplex/Chat/Controller.hs | 6 +++
src/Simplex/Chat/Messages.hs | 11 ++++
src/Simplex/Chat/Store/Messages.hs | 18 +++++++
src/Simplex/Chat/View.hs | 46 +++++++++--------
12 files changed, 210 insertions(+), 42 deletions(-)
diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift
index a6d574e38d..57f4f2eda8 100644
--- a/apps/ios/Shared/Model/SimpleXAPI.swift
+++ b/apps/ios/Shared/Model/SimpleXAPI.swift
@@ -561,6 +561,18 @@ func apiGroupMemberInfo(_ groupId: Int64, _ groupMemberId: Int64) throws -> (Gro
throw r
}
+func apiContactQueueInfo(_ contactId: Int64) async throws -> (RcvMsgInfo?, QueueInfo) {
+ let r = await chatSendCmd(.apiContactQueueInfo(contactId: contactId))
+ if case let .queueInfo(_, rcvMsgInfo, queueInfo) = r { return (rcvMsgInfo, queueInfo) }
+ throw r
+}
+
+func apiGroupMemberQueueInfo(_ groupId: Int64, _ groupMemberId: Int64) async throws -> (RcvMsgInfo?, QueueInfo) {
+ let r = await chatSendCmd(.apiGroupMemberQueueInfo(groupId: groupId, groupMemberId: groupMemberId))
+ if case let .queueInfo(_, rcvMsgInfo, queueInfo) = r { return (rcvMsgInfo, queueInfo) }
+ throw r
+}
+
func apiSwitchContact(contactId: Int64) throws -> ConnectionStats {
let r = chatSendCmdSync(.apiSwitchContact(contactId: contactId))
if case let .contactSwitchStarted(_, _, connectionStats) = r { return connectionStats }
diff --git a/apps/ios/Shared/Views/Chat/ChatInfoView.swift b/apps/ios/Shared/Views/Chat/ChatInfoView.swift
index 2e5a4f2af6..f5abfe9c58 100644
--- a/apps/ios/Shared/Views/Chat/ChatInfoView.swift
+++ b/apps/ios/Shared/Views/Chat/ChatInfoView.swift
@@ -110,6 +110,7 @@ struct ChatInfoView: View {
case switchAddressAlert
case abortSwitchAddressAlert
case syncConnectionForceAlert
+ case queueInfo(info: String)
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
var id: String {
@@ -119,6 +120,7 @@ struct ChatInfoView: View {
case .switchAddressAlert: return "switchAddressAlert"
case .abortSwitchAddressAlert: return "abortSwitchAddressAlert"
case .syncConnectionForceAlert: return "syncConnectionForceAlert"
+ case let .queueInfo(info): return "queueInfo \(info)"
case let .error(title, _): return "error \(title)"
}
}
@@ -224,6 +226,18 @@ struct ChatInfoView: View {
Section(header: Text("For console")) {
infoRow("Local name", chat.chatInfo.localDisplayName)
infoRow("Database ID", "\(chat.chatInfo.apiId)")
+ Button ("Debug delivery") {
+ Task {
+ do {
+ let info = queueInfoText(try await apiContactQueueInfo(chat.chatInfo.apiId))
+ await MainActor.run { alert = .queueInfo(info: info) }
+ } catch let e {
+ logger.error("apiContactQueueInfo error: \(responseError(e))")
+ let a = getErrorAlert(e, "Error")
+ await MainActor.run { alert = .error(title: a.title, error: a.message) }
+ }
+ }
+ }
}
}
}
@@ -243,6 +257,7 @@ struct ChatInfoView: View {
case .switchAddressAlert: return switchAddressAlert(switchContactAddress)
case .abortSwitchAddressAlert: return abortSwitchAddressAlert(abortSwitchContactAddress)
case .syncConnectionForceAlert: return syncConnectionForceAlert({ syncContactConnection(force: true) })
+ case let .queueInfo(info): return queueInfoAlert(info)
case let .error(title, error): return mkAlert(title: title, message: error)
}
}
@@ -577,6 +592,22 @@ func syncConnectionForceAlert(_ syncConnectionForce: @escaping () -> Void) -> Al
)
}
+func queueInfoText(_ info: (RcvMsgInfo?, QueueInfo)) -> String {
+ let (rcvMsgInfo, qInfo) = info
+ var msgInfo: String
+ if let rcvMsgInfo { msgInfo = encodeJSON(rcvMsgInfo) } else { msgInfo = "none" }
+ return String.localizedStringWithFormat(NSLocalizedString("server queue info: %@\n\nlast received msg: %@", comment: "queue info"), encodeJSON(qInfo), msgInfo)
+}
+
+func queueInfoAlert(_ info: String) -> Alert {
+ Alert(
+ title: Text("Message queue info"),
+ message: Text(info),
+ primaryButton: .default(Text("Ok")),
+ secondaryButton: .default(Text("Copy")) { UIPasteboard.general.string = info }
+ )
+}
+
struct ChatInfoView_Previews: PreviewProvider {
static var previews: some View {
ChatInfoView(
diff --git a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift
index a24608b7e7..a851e3fc1d 100644
--- a/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift
+++ b/apps/ios/Shared/Views/Chat/Group/GroupMemberInfoView.swift
@@ -35,6 +35,7 @@ struct GroupMemberInfoView: View {
case abortSwitchAddressAlert
case syncConnectionForceAlert
case planAndConnectAlert(alert: PlanAndConnectAlert)
+ case queueInfo(info: String)
case error(title: LocalizedStringKey, error: LocalizedStringKey)
var id: String {
@@ -49,6 +50,7 @@ struct GroupMemberInfoView: View {
case .abortSwitchAddressAlert: return "abortSwitchAddressAlert"
case .syncConnectionForceAlert: return "syncConnectionForceAlert"
case let .planAndConnectAlert(alert): return "planAndConnectAlert \(alert.id)"
+ case let .queueInfo(info): return "queueInfo \(info)"
case let .error(title, _): return "error \(title)"
}
}
@@ -178,6 +180,18 @@ struct GroupMemberInfoView: View {
Section("For console") {
infoRow("Local name", member.localDisplayName)
infoRow("Database ID", "\(member.groupMemberId)")
+ Button ("Debug delivery") {
+ Task {
+ do {
+ let info = queueInfoText(try await apiGroupMemberQueueInfo(groupInfo.apiId, member.groupMemberId))
+ await MainActor.run { alert = .queueInfo(info: info) }
+ } catch let e {
+ logger.error("apiContactQueueInfo error: \(responseError(e))")
+ let a = getErrorAlert(e, "Error")
+ await MainActor.run { alert = .error(title: a.title, error: a.message) }
+ }
+ }
+ }
}
}
}
@@ -223,6 +237,7 @@ struct GroupMemberInfoView: View {
case .abortSwitchAddressAlert: return abortSwitchAddressAlert(abortSwitchMemberAddress)
case .syncConnectionForceAlert: return syncConnectionForceAlert({ syncMemberConnection(force: true) })
case let .planAndConnectAlert(alert): return planAndConnectAlert(alert, dismiss: true)
+ case let .queueInfo(info): return queueInfoAlert(info)
case let .error(title, error): return Alert(title: Text(title), message: Text(error))
}
}
diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj
index 93e61f3b21..412ecc1258 100644
--- a/apps/ios/SimpleX.xcodeproj/project.pbxproj
+++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj
@@ -24,6 +24,11 @@
5C029EAA283942EA004A9677 /* CallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA9283942EA004A9677 /* CallController.swift */; };
5C05DF532840AA1D00C683F9 /* CallSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C05DF522840AA1D00C683F9 /* CallSettings.swift */; };
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; };
+ 5C0EA1272C08ADAF00AD2E5E /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1222C08ADAF00AD2E5E /* libgmp.a */; };
+ 5C0EA1282C08ADAF00AD2E5E /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1232C08ADAF00AD2E5E /* libffi.a */; };
+ 5C0EA1292C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1242C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a */; };
+ 5C0EA12A2C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1252C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a */; };
+ 5C0EA12B2C08ADAF00AD2E5E /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1262C08ADAF00AD2E5E /* libgmpxx.a */; };
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */; };
5C10D88A28F187F300E58BF0 /* FullScreenMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C10D88928F187F300E58BF0 /* FullScreenMediaView.swift */; };
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
@@ -139,11 +144,6 @@
5CEACCED27DEA495000BD591 /* MsgContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEACCEC27DEA495000BD591 /* MsgContentView.swift */; };
5CEBD7462A5C0A8F00665FE2 /* KeyboardPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */; };
5CEBD7482A5F115D00665FE2 /* SetDeliveryReceiptsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */; };
- 5CEE879E2C076B8400583B8A /* libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CEE87992C076B8300583B8A /* libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7.a */; };
- 5CEE879F2C076B8400583B8A /* libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CEE879A2C076B8300583B8A /* libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7-ghc9.6.3.a */; };
- 5CEE87A02C076B8400583B8A /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CEE879B2C076B8400583B8A /* libffi.a */; };
- 5CEE87A12C076B8400583B8A /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CEE879C2C076B8400583B8A /* libgmp.a */; };
- 5CEE87A22C076B8400583B8A /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CEE879D2C076B8400583B8A /* libgmpxx.a */; };
5CF937202B24DE8C00E1D781 /* SharedFileSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF9371F2B24DE8C00E1D781 /* SharedFileSubscriber.swift */; };
5CF937232B2503D000E1D781 /* NSESubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CF937212B25034A00E1D781 /* NSESubscriber.swift */; };
5CFA59C42860BC6200863A68 /* MigrateToAppGroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */; };
@@ -273,6 +273,11 @@
5C029EA9283942EA004A9677 /* CallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallController.swift; sourceTree = ""; };
5C05DF522840AA1D00C683F9 /* CallSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallSettings.swift; sourceTree = ""; };
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatPreviewView.swift; sourceTree = ""; };
+ 5C0EA1222C08ADAF00AD2E5E /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; };
+ 5C0EA1232C08ADAF00AD2E5E /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; };
+ 5C0EA1242C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a"; sourceTree = ""; };
+ 5C0EA1252C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a"; sourceTree = ""; };
+ 5C0EA1262C08ADAF00AD2E5E /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; };
5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionInfo.swift; sourceTree = ""; };
5C10D88928F187F300E58BF0 /* FullScreenMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenMediaView.swift; sourceTree = ""; };
5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestView.swift; sourceTree = ""; };
@@ -435,11 +440,6 @@
5CEACCEC27DEA495000BD591 /* MsgContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MsgContentView.swift; sourceTree = ""; };
5CEBD7452A5C0A8F00665FE2 /* KeyboardPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardPadding.swift; sourceTree = ""; };
5CEBD7472A5F115D00665FE2 /* SetDeliveryReceiptsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetDeliveryReceiptsView.swift; sourceTree = ""; };
- 5CEE87992C076B8300583B8A /* libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7.a"; sourceTree = ""; };
- 5CEE879A2C076B8300583B8A /* libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7-ghc9.6.3.a"; sourceTree = ""; };
- 5CEE879B2C076B8400583B8A /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; };
- 5CEE879C2C076B8400583B8A /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; };
- 5CEE879D2C076B8400583B8A /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; };
5CF9371F2B24DE8C00E1D781 /* SharedFileSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedFileSubscriber.swift; sourceTree = ""; };
5CF937212B25034A00E1D781 /* NSESubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSESubscriber.swift; sourceTree = ""; };
5CFA59C32860BC6200863A68 /* MigrateToAppGroupView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToAppGroupView.swift; sourceTree = ""; };
@@ -529,13 +529,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 5CEE879E2C076B8400583B8A /* libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
- 5CEE879F2C076B8400583B8A /* libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7-ghc9.6.3.a in Frameworks */,
- 5CEE87A02C076B8400583B8A /* libffi.a in Frameworks */,
- 5CEE87A12C076B8400583B8A /* libgmp.a in Frameworks */,
+ 5C0EA1272C08ADAF00AD2E5E /* libgmp.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
- 5CEE87A22C076B8400583B8A /* libgmpxx.a in Frameworks */,
+ 5C0EA12A2C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a in Frameworks */,
+ 5C0EA1292C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a in Frameworks */,
+ 5C0EA1282C08ADAF00AD2E5E /* libffi.a in Frameworks */,
+ 5C0EA12B2C08ADAF00AD2E5E /* libgmpxx.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -601,11 +601,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
- 5CEE879B2C076B8400583B8A /* libffi.a */,
- 5CEE879C2C076B8400583B8A /* libgmp.a */,
- 5CEE879D2C076B8400583B8A /* libgmpxx.a */,
- 5CEE879A2C076B8300583B8A /* libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7-ghc9.6.3.a */,
- 5CEE87992C076B8300583B8A /* libHSsimplex-chat-5.8.0.4-LLYprD9nQTR9mmjl4EdHW7.a */,
+ 5C0EA1232C08ADAF00AD2E5E /* libffi.a */,
+ 5C0EA1222C08ADAF00AD2E5E /* libgmp.a */,
+ 5C0EA1262C08ADAF00AD2E5E /* libgmpxx.a */,
+ 5C0EA1242C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a */,
+ 5C0EA1252C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a */,
);
path = Libraries;
sourceTree = "";
diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift
index 12683bc3a4..3ce436aabb 100644
--- a/apps/ios/SimpleXChat/APITypes.swift
+++ b/apps/ios/SimpleXChat/APITypes.swift
@@ -82,6 +82,8 @@ public enum ChatCommand {
case apiSetMemberSettings(groupId: Int64, groupMemberId: Int64, memberSettings: GroupMemberSettings)
case apiContactInfo(contactId: Int64)
case apiGroupMemberInfo(groupId: Int64, groupMemberId: Int64)
+ case apiContactQueueInfo(contactId: Int64)
+ case apiGroupMemberQueueInfo(groupId: Int64, groupMemberId: Int64)
case apiSwitchContact(contactId: Int64)
case apiSwitchGroupMember(groupId: Int64, groupMemberId: Int64)
case apiAbortSwitchContact(contactId: Int64)
@@ -228,6 +230,8 @@ public enum ChatCommand {
case let .apiSetMemberSettings(groupId, groupMemberId, memberSettings): return "/_member settings #\(groupId) \(groupMemberId) \(encodeJSON(memberSettings))"
case let .apiContactInfo(contactId): return "/_info @\(contactId)"
case let .apiGroupMemberInfo(groupId, groupMemberId): return "/_info #\(groupId) \(groupMemberId)"
+ case let .apiContactQueueInfo(contactId): return "/_queue info @\(contactId)"
+ case let .apiGroupMemberQueueInfo(groupId, groupMemberId): return "/_queue info #\(groupId) \(groupMemberId)"
case let .apiSwitchContact(contactId): return "/_switch @\(contactId)"
case let .apiSwitchGroupMember(groupId, groupMemberId): return "/_switch #\(groupId) \(groupMemberId)"
case let .apiAbortSwitchContact(contactId): return "/_abort switch @\(contactId)"
@@ -375,6 +379,8 @@ public enum ChatCommand {
case .apiSetMemberSettings: return "apiSetMemberSettings"
case .apiContactInfo: return "apiContactInfo"
case .apiGroupMemberInfo: return "apiGroupMemberInfo"
+ case .apiContactQueueInfo: return "apiContactQueueInfo"
+ case .apiGroupMemberQueueInfo: return "apiGroupMemberQueueInfo"
case .apiSwitchContact: return "apiSwitchContact"
case .apiSwitchGroupMember: return "apiSwitchGroupMember"
case .apiAbortSwitchContact: return "apiAbortSwitchContact"
@@ -516,6 +522,7 @@ public enum ChatResponse: Decodable, Error {
case networkConfig(networkConfig: NetCfg)
case contactInfo(user: UserRef, contact: Contact, connectionStats_: ConnectionStats?, customUserProfile: Profile?)
case groupMemberInfo(user: UserRef, groupInfo: GroupInfo, member: GroupMember, connectionStats_: ConnectionStats?)
+ case queueInfo(user: UserRef, rcvMsgInfo: RcvMsgInfo?, queueInfo: QueueInfo)
case contactSwitchStarted(user: UserRef, contact: Contact, connectionStats: ConnectionStats)
case groupMemberSwitchStarted(user: UserRef, groupInfo: GroupInfo, member: GroupMember, connectionStats: ConnectionStats)
case contactSwitchAborted(user: UserRef, contact: Contact, connectionStats: ConnectionStats)
@@ -678,6 +685,7 @@ public enum ChatResponse: Decodable, Error {
case .networkConfig: return "networkConfig"
case .contactInfo: return "contactInfo"
case .groupMemberInfo: return "groupMemberInfo"
+ case .queueInfo: return "queueInfo"
case .contactSwitchStarted: return "contactSwitchStarted"
case .groupMemberSwitchStarted: return "groupMemberSwitchStarted"
case .contactSwitchAborted: return "contactSwitchAborted"
@@ -836,6 +844,9 @@ public enum ChatResponse: Decodable, Error {
case let .networkConfig(networkConfig): return String(describing: networkConfig)
case let .contactInfo(u, contact, connectionStats_, customUserProfile): return withUser(u, "contact: \(String(describing: contact))\nconnectionStats_: \(String(describing: connectionStats_))\ncustomUserProfile: \(String(describing: customUserProfile))")
case let .groupMemberInfo(u, groupInfo, member, connectionStats_): return withUser(u, "groupInfo: \(String(describing: groupInfo))\nmember: \(String(describing: member))\nconnectionStats_: \(String(describing: connectionStats_))")
+ case let .queueInfo(u, rcvMsgInfo, queueInfo):
+ let msgInfo = if let info = rcvMsgInfo { encodeJSON(rcvMsgInfo) } else { "none" }
+ return withUser(u, "rcvMsgInfo: \(msgInfo)\nqueueInfo: \(encodeJSON(queueInfo))")
case let .contactSwitchStarted(u, contact, connectionStats): return withUser(u, "contact: \(String(describing: contact))\nconnectionStats: \(String(describing: connectionStats))")
case let .groupMemberSwitchStarted(u, groupInfo, member, connectionStats): return withUser(u, "groupInfo: \(String(describing: groupInfo))\nmember: \(String(describing: member))\nconnectionStats: \(String(describing: connectionStats))")
case let .contactSwitchAborted(u, contact, connectionStats): return withUser(u, "contact: \(String(describing: contact))\nconnectionStats: \(String(describing: connectionStats))")
@@ -2170,3 +2181,42 @@ public enum UserNetworkType: String, Codable {
}
}
}
+
+public struct RcvMsgInfo: Codable {
+ var msgId: Int64
+ var msgDeliveryId: Int64
+ var msgDeliveryStatus: String
+ var agentMsgId: Int64
+ var agentMsgMeta: String
+}
+
+public struct QueueInfo: Codable {
+ var qiSnd: Bool
+ var qiNtf: Bool
+ var qiSub: QSub?
+ var qiSize: Int
+ var qiMsg: MsgInfo?
+}
+
+public struct QSub: Codable {
+ var qSubThread: QSubThread
+ var qDelivered: String?
+}
+
+public enum QSubThread: String, Codable {
+ case noSub
+ case subPending
+ case subThread
+ case prohibitSub
+}
+
+public struct MsgInfo: Codable {
+ var msgId: String
+ var msgTs: Date
+ var msgType: MsgType
+}
+
+public enum MsgType: String, Codable {
+ case message
+ case quota
+}
diff --git a/cabal.project b/cabal.project
index 575fcd100c..cbbe549649 100644
--- a/cabal.project
+++ b/cabal.project
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
- tag: 97a953550f90b14dbf0f9a62077e88df306ebeca
+ tag: 88f1b727e0e4bfef01a346d818b7f6d94a181b16
source-repository-package
type: git
diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix
index 138aafe57a..f09bf7af57 100644
--- a/scripts/nix/sha256map.nix
+++ b/scripts/nix/sha256map.nix
@@ -1,5 +1,5 @@
{
- "https://github.com/simplex-chat/simplexmq.git"."97a953550f90b14dbf0f9a62077e88df306ebeca" = "15cdvaggk7jghyc0jsxgb17rl327a8z42h0pfga6yrcamcb07mln";
+ "https://github.com/simplex-chat/simplexmq.git"."88f1b727e0e4bfef01a346d818b7f6d94a181b16" = "0i785dm8sm1c5lydq2kci1a3ix91q3hn89l7x80gnxyqgn4qq2gd";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs
index 02a741ef41..54e9f31b4f 100644
--- a/src/Simplex/Chat.hs
+++ b/src/Simplex/Chat.hs
@@ -1379,6 +1379,11 @@ processChatCommand' vr = \case
forM customUserProfileId $ \profileId -> withStore (\db -> getProfileById db userId profileId)
connectionStats <- mapM (withAgent . flip getConnectionServers) (contactConnId ct)
pure $ CRContactInfo user ct connectionStats (fmap fromLocalProfile incognitoProfile)
+ APIContactQueueInfo contactId -> withUser $ \user -> do
+ ct@Contact {activeConn} <- withStore $ \db -> getContact db vr user contactId
+ case activeConn of
+ Just conn -> getConnQueueInfo user conn
+ Nothing -> throwChatError $ CEContactNotActive ct
APIGroupInfo gId -> withUser $ \user -> do
(g, s) <- withStore $ \db -> (,) <$> getGroupInfo db vr user gId <*> liftIO (getGroupSummary db user gId)
pure $ CRGroupInfo user g s
@@ -1386,6 +1391,11 @@ processChatCommand' vr = \case
(g, m) <- withStore $ \db -> (,) <$> getGroupInfo db vr user gId <*> getGroupMember db vr user gId gMemberId
connectionStats <- mapM (withAgent . flip getConnectionServers) (memberConnId m)
pure $ CRGroupMemberInfo user g m connectionStats
+ APIGroupMemberQueueInfo gId gMemberId -> withUser $ \user -> do
+ GroupMember {activeConn} <- withStore $ \db -> getGroupMember db vr user gId gMemberId
+ case activeConn of
+ Just conn -> getConnQueueInfo user conn
+ Nothing -> throwChatError CEGroupMemberNotActive
APISwitchContact contactId -> withUser $ \user -> do
ct <- withStore $ \db -> getContact db vr user contactId
case contactConnId ct of
@@ -1497,6 +1507,8 @@ processChatCommand' vr = \case
groupId <- withStore $ \db -> getGroupIdByName db user gName
processChatCommand $ APIGroupInfo groupId
GroupMemberInfo gName mName -> withMemberName gName mName APIGroupMemberInfo
+ ContactQueueInfo cName -> withContactName cName APIContactQueueInfo
+ GroupMemberQueueInfo gName mName -> withMemberName gName mName APIGroupMemberQueueInfo
SwitchContact cName -> withContactName cName APISwitchContact
SwitchGroupMember gName mName -> withMemberName gName mName APISwitchGroupMember
AbortSwitchContact cName -> withContactName cName APIAbortSwitchContact
@@ -2795,6 +2807,9 @@ processChatCommand' vr = \case
pure CIFile {fileId, fileName = takeFileName filePath, fileSize, fileSource = Just cf, fileStatus = CIFSSndStored, fileProtocol = FPLocal}
let ci = mkChatItem cd ciId content ciFile_ Nothing Nothing itemForwarded Nothing False createdAt Nothing createdAt
pure . CRNewChatItem user $ AChatItem SCTLocal SMDSnd (LocalChat nf) ci
+ getConnQueueInfo user Connection {connId, agentConnId = AgentConnId acId} = do
+ msgInfo <- withStore' (`getLastRcvMsgInfo` connId)
+ CRQueueInfo user msgInfo <$> withAgent (`getConnectionQueueInfo` acId)
contactCITimed :: Contact -> CM (Maybe CITimed)
contactCITimed ct = sndContactCITimed False ct Nothing
@@ -7361,6 +7376,10 @@ chatCommandP =
("/info #" <|> "/i #") *> (GroupMemberInfo <$> displayName <* A.space <* char_ '@' <*> displayName),
("/info #" <|> "/i #") *> (ShowGroupInfo <$> displayName),
("/info " <|> "/i ") *> char_ '@' *> (ContactInfo <$> displayName),
+ "/_queue info #" *> (APIGroupMemberQueueInfo <$> A.decimal <* A.space <*> A.decimal),
+ "/_queue info @" *> (APIContactQueueInfo <$> A.decimal),
+ ("/queue info #" <|> "/qi #") *> (GroupMemberQueueInfo <$> displayName <* A.space <* char_ '@' <*> displayName),
+ ("/queue info " <|> "/qi ") *> char_ '@' *> (ContactQueueInfo <$> displayName),
"/_switch #" *> (APISwitchGroupMember <$> A.decimal <* A.space <*> A.decimal),
"/_switch @" *> (APISwitchContact <$> A.decimal),
"/_abort switch #" *> (APIAbortSwitchGroupMember <$> A.decimal <* A.space <*> A.decimal),
diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs
index 8f8d460c60..9053f673f0 100644
--- a/src/Simplex/Chat/Controller.hs
+++ b/src/Simplex/Chat/Controller.hs
@@ -83,6 +83,7 @@ import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Notifications.Protocol (DeviceToken (..), NtfTknStatus)
import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, enumJSON, parseAll, parseString, sumTypeJSON)
import Simplex.Messaging.Protocol (AProtoServerWithAuth, AProtocolType (..), CorrId, NtfServer, ProtoServerWithAuth, ProtocolTypeI, QueueId, SMPMsgMeta (..), SProtocolType, SubscriptionMode (..), UserProtocol, XFTPServer, XFTPServerWithAuth, userProtocol)
+import Simplex.Messaging.Server.QueueStore.QueueInfo
import Simplex.Messaging.TMap (TMap)
import Simplex.Messaging.Transport (TLS, simplexMQVersion)
import Simplex.Messaging.Transport.Client (TransportHost)
@@ -357,6 +358,8 @@ data ChatCommand
| APIContactInfo ContactId
| APIGroupInfo GroupId
| APIGroupMemberInfo GroupId GroupMemberId
+ | APIContactQueueInfo ContactId
+ | APIGroupMemberQueueInfo GroupId GroupMemberId
| APISwitchContact ContactId
| APISwitchGroupMember GroupId GroupMemberId
| APIAbortSwitchContact ContactId
@@ -375,6 +378,8 @@ data ChatCommand
| ContactInfo ContactName
| ShowGroupInfo GroupName
| GroupMemberInfo GroupName ContactName
+ | ContactQueueInfo ContactName
+ | GroupMemberQueueInfo GroupName ContactName
| SwitchContact ContactName
| SwitchGroupMember GroupName ContactName
| AbortSwitchContact ContactName
@@ -569,6 +574,7 @@ data ChatResponse
| CRContactInfo {user :: User, contact :: Contact, connectionStats_ :: Maybe ConnectionStats, customUserProfile :: Maybe Profile}
| CRGroupInfo {user :: User, groupInfo :: GroupInfo, groupSummary :: GroupSummary}
| CRGroupMemberInfo {user :: User, groupInfo :: GroupInfo, member :: GroupMember, connectionStats_ :: Maybe ConnectionStats}
+ | CRQueueInfo {user :: User, rcvMsgInfo :: Maybe RcvMsgInfo, queueInfo :: QueueInfo}
| CRContactSwitchStarted {user :: User, contact :: Contact, connectionStats :: ConnectionStats}
| CRGroupMemberSwitchStarted {user :: User, groupInfo :: GroupInfo, member :: GroupMember, connectionStats :: ConnectionStats}
| CRContactSwitchAborted {user :: User, contact :: Contact, connectionStats :: ConnectionStats}
diff --git a/src/Simplex/Chat/Messages.hs b/src/Simplex/Chat/Messages.hs
index 6c0e93e017..ea79161e06 100644
--- a/src/Simplex/Chat/Messages.hs
+++ b/src/Simplex/Chat/Messages.hs
@@ -962,6 +962,15 @@ data RcvMsgDelivery = RcvMsgDelivery
}
deriving (Show)
+data RcvMsgInfo = RcvMsgInfo
+ { msgId :: Int64,
+ msgDeliveryId :: Int64,
+ msgDeliveryStatus :: Text,
+ agentMsgId :: AgentMsgId,
+ agentMsgMeta :: Text
+ }
+ deriving (Show)
+
data MsgMetaJSON = MsgMetaJSON
{ integrity :: Text,
rcvId :: Int64,
@@ -1332,3 +1341,5 @@ $(JQ.deriveJSON defaultJSON ''MsgMetaJSON)
msgMetaJson :: MsgMeta -> Text
msgMetaJson = decodeLatin1 . LB.toStrict . J.encode . msgMetaToJson
+
+$(JQ.deriveJSON defaultJSON ''RcvMsgInfo)
diff --git a/src/Simplex/Chat/Store/Messages.hs b/src/Simplex/Chat/Store/Messages.hs
index 84b2536380..853d34995a 100644
--- a/src/Simplex/Chat/Store/Messages.hs
+++ b/src/Simplex/Chat/Store/Messages.hs
@@ -23,6 +23,7 @@ module Simplex.Chat.Store.Messages
createNewSndMessage,
createSndMsgDelivery,
createNewMessageAndRcvMsgDelivery,
+ getLastRcvMsgInfo,
createNewRcvMessage,
updateSndMsgDeliveryStatus,
createPendingGroupMessage,
@@ -226,6 +227,23 @@ createNewMessageAndRcvMsgDelivery db connOrGroupId newMessage sharedMsgId_ RcvMs
(msgId, connId, agentMsgId, msgMetaJson agentMsgMeta, snd $ broker agentMsgMeta, currentTs, currentTs, MDSRcvAgent)
pure msg
+getLastRcvMsgInfo :: DB.Connection -> Int64 -> IO (Maybe RcvMsgInfo)
+getLastRcvMsgInfo db connId =
+ maybeFirstRow rcvMsgInfo $
+ DB.query
+ db
+ [sql|
+ SELECT message_id, msg_delivery_id, delivery_status, agent_msg_id, agent_msg_meta
+ FROM msg_deliveries
+ WHERE connection_id = ? AND delivery_status IN (?, ?)
+ ORDER BY created_at DESC, msg_delivery_id DESC
+ LIMIT 1
+ |]
+ (connId, MDSRcvAgent, MDSRcvAcknowledged)
+ where
+ rcvMsgInfo (msgId, msgDeliveryId, msgDeliveryStatus, agentMsgId, agentMsgMeta) =
+ RcvMsgInfo {msgId, msgDeliveryId, msgDeliveryStatus, agentMsgId, agentMsgMeta}
+
createNewRcvMessage :: forall e. MsgEncodingI e => DB.Connection -> ConnOrGroupId -> NewRcvMessage e -> Maybe SharedMsgId -> Maybe GroupMemberId -> Maybe GroupMemberId -> ExceptT StoreError IO RcvMessage
createNewRcvMessage db connOrGroupId NewRcvMessage {chatMsgEvent, msgBody} sharedMsgId_ authorMember forwardedByMember =
case connOrGroupId of
diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs
index b912040ac5..a315e755e1 100644
--- a/src/Simplex/Chat/View.hs
+++ b/src/Simplex/Chat/View.hs
@@ -13,7 +13,6 @@ module Simplex.Chat.View where
import qualified Data.Aeson as J
import qualified Data.Aeson.TH as JQ
-import Data.ByteString.Char8 (ByteString)
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy.Char8 as LB
import Data.Char (isSpace, toUpper)
@@ -65,7 +64,7 @@ import Simplex.Messaging.Parsers (dropPrefix, taggedObjectJSON)
import Simplex.Messaging.Protocol (AProtoServerWithAuth (..), AProtocolType, ProtoServerWithAuth, ProtocolServer (..), ProtocolTypeI, SProtocolType (..))
import qualified Simplex.Messaging.Protocol as SMP
import Simplex.Messaging.Transport.Client (TransportHost (..))
-import Simplex.Messaging.Util (bshow, tshow)
+import Simplex.Messaging.Util (tshow)
import Simplex.Messaging.Version hiding (version)
import Simplex.RemoteControl.Types (RCCtrlAddress (..))
import System.Console.ANSI.Types
@@ -90,10 +89,10 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
CRChatRunning -> ["chat is running"]
CRChatStopped -> ["chat stopped"]
CRChatSuspended -> ["chat suspended"]
- CRApiChats u chats -> ttyUser u $ if testView then testViewChats chats else [plain . bshow $ J.encode chats]
+ CRApiChats u chats -> ttyUser u $ if testView then testViewChats chats else [viewJSON chats]
CRChats chats -> viewChats ts tz chats
- CRApiChat u chat -> ttyUser u $ if testView then testViewChat chat else [plain . bshow $ J.encode chat]
- CRApiParsedMarkdown ft -> [plain . bshow $ J.encode ft]
+ CRApiChat u chat -> ttyUser u $ if testView then testViewChat chat else [viewJSON chat]
+ CRApiParsedMarkdown ft -> [viewJSON ft]
CRUserProtoServers u userServers -> ttyUser u $ viewUserServers userServers testView
CRServerTestResult u srv testFailure -> ttyUser u $ viewServerTestResult srv testFailure
CRChatItemTTL u ttl -> ttyUser u $ viewChatItemTTL ttl
@@ -101,6 +100,10 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
CRContactInfo u ct cStats customUserProfile -> ttyUser u $ viewContactInfo ct cStats customUserProfile
CRGroupInfo u g s -> ttyUser u $ viewGroupInfo g s
CRGroupMemberInfo u g m cStats -> ttyUser u $ viewGroupMemberInfo g m cStats
+ CRQueueInfo _ msgInfo qInfo ->
+ [ "last received msg: " <> maybe "none" viewJSON msgInfo,
+ "server queue info: " <> viewJSON qInfo
+ ]
CRContactSwitchStarted {} -> ["switch started"]
CRGroupMemberSwitchStarted {} -> ["switch started"]
CRContactSwitchAborted {} -> ["switch aborted"]
@@ -220,7 +223,7 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
CRSndFileError u (Just ci) _ e -> ttyUser u $ uploadingFile "error" ci <> [plain e]
CRSndFileRcvCancelled u _ ft@SndFileTransfer {recipientDisplayName = c} ->
ttyUser u [ttyContact c <> " cancelled receiving " <> sndFile ft]
- CRStandaloneFileInfo info_ -> maybe ["no file information in URI"] (\j -> [plain . LB.toStrict $ J.encode j]) info_
+ CRStandaloneFileInfo info_ -> maybe ["no file information in URI"] (\j -> [viewJSON j]) info_
CRContactConnecting u _ -> ttyUser u []
CRContactConnected u ct userCustomProfile -> ttyUser u $ viewContactConnected ct userCustomProfile testView
CRContactAnotherClient u c -> ttyUser u [ttyContact' c <> ": contact is connected to another client"]
@@ -322,7 +325,7 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
]
CRRemoteFileStored rhId (CryptoFile filePath cfArgs_) ->
[plain $ "file " <> filePath <> " stored on remote host " <> show rhId]
- <> maybe [] ((: []) . plain . cryptoFileArgsStr testView) cfArgs_
+ <> maybe [] ((: []) . cryptoFileArgsStr testView) cfArgs_
CRRemoteCtrlList cs -> viewRemoteCtrls cs
CRRemoteCtrlFound {remoteCtrl = RemoteCtrlInfo {remoteCtrlId, ctrlDeviceName}, ctrlAppInfo_, appVersion, compatible} ->
[ ("remote controller " <> sShow remoteCtrlId <> " found: ")
@@ -354,8 +357,8 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
in ("Chat queries" : map viewQuery chatQueries) <> [""] <> ("Agent queries" : map viewQuery agentQueries)
CRDebugLocks {chatLockName, chatEntityLocks, agentLocks} ->
[ maybe "no chat lock" (("chat lock: " <>) . plain) chatLockName,
- plain $ "chat entity locks: " <> LB.unpack (J.encode chatEntityLocks),
- plain $ "agent locks: " <> LB.unpack (J.encode agentLocks)
+ "chat entity locks: " <> viewJSON chatEntityLocks,
+ "agent locks: " <> viewJSON agentLocks
]
CRAgentStats stats -> map (plain . intercalate ",") stats
CRAgentSubs {activeSubs, pendingSubs, removedSubs} ->
@@ -370,12 +373,12 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
("active subscriptions:" : map sShow activeSubscriptions)
<> ("pending subscriptions: " : map sShow pendingSubscriptions)
<> ("removed subscriptions: " : map sShow removedSubscriptions)
- CRAgentWorkersSummary {agentWorkersSummary} -> ["agent workers summary: " <> plain (LB.unpack $ J.encode agentWorkersSummary)]
+ CRAgentWorkersSummary {agentWorkersSummary} -> ["agent workers summary: " <> viewJSON agentWorkersSummary]
CRAgentWorkersDetails {agentWorkersDetails} ->
[ "agent workers details:",
- plain . LB.unpack $ J.encode agentWorkersDetails -- this would be huge, but copypastable when has its own line
+ viewJSON agentWorkersDetails -- this would be huge, but copypastable when has its own line
]
- CRAgentMsgCounts {msgCounts} -> ["received messages (total, duplicates):", plain . LB.unpack $ J.encode msgCounts]
+ CRAgentMsgCounts {msgCounts} -> ["received messages (total, duplicates):", viewJSON msgCounts]
CRAgentQueuesInfo {agentQueuesInfo} ->
[ "agent queues info:",
plain . LB.unpack $ J.encode agentQueuesInfo
@@ -397,7 +400,7 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
CRChatError u e -> ttyUser' u $ viewChatError False logLevel testView e
CRChatErrors u errs -> ttyUser' u $ concatMap (viewChatError False logLevel testView) errs
CRArchiveImported archiveErrs -> if null archiveErrs then ["ok"] else ["archive import errors: " <> plain (show archiveErrs)]
- CRAppSettings as -> ["app settings: " <> plain (LB.unpack $ J.encode as)]
+ CRAppSettings as -> ["app settings: " <> viewJSON as]
CRTimedAction _ _ -> []
CRCustomChatResponse u r -> ttyUser' u $ [plain r]
where
@@ -1241,10 +1244,10 @@ viewGroupInfo GroupInfo {groupId, uiThemes, customData} s =
<> viewCustomData customData
viewUITheme :: Maybe UIThemeEntityOverrides -> [StyledString]
-viewUITheme = maybe [] (\uiThemes -> ["UI themes: " <> plain (LB.toStrict $ J.encode uiThemes)])
+viewUITheme = maybe [] (\uiThemes -> ["UI themes: " <> viewJSON uiThemes])
viewCustomData :: Maybe CustomData -> [StyledString]
-viewCustomData = maybe [] (\(CustomData v) -> ["custom data: " <> plain (LB.toStrict . J.encode $ J.Object v)])
+viewCustomData = maybe [] (\(CustomData v) -> ["custom data: " <> viewJSON (J.Object v)])
viewGroupMemberInfo :: GroupInfo -> GroupMember -> Maybe ConnectionStats -> [StyledString]
viewGroupMemberInfo GroupInfo {groupId} m@GroupMember {groupMemberId, memberProfile = LocalProfile {localAlias, contactLink}, activeConn} stats =
@@ -1686,7 +1689,7 @@ receivingFile_' :: (Maybe RemoteHostId, Maybe User) -> Bool -> String -> AChatIt
receivingFile_' hu testView status (AChatItem _ _ chat ChatItem {file = Just CIFile {fileId, fileName, fileSource = Just f@(CryptoFile _ cfArgs_)}, chatDir}) =
[plain status <> " receiving " <> fileTransferStr fileId fileName <> fileFrom chat chatDir] <> cfArgsStr cfArgs_ <> getRemoteFileStr
where
- cfArgsStr (Just cfArgs) = [plain (cryptoFileArgsStr testView cfArgs) | status == "completed"]
+ cfArgsStr (Just cfArgs) = [cryptoFileArgsStr testView cfArgs | status == "completed"]
cfArgsStr _ = []
getRemoteFileStr = case hu of
(Just rhId, Just User {userId})
@@ -1707,10 +1710,10 @@ viewLocalFile to CIFile {fileId, fileSource} ts tz = case fileSource of
Just (CryptoFile fPath _) -> sentWithTime_ ts tz [to <> fileTransferStr fileId fPath]
_ -> const []
-cryptoFileArgsStr :: Bool -> CryptoFileArgs -> ByteString
+cryptoFileArgsStr :: Bool -> CryptoFileArgs -> StyledString
cryptoFileArgsStr testView cfArgs@(CFArgs key nonce)
- | testView = LB.toStrict $ J.encode cfArgs
- | otherwise = "encryption key: " <> strEncode key <> ", nonce: " <> strEncode nonce
+ | testView = viewJSON cfArgs
+ | otherwise = plain $ "encryption key: " <> strEncode key <> ", nonce: " <> strEncode nonce
fileFrom :: ChatInfo c -> CIDirection c d -> StyledString
fileFrom (DirectChat ct) CIDirectRcv = " from " <> ttyContact' ct
@@ -1828,7 +1831,7 @@ viewCallAnswer ct WebRTCSession {rtcSession = answer, rtcIceCandidates = iceCand
[ ttyContact' ct <> " continued the WebRTC call",
"To connect, please paste the data below in your browser window you opened earlier and click Connect button",
"",
- plain . LB.toStrict . J.encode $ WCCallAnswer {answer, iceCandidates}
+ viewJSON WCCallAnswer {answer, iceCandidates}
]
callMediaStr :: CallType -> StyledString
@@ -2086,6 +2089,9 @@ viewConnectionEntityInactive entity inactive
| inactive = ["[" <> connEntityLabel entity <> "] connection is marked as inactive"]
| otherwise = ["[" <> connEntityLabel entity <> "] inactive connection is marked as active"]
+viewJSON :: J.ToJSON a => a -> StyledString
+viewJSON = plain . LB.toStrict . J.encode
+
connEntityLabel :: ConnectionEntity -> StyledString
connEntityLabel = \case
RcvDirectMsgConnection _ (Just Contact {localDisplayName = c}) -> plain c
From d46bae6498e60b6ddc48a65b838c37b8afc53e1e Mon Sep 17 00:00:00 2001
From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Date: Fri, 31 May 2024 20:20:49 +0400
Subject: [PATCH 04/19] ios: allow to save sent file on tap (#4264)
---
apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift | 7 ++++++-
.../chat/simplex/common/views/chat/item/CIFileView.kt | 8 +-------
2 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift
index 0af0469e42..53d840306e 100644
--- a/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift
+++ b/apps/ios/Shared/Views/Chat/ChatItem/CIFileView.swift
@@ -54,7 +54,7 @@ struct CIFileView: View {
switch (file.fileStatus) {
case .sndStored: return file.fileProtocol == .local
case .sndTransfer: return false
- case .sndComplete: return false
+ case .sndComplete: return true
case .sndCancelled: return false
case .sndError: return false
case .rcvInvitation: return true
@@ -113,6 +113,11 @@ struct CIFileView: View {
if file.fileProtocol == .local, let fileSource = getLoadedFileSource(file) {
saveCryptoFile(fileSource)
}
+ case .sndComplete:
+ logger.debug("CIFileView fileAction - in .sndComplete")
+ if let fileSource = getLoadedFileSource(file) {
+ saveCryptoFile(fileSource)
+ }
default: break
}
}
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt
index a48bb2bb12..0ce9ba32fc 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIFileView.kt
@@ -154,13 +154,7 @@ fun CIFileView(
FileProtocol.SMP -> progressIndicator()
FileProtocol.LOCAL -> {}
}
- is CIFileStatus.SndComplete -> {
- if ((file.forwardingAllowed() || (chatModel.connectedToRemote() && CIFile.cachedRemoteFileRequests[file.fileSource] == true))) {
- fileIcon()
- } else {
- fileIcon(innerIcon = painterResource(MR.images.ic_check_filled))
- }
- }
+ is CIFileStatus.SndComplete -> fileIcon(innerIcon = painterResource(MR.images.ic_check_filled))
is CIFileStatus.SndCancelled -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
is CIFileStatus.SndError -> fileIcon(innerIcon = painterResource(MR.images.ic_close))
is CIFileStatus.RcvInvitation ->
From 184a24b70e236c7f3ef135494b97c9fd9d91912d Mon Sep 17 00:00:00 2001
From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Date: Fri, 31 May 2024 21:30:59 +0400
Subject: [PATCH 05/19] ui: fix filtering of contacts that can be invited to
group (#4265)
---
apps/ios/Shared/Model/SimpleXAPI.swift | 2 +-
.../chat/simplex/common/views/chat/group/AddGroupMembersView.kt | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift
index 57f4f2eda8..af3cc5fd71 100644
--- a/apps/ios/Shared/Model/SimpleXAPI.swift
+++ b/apps/ios/Shared/Model/SimpleXAPI.swift
@@ -1277,7 +1277,7 @@ func filterMembersToAdd(_ ms: [GMember]) -> [Contact] {
let memberContactIds = ms.compactMap{ m in m.wrapped.memberCurrent ? m.wrapped.memberContactId : nil }
return ChatModel.shared.chats
.compactMap{ $0.chatInfo.contact }
- .filter{ c in c.ready && c.active && !memberContactIds.contains(c.apiId) }
+ .filter{ c in c.sendMsgEnabled && !c.nextSendGrpInv && !memberContactIds.contains(c.apiId) }
.sorted{ $0.displayName.lowercased() < $1.displayName.lowercased() }
}
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt
index d546b51a93..931cc17872 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/AddGroupMembersView.kt
@@ -86,7 +86,7 @@ fun getContactsToAdd(chatModel: ChatModel, search: String): List {
.map { it.chatInfo }
.filterIsInstance()
.map { it.contact }
- .filter { c -> c.ready && c.active && c.contactId !in memberContactIds && c.chatViewName.lowercase().contains(s) }
+ .filter { c -> c.sendMsgEnabled && !c.nextSendGrpInv && c.contactId !in memberContactIds && c.chatViewName.lowercase().contains(s) }
.sortedBy { it.displayName.lowercase() }
.toList()
}
From b1656031364e0f6a0a9d932ef2d20c2d2801453d Mon Sep 17 00:00:00 2001
From: Evgeny Poberezkin
Date: Fri, 31 May 2024 18:33:29 +0100
Subject: [PATCH 06/19] ios: log file error to console
---
apps/ios/Shared/Model/SimpleXAPI.swift | 2 +-
apps/ios/SimpleXChat/APITypes.swift | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift
index af3cc5fd71..764db8335e 100644
--- a/apps/ios/Shared/Model/SimpleXAPI.swift
+++ b/apps/ios/Shared/Model/SimpleXAPI.swift
@@ -1847,7 +1847,7 @@ func processReceivedMsg(_ res: ChatResponse) async {
}
case let .sndFileCompleteXFTP(user, aChatItem, _):
await chatItemSimpleUpdate(user, aChatItem)
- case let .sndFileError(user, aChatItem, _):
+ case let .sndFileError(user, aChatItem, _, _):
if let aChatItem = aChatItem {
await chatItemSimpleUpdate(user, aChatItem)
Task { cleanupFile(aChatItem) }
diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift
index 3ce436aabb..1574d43ac0 100644
--- a/apps/ios/SimpleXChat/APITypes.swift
+++ b/apps/ios/SimpleXChat/APITypes.swift
@@ -635,7 +635,7 @@ public enum ChatResponse: Decodable, Error {
case sndFileCompleteXFTP(user: UserRef, chatItem: AChatItem, fileTransferMeta: FileTransferMeta)
case sndStandaloneFileComplete(user: UserRef, fileTransferMeta: FileTransferMeta, rcvURIs: [String])
case sndFileCancelledXFTP(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta)
- case sndFileError(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta)
+ case sndFileError(user: UserRef, chatItem_: AChatItem?, fileTransferMeta: FileTransferMeta, errorMessage: String)
// call events
case callInvitation(callInvitation: RcvCallInvitation)
case callOffer(user: UserRef, contact: Contact, callType: CallType, offer: WebRTCSession, sharedKey: String?, askConfirmation: Bool)
@@ -956,7 +956,7 @@ public enum ChatResponse: Decodable, Error {
case let .sndFileCompleteXFTP(u, chatItem, _): return withUser(u, String(describing: chatItem))
case let .sndStandaloneFileComplete(u, _, rcvURIs): return withUser(u, String(rcvURIs.count))
case let .sndFileCancelledXFTP(u, chatItem, _): return withUser(u, String(describing: chatItem))
- case let .sndFileError(u, chatItem, _): return withUser(u, String(describing: chatItem))
+ case let .sndFileError(u, chatItem, _, err): return withUser(u, "error: \(String(describing: err))\nchatItem: \(String(describing: chatItem))")
case let .callInvitation(inv): return String(describing: inv)
case let .callOffer(u, contact, callType, offer, sharedKey, askConfirmation): return withUser(u, "contact: \(contact.id)\ncallType: \(String(describing: callType))\nsharedKey: \(sharedKey ?? "")\naskConfirmation: \(askConfirmation)\noffer: \(String(describing: offer))")
case let .callAnswer(u, contact, answer): return withUser(u, "contact: \(contact.id)\nanswer: \(String(describing: answer))")
From c251f5e2bd9f691032cd23f1b840f3558a9f60cf Mon Sep 17 00:00:00 2001
From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
Date: Sat, 1 Jun 2024 00:54:12 +0700
Subject: [PATCH 07/19] android, desktop: debug subscribed SMP queues (#4262)
Co-authored-by: Evgeny Poberezkin
---
.../chat/simplex/common/model/SimpleXAPI.kt | 72 +++++++++++++++++++
.../simplex/common/views/chat/ChatInfoView.kt | 20 ++++++
.../views/chat/group/GroupMemberInfoView.kt | 18 +++++
.../commonMain/resources/MR/base/strings.xml | 4 ++
4 files changed, 114 insertions(+)
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt
index b0557e2f67..1f7f55fb53 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt
@@ -931,6 +931,20 @@ object ChatController {
return null
}
+ suspend fun apiContactQueueInfo(rh: Long?, contactId: Long): Pair? {
+ val r = sendCmd(rh, CC.APIContactQueueInfo(contactId))
+ if (r is CR.QueueInfoR) return Pair(r.rcvMsgInfo, r.queueInfo)
+ apiErrorAlert("apiContactQueueInfo", generalGetString(MR.strings.error), r)
+ return null
+ }
+
+ suspend fun apiGroupMemberQueueInfo(rh: Long?, groupId: Long, groupMemberId: Long): Pair? {
+ val r = sendCmd(rh, CC.APIGroupMemberQueueInfo(groupId, groupMemberId))
+ if (r is CR.QueueInfoR) return Pair(r.rcvMsgInfo, r.queueInfo)
+ apiErrorAlert("apiGroupMemberQueueInfo", generalGetString(MR.strings.error), r)
+ return null
+ }
+
suspend fun apiSwitchContact(rh: Long?, contactId: Long): ConnectionStats? {
val r = sendCmd(rh, CC.APISwitchContact(contactId))
if (r is CR.ContactSwitchStarted) return r.connectionStats
@@ -2507,6 +2521,8 @@ sealed class CC {
class ApiSetMemberSettings(val groupId: Long, val groupMemberId: Long, val memberSettings: GroupMemberSettings): CC()
class APIContactInfo(val contactId: Long): CC()
class APIGroupMemberInfo(val groupId: Long, val groupMemberId: Long): CC()
+ class APIContactQueueInfo(val contactId: Long): CC()
+ class APIGroupMemberQueueInfo(val groupId: Long, val groupMemberId: Long): CC()
class APISwitchContact(val contactId: Long): CC()
class APISwitchGroupMember(val groupId: Long, val groupMemberId: Long): CC()
class APIAbortSwitchContact(val contactId: Long): CC()
@@ -2652,6 +2668,8 @@ sealed class CC {
is ApiSetMemberSettings -> "/_member settings #$groupId $groupMemberId ${json.encodeToString(memberSettings)}"
is APIContactInfo -> "/_info @$contactId"
is APIGroupMemberInfo -> "/_info #$groupId $groupMemberId"
+ is APIContactQueueInfo -> "/_queue info @$contactId"
+ is APIGroupMemberQueueInfo -> "/_queue info #$groupId $groupMemberId"
is APISwitchContact -> "/_switch @$contactId"
is APISwitchGroupMember -> "/_switch #$groupId $groupMemberId"
is APIAbortSwitchContact -> "/_abort switch @$contactId"
@@ -2790,6 +2808,8 @@ sealed class CC {
is ApiSetMemberSettings -> "apiSetMemberSettings"
is APIContactInfo -> "apiContactInfo"
is APIGroupMemberInfo -> "apiGroupMemberInfo"
+ is APIContactQueueInfo -> "apiContactQueueInfo"
+ is APIGroupMemberQueueInfo -> "apiGroupMemberQueueInfo"
is APISwitchContact -> "apiSwitchContact"
is APISwitchGroupMember -> "apiSwitchGroupMember"
is APIAbortSwitchContact -> "apiAbortSwitchContact"
@@ -4197,6 +4217,7 @@ sealed class CR {
@Serializable @SerialName("networkConfig") class NetworkConfig(val networkConfig: NetCfg): CR()
@Serializable @SerialName("contactInfo") class ContactInfo(val user: UserRef, val contact: Contact, val connectionStats_: ConnectionStats? = null, val customUserProfile: Profile? = null): CR()
@Serializable @SerialName("groupMemberInfo") class GroupMemberInfo(val user: UserRef, val groupInfo: GroupInfo, val member: GroupMember, val connectionStats_: ConnectionStats? = null): CR()
+ @Serializable @SerialName("queueInfo") class QueueInfoR(val user: UserRef, val rcvMsgInfo: RcvMsgInfo?, val queueInfo: QueueInfo): CR()
@Serializable @SerialName("contactSwitchStarted") class ContactSwitchStarted(val user: UserRef, val contact: Contact, val connectionStats: ConnectionStats): CR()
@Serializable @SerialName("groupMemberSwitchStarted") class GroupMemberSwitchStarted(val user: UserRef, val groupInfo: GroupInfo, val member: GroupMember, val connectionStats: ConnectionStats): CR()
@Serializable @SerialName("contactSwitchAborted") class ContactSwitchAborted(val user: UserRef, val contact: Contact, val connectionStats: ConnectionStats): CR()
@@ -4368,6 +4389,7 @@ sealed class CR {
is NetworkConfig -> "networkConfig"
is ContactInfo -> "contactInfo"
is GroupMemberInfo -> "groupMemberInfo"
+ is QueueInfoR -> "queueInfo"
is ContactSwitchStarted -> "contactSwitchStarted"
is GroupMemberSwitchStarted -> "groupMemberSwitchStarted"
is ContactSwitchAborted -> "contactSwitchAborted"
@@ -4529,6 +4551,7 @@ sealed class CR {
is NetworkConfig -> json.encodeToString(networkConfig)
is ContactInfo -> withUser(user, "contact: ${json.encodeToString(contact)}\nconnectionStats: ${json.encodeToString(connectionStats_)}")
is GroupMemberInfo -> withUser(user, "group: ${json.encodeToString(groupInfo)}\nmember: ${json.encodeToString(member)}\nconnectionStats: ${json.encodeToString(connectionStats_)}")
+ is QueueInfoR -> withUser(user, "rcvMsgInfo: ${json.encodeToString(rcvMsgInfo)}\nqueueInfo: ${json.encodeToString(queueInfo)}\n")
is ContactSwitchStarted -> withUser(user, "contact: ${json.encodeToString(contact)}\nconnectionStats: ${json.encodeToString(connectionStats)}")
is GroupMemberSwitchStarted -> withUser(user, "group: ${json.encodeToString(groupInfo)}\nmember: ${json.encodeToString(member)}\nconnectionStats: ${json.encodeToString(connectionStats)}")
is ContactSwitchAborted -> withUser(user, "contact: ${json.encodeToString(contact)}\nconnectionStats: ${json.encodeToString(connectionStats)}")
@@ -5786,3 +5809,52 @@ enum class UserNetworkType {
OTHER -> generalGetString(MR.strings.network_type_other)
}
}
+
+@Serializable
+data class RcvMsgInfo (
+ val msgId: Long,
+ val msgDeliveryId: Long,
+ val msgDeliveryStatus: String,
+ val agentMsgId: Long,
+ val agentMsgMeta: String
+)
+
+@Serializable
+data class QueueInfo (
+ val qiSnd: Boolean,
+ val qiNtf: Boolean,
+ val qiSub: QSub? = null,
+ val qiSize: Int,
+ val qiMsg: MsgInfo? = null
+)
+
+@Serializable
+data class QSub (
+ val qSubThread: QSubThread,
+ val qDelivered: String? = null
+)
+
+enum class QSubThread {
+ @SerialName("noSub")
+ NO_SUB,
+ @SerialName("subPending")
+ SUB_PENDING,
+ @SerialName("subThread")
+ SUB_THREAD,
+ @SerialName("prohibitSub")
+ PROHIBIT_SUB
+}
+
+@Serializable
+data class MsgInfo (
+ val msgId: String,
+ val msgTs: Instant,
+ val msgType: MsgType,
+)
+
+enum class MsgType {
+ @SerialName("message")
+ MESSAGE,
+ @SerialName("quota")
+ QUOTA
+}
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt
index 12b5747787..48ed0570a7 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ChatInfoView.kt
@@ -42,6 +42,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlinx.datetime.Clock
+import kotlinx.serialization.encodeToString
import java.io.File
@Composable
@@ -418,6 +419,19 @@ fun ChatInfoLayout(
SectionView(title = stringResource(MR.strings.section_title_for_console)) {
InfoRow(stringResource(MR.strings.info_row_local_name), chat.chatInfo.localDisplayName)
InfoRow(stringResource(MR.strings.info_row_database_id), chat.chatInfo.apiId.toString())
+ SectionItemView({
+ withBGApi {
+ val info = controller.apiContactQueueInfo(chat.remoteHostId, chat.chatInfo.apiId)
+ if (info != null) {
+ AlertManager.shared.showAlertMsg(
+ title = generalGetString(MR.strings.message_queue_info),
+ text = queueInfoText(info)
+ )
+ }
+ }
+ }) {
+ Text(stringResource(MR.strings.info_row_debug_delivery))
+ }
}
}
SectionBottomSpacer()
@@ -798,6 +812,12 @@ fun showSyncConnectionForceAlert(syncConnectionForce: () -> Unit) {
)
}
+fun queueInfoText(info: Pair): String {
+ val (rcvMsgInfo, qInfo) = info
+ val msgInfo: String = if (rcvMsgInfo != null) json.encodeToString(rcvMsgInfo) else generalGetString(MR.strings.message_queue_info_none)
+ return generalGetString(MR.strings.message_queue_info_server_info).format(json.encodeToString(qInfo), msgInfo)
+}
+
@Preview
@Composable
fun PreviewChatInfoLayout() {
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt
index e90efa7d1b..2799904b71 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/group/GroupMemberInfoView.kt
@@ -3,6 +3,7 @@ package chat.simplex.common.views.chat.group
import InfoRow
import SectionBottomSpacer
import SectionDividerSpaced
+import SectionItemView
import SectionSpacer
import SectionTextFooter
import SectionView
@@ -27,6 +28,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.*
+import chat.simplex.common.model.ChatModel.controller
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.chat.*
import chat.simplex.common.views.helpers.*
@@ -58,6 +60,7 @@ fun GroupMemberInfoView(
if (chat != null) {
val newRole = remember { mutableStateOf(member.memberRole) }
GroupMemberInfoLayout(
+ rhId = rhId,
groupInfo,
member,
connStats,
@@ -219,6 +222,7 @@ fun removeMemberDialog(rhId: Long?, groupInfo: GroupInfo, member: GroupMember, c
@Composable
fun GroupMemberInfoLayout(
+ rhId: Long?,
groupInfo: GroupInfo,
member: GroupMember,
connStats: MutableState,
@@ -397,6 +401,19 @@ fun GroupMemberInfoLayout(
SectionView(title = stringResource(MR.strings.section_title_for_console)) {
InfoRow(stringResource(MR.strings.info_row_local_name), member.localDisplayName)
InfoRow(stringResource(MR.strings.info_row_database_id), member.groupMemberId.toString())
+ SectionItemView({
+ withBGApi {
+ val info = controller.apiGroupMemberQueueInfo(rhId, groupInfo.apiId, member.groupMemberId)
+ if (info != null) {
+ AlertManager.shared.showAlertMsg(
+ title = generalGetString(MR.strings.message_queue_info),
+ text = queueInfoText(info)
+ )
+ }
+ }
+ }) {
+ Text(stringResource(MR.strings.info_row_debug_delivery))
+ }
}
}
SectionBottomSpacer()
@@ -644,6 +661,7 @@ fun blockMemberForAll(rhId: Long?, gInfo: GroupInfo, member: GroupMember, blocke
fun PreviewGroupMemberInfoLayout() {
SimpleXTheme {
GroupMemberInfoLayout(
+ rhId = null,
groupInfo = GroupInfo.sampleData,
member = GroupMember.sampleData,
connStats = remember { mutableStateOf(null) },
diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml
index d930a1b72b..df43d1459f 100644
--- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml
+++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml
@@ -1401,6 +1401,7 @@
FOR CONSOLE
Local name
Database ID
+ Debug delivery
Record updated at
Sent at
Created at
@@ -1462,6 +1463,9 @@
Connection
direct
indirect (%1$s)
+ Message queue info
+ none
+ server queue info: %1$s\n\nlast received msg: %2$s
Welcome message
From 3c98c6acc0d221c24441535e771d3089746d752e Mon Sep 17 00:00:00 2001
From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
Date: Sat, 1 Jun 2024 04:25:15 +0700
Subject: [PATCH 08/19] android, desktop: selectable cards for proxy options
(#4263)
* android, desktop: selectable cards for proxy options
* title
---
.../simplex/common/views/helpers/Section.kt | 24 ++++++++++++++++-
.../views/onboarding/SetNotificationsMode.kt | 27 ++++++++++++-------
.../views/usersettings/NetworkAndServers.kt | 5 ++--
3 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt
index c96a277fb8..94affad0e7 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/Section.kt
@@ -1,6 +1,5 @@
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
@@ -13,12 +12,15 @@ import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.*
+import chat.simplex.common.model.NotificationsMode
import chat.simplex.common.platform.onRightClick
import chat.simplex.common.platform.windowWidth
import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.*
+import chat.simplex.common.views.onboarding.SelectableCard
import chat.simplex.common.views.usersettings.SettingsActionItemWithContent
import chat.simplex.res.MR
+import dev.icerock.moko.resources.compose.stringResource
@Composable
fun SectionView(title: String? = null, padding: PaddingValues = PaddingValues(), content: (@Composable ColumnScope.() -> Unit)) {
@@ -76,6 +78,26 @@ fun SectionViewSelectable(
SectionTextFooter(values.first { it.value == currentValue.value }.description)
}
+@Composable
+fun SectionViewSelectableCards(
+ title: String?,
+ currentValue: State,
+ values: List>,
+ onSelected: (T) -> Unit,
+) {
+ SectionView(title) {
+ Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
+ if (title != null) {
+ Text(title, Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
+ Spacer(Modifier.height(DEFAULT_PADDING * 2f))
+ }
+ values.forEach { item ->
+ SelectableCard(currentValue, item.value, item.title, item.description, onSelected)
+ }
+ }
+ }
+}
+
@Composable
fun SectionItemView(
click: (() -> Unit)? = null,
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt
index 9124808959..61ecee74e4 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/onboarding/SetNotificationsMode.kt
@@ -8,6 +8,7 @@ import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.AnnotatedString
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
@@ -35,9 +36,15 @@ fun SetNotificationsMode(m: ChatModel) {
Column(Modifier.padding(horizontal = DEFAULT_PADDING * 1f)) {
Text(stringResource(MR.strings.onboarding_notifications_mode_subtitle), Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
Spacer(Modifier.height(DEFAULT_PADDING * 2f))
- NotificationButton(currentMode, NotificationsMode.OFF, MR.strings.onboarding_notifications_mode_off, MR.strings.onboarding_notifications_mode_off_desc)
- NotificationButton(currentMode, NotificationsMode.PERIODIC, MR.strings.onboarding_notifications_mode_periodic, MR.strings.onboarding_notifications_mode_periodic_desc)
- NotificationButton(currentMode, NotificationsMode.SERVICE, MR.strings.onboarding_notifications_mode_service, MR.strings.onboarding_notifications_mode_service_desc)
+ SelectableCard(currentMode, NotificationsMode.OFF, stringResource(MR.strings.onboarding_notifications_mode_off), annotatedStringResource(MR.strings.onboarding_notifications_mode_off_desc)) {
+ currentMode.value = NotificationsMode.OFF
+ }
+ SelectableCard(currentMode, NotificationsMode.PERIODIC, stringResource(MR.strings.onboarding_notifications_mode_periodic), annotatedStringResource(MR.strings.onboarding_notifications_mode_periodic_desc)){
+ currentMode.value = NotificationsMode.PERIODIC
+ }
+ SelectableCard(currentMode, NotificationsMode.SERVICE, stringResource(MR.strings.onboarding_notifications_mode_service), annotatedStringResource(MR.strings.onboarding_notifications_mode_service_desc)){
+ currentMode.value = NotificationsMode.SERVICE
+ }
}
Spacer(Modifier.fillMaxHeight().weight(1f))
Box(Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), contentAlignment = Alignment.Center) {
@@ -54,22 +61,22 @@ fun SetNotificationsMode(m: ChatModel) {
expect fun SetNotificationsModeAdditions()
@Composable
-private fun NotificationButton(currentMode: MutableState, mode: NotificationsMode, title: StringResource, description: StringResource) {
+fun SelectableCard(currentValue: State, newValue: T, title: String, description: AnnotatedString, onSelected: (T) -> Unit) {
TextButton(
- onClick = { currentMode.value = mode },
- border = BorderStroke(1.dp, color = if (currentMode.value == mode) MaterialTheme.colors.primary else MaterialTheme.colors.secondary.copy(alpha = 0.5f)),
+ onClick = { onSelected(newValue) },
+ border = BorderStroke(1.dp, color = if (currentValue.value == newValue) MaterialTheme.colors.primary else MaterialTheme.colors.secondary.copy(alpha = 0.5f)),
shape = RoundedCornerShape(35.dp),
) {
- Column(Modifier.padding(horizontal = 10.dp).padding(top = 4.dp, bottom = 8.dp)) {
+ Column(Modifier.padding(horizontal = 10.dp).padding(top = 4.dp, bottom = 8.dp).fillMaxWidth()) {
Text(
- stringResource(title),
+ title,
style = MaterialTheme.typography.h3,
fontWeight = FontWeight.Medium,
- color = if (currentMode.value == mode) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
+ color = if (currentValue.value == newValue) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
modifier = Modifier.padding(bottom = 8.dp).align(Alignment.CenterHorizontally),
textAlign = TextAlign.Center
)
- Text(annotatedStringResource(description),
+ Text(description,
Modifier.align(Alignment.CenterHorizontally),
fontSize = 15.sp,
color = MaterialTheme.colors.onBackground,
diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt
index d07fad8623..5898ccb657 100644
--- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt
+++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/NetworkAndServers.kt
@@ -7,6 +7,7 @@ import SectionItemView
import SectionItemWithValue
import SectionView
import SectionViewSelectable
+import SectionViewSelectableCards
import TextIconSpaced
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
@@ -555,7 +556,7 @@ private fun SMPProxyModePicker(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.network_smp_proxy_mode_private_routing))
- SectionViewSelectable(null, smpProxyMode, values, updateSMPProxyMode)
+ SectionViewSelectableCards(null, smpProxyMode, values, updateSMPProxyMode)
}
}
}
@@ -592,7 +593,7 @@ private fun SMPProxyFallbackPicker(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(MR.strings.network_smp_proxy_fallback_allow_downgrade))
- SectionViewSelectable(null, smpProxyFallback, values, updateSMPProxyFallback)
+ SectionViewSelectableCards(null, smpProxyFallback, values, updateSMPProxyFallback)
}
}
}
From c52e5349db3139dd88f0e291d95f91422ab88cd2 Mon Sep 17 00:00:00 2001
From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com>
Date: Sat, 1 Jun 2024 04:47:57 +0700
Subject: [PATCH 09/19] ios: more sheets will become hidden while protect
screen on (#4259)
Co-authored-by: Evgeny Poberezkin
---
.../Views/Chat/ChatItem/CIInvalidJSONView.swift | 2 +-
apps/ios/Shared/Views/Chat/ChatView.swift | 2 +-
apps/ios/Shared/Views/ChatList/ChatListNavLink.swift | 12 +++++++-----
.../Shared/Views/UserSettings/UserProfilesView.swift | 4 ++--
4 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/apps/ios/Shared/Views/Chat/ChatItem/CIInvalidJSONView.swift b/apps/ios/Shared/Views/Chat/ChatItem/CIInvalidJSONView.swift
index 0299a5e6f8..40ed8bc76c 100644
--- a/apps/ios/Shared/Views/Chat/ChatItem/CIInvalidJSONView.swift
+++ b/apps/ios/Shared/Views/Chat/ChatItem/CIInvalidJSONView.swift
@@ -24,7 +24,7 @@ struct CIInvalidJSONView: View {
.cornerRadius(18)
.textSelection(.disabled)
.onTapGesture { showJSON = true }
- .sheet(isPresented: $showJSON) {
+ .appSheet(isPresented: $showJSON) {
invalidJSONView(json)
}
}
diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift
index 4055ca2b28..27eb3bd653 100644
--- a/apps/ios/Shared/Views/Chat/ChatView.swift
+++ b/apps/ios/Shared/Views/Chat/ChatView.swift
@@ -131,7 +131,7 @@ struct ChatView: View {
} label: {
ChatInfoToolbar(chat: chat)
}
- .sheet(isPresented: $showChatInfoSheet, onDismiss: {
+ .appSheet(isPresented: $showChatInfoSheet, onDismiss: {
connectionStats = nil
customUserProfile = nil
connectionCode = nil
diff --git a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift
index efe254323e..73c3c73556 100644
--- a/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift
+++ b/apps/ios/Shared/Views/ChatList/ChatListNavLink.swift
@@ -349,10 +349,12 @@ struct ChatListNavLink: View {
.tint(.accentColor)
}
.frame(height: rowHeights[dynamicTypeSize])
- .sheet(isPresented: $showContactConnectionInfo) {
- if case let .contactConnection(contactConnection) = chat.chatInfo {
- ContactConnectionInfo(contactConnection: contactConnection)
- .environment(\EnvironmentValues.refresh as! WritableKeyPath, nil)
+ .appSheet(isPresented: $showContactConnectionInfo) {
+ Group {
+ if case let .contactConnection(contactConnection) = chat.chatInfo {
+ ContactConnectionInfo(contactConnection: contactConnection)
+ .environment(\EnvironmentValues.refresh as! WritableKeyPath, nil)
+ }
}
}
.onTapGesture {
@@ -467,7 +469,7 @@ struct ChatListNavLink: View {
.padding(4)
.frame(height: rowHeights[dynamicTypeSize])
.onTapGesture { showInvalidJSON = true }
- .sheet(isPresented: $showInvalidJSON) {
+ .appSheet(isPresented: $showInvalidJSON) {
invalidJSONView(json)
.environment(\EnvironmentValues.refresh as! WritableKeyPath, nil)
}
diff --git a/apps/ios/Shared/Views/UserSettings/UserProfilesView.swift b/apps/ios/Shared/Views/UserSettings/UserProfilesView.swift
index 8c1a3bf4e1..5da7c8e877 100644
--- a/apps/ios/Shared/Views/UserSettings/UserProfilesView.swift
+++ b/apps/ios/Shared/Views/UserSettings/UserProfilesView.swift
@@ -123,7 +123,7 @@ struct UserProfilesView: View {
deleteModeButton("Profile and server connections", true)
deleteModeButton("Local profile data only", false)
}
- .sheet(item: $selectedUser) { user in
+ .appSheet(item: $selectedUser) { user in
HiddenProfileView(user: user, profileHidden: $profileHidden)
}
.onChange(of: profileHidden) { _ in
@@ -131,7 +131,7 @@ struct UserProfilesView: View {
withAnimation { profileHidden = false }
}
}
- .sheet(item: $profileAction) { action in
+ .appSheet(item: $profileAction) { action in
profileActionView(action)
}
.alert(item: $alert) { alert in
From 6ad1423f295d70cc67cbdb3f0bd17a37135e5b35 Mon Sep 17 00:00:00 2001
From: Evgeny Poberezkin
Date: Fri, 31 May 2024 23:35:00 +0100
Subject: [PATCH 10/19] core: 5.7.5.0 (simplexmq: 5.7.6.0, file download fix)
---
cabal.project | 2 +-
package.yaml | 2 +-
scripts/nix/sha256map.nix | 2 +-
simplex-chat.cabal | 2 +-
tests/ChatClient.hs | 3 ++-
5 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/cabal.project b/cabal.project
index 9efbb332ff..9e8e0e1dac 100644
--- a/cabal.project
+++ b/cabal.project
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
- tag: df35c50b99a1291aac3ff86ed71387bb4f03c984
+ tag: 0b5ab3a374ff0ed9719a77fdda03a296e49eb78b
source-repository-package
type: git
diff --git a/package.yaml b/package.yaml
index 606cd16b4e..96439b1633 100644
--- a/package.yaml
+++ b/package.yaml
@@ -1,5 +1,5 @@
name: simplex-chat
-version: 5.7.4.1
+version: 5.7.5.0
#synopsis:
#description:
homepage: https://github.com/simplex-chat/simplex-chat#readme
diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix
index 7c11ea0e9f..2eca78943d 100644
--- a/scripts/nix/sha256map.nix
+++ b/scripts/nix/sha256map.nix
@@ -1,5 +1,5 @@
{
- "https://github.com/simplex-chat/simplexmq.git"."df35c50b99a1291aac3ff86ed71387bb4f03c984" = "0a3vvay14a0f7ypl94fag23g0z7b1kpq3l36kw6jgb0fjhr84m83";
+ "https://github.com/simplex-chat/simplexmq.git"."0b5ab3a374ff0ed9719a77fdda03a296e49eb78b" = "1p4pqv9i1isjws037ll8nkb0lhrkqkm8ck3kvjb7akxaq43v3nl4";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
diff --git a/simplex-chat.cabal b/simplex-chat.cabal
index 681bcc9e57..5b1e1c8675 100644
--- a/simplex-chat.cabal
+++ b/simplex-chat.cabal
@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack
name: simplex-chat
-version: 5.7.4.1
+version: 5.7.5.0
category: Web, System, Services, Cryptography
homepage: https://github.com/simplex-chat/simplex-chat#readme
author: simplex.chat
diff --git a/tests/ChatClient.hs b/tests/ChatClient.hs
index 4897a3b3d3..34ab002d37 100644
--- a/tests/ChatClient.hs
+++ b/tests/ChatClient.hs
@@ -463,7 +463,8 @@ xftpServerConfig =
serverStatsLogFile = "tests/tmp/xftp-server-stats.daily.log",
serverStatsBackupFile = Nothing,
controlPort = Nothing,
- transportConfig = defaultTransportServerConfig
+ transportConfig = defaultTransportServerConfig,
+ responseDelay = 0
}
withXFTPServer :: IO () -> IO ()
From ef30fcf5e2f6e9834f10e08a08a347f02942f147 Mon Sep 17 00:00:00 2001
From: Evgeny Poberezkin
Date: Fri, 31 May 2024 23:41:20 +0100
Subject: [PATCH 11/19] cli: options for private message routing and fallback
mode (#4256)
* cli: options for private message routing and fallback mode
* remove short options
* fix tests
* encoding
* fix
---
cabal.project | 2 +-
src/Simplex/Chat.hs | 36 +++++++++++++++++-------
src/Simplex/Chat/Controller.hs | 16 ++++++++++-
src/Simplex/Chat/Mobile.hs | 3 +-
src/Simplex/Chat/Options.hs | 46 +++++++++++++++++++------------
src/Simplex/Chat/Terminal/Main.hs | 14 ++++++----
src/Simplex/Chat/View.hs | 12 ++++++--
tests/ChatClient.hs | 9 +++---
8 files changed, 95 insertions(+), 43 deletions(-)
diff --git a/cabal.project b/cabal.project
index cbbe549649..0754c5b439 100644
--- a/cabal.project
+++ b/cabal.project
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
- tag: 88f1b727e0e4bfef01a346d818b7f6d94a181b16
+ tag: e1017e2a7ffff80a779f66fbb99189849b68b547
source-repository-package
type: git
diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs
index 54e9f31b4f..5eb75148cc 100644
--- a/src/Simplex/Chat.hs
+++ b/src/Simplex/Chat.hs
@@ -94,7 +94,7 @@ import qualified Simplex.FileTransfer.Description as FD
import Simplex.FileTransfer.Protocol (FileParty (..), FilePartyI)
import qualified Simplex.FileTransfer.Transport as XFTP
import Simplex.Messaging.Agent as Agent
-import Simplex.Messaging.Agent.Client (AgentStatsKey (..), SubInfo (..), agentClientStore, getAgentQueuesInfo, getAgentWorkersDetails, getAgentWorkersSummary, ipAddressProtected, temporaryAgentError, withLockMap)
+import Simplex.Messaging.Agent.Client (AgentStatsKey (..), SubInfo (..), agentClientStore, getAgentQueuesInfo, getAgentWorkersDetails, getAgentWorkersSummary, getNetworkConfig', ipAddressProtected, temporaryAgentError, withLockMap)
import Simplex.Messaging.Agent.Env.SQLite (AgentConfig (..), InitialAgentServers (..), createAgentStore, defaultAgentConfig)
import Simplex.Messaging.Agent.Lock (withLock)
import Simplex.Messaging.Agent.Protocol
@@ -103,7 +103,7 @@ import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..), Migrati
import Simplex.Messaging.Agent.Store.SQLite.DB (SlowQueryStats (..))
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
import qualified Simplex.Messaging.Agent.Store.SQLite.Migrations as Migrations
-import Simplex.Messaging.Client (ProxyClientError (..), defaultNetworkConfig)
+import Simplex.Messaging.Client (ProxyClientError (..), NetworkConfig (..), defaultNetworkConfig)
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Crypto.File (CryptoFile (..), CryptoFileArgs (..))
import qualified Simplex.Messaging.Crypto.File as CF
@@ -218,7 +218,7 @@ newChatController
ChatDatabase {chatStore, agentStore}
user
cfg@ChatConfig {agentConfig = aCfg, defaultServers, inlineFiles, deviceNameForRemote}
- ChatOpts {coreOptions = CoreChatOpts {smpServers, xftpServers, networkConfig, logLevel, logConnections, logServerHosts, logFile, tbqSize, highlyAvailable}, deviceName, optFilesFolder, optTempDirectory, showReactions, allowInstantFiles, autoAcceptFileSize}
+ ChatOpts {coreOptions = CoreChatOpts {smpServers, xftpServers, simpleNetCfg, logLevel, logConnections, logServerHosts, logFile, tbqSize, highlyAvailable}, deviceName, optFilesFolder, optTempDirectory, showReactions, allowInstantFiles, autoAcceptFileSize}
backgroundMode = do
let inlineFiles' = if allowInstantFiles || autoAcceptFileSize > 0 then inlineFiles else inlineFiles {sendChunks = 0, receiveInstant = False}
config = cfg {logLevel, showReactions, tbqSize, subscriptionEvents = logConnections, hostEvents = logServerHosts, defaultServers = configServers, inlineFiles = inlineFiles', autoAcceptFileSize, highlyAvailable}
@@ -303,7 +303,7 @@ newChatController
let DefaultAgentServers {smp = defSmp, xftp = defXftp} = defaultServers
smp' = fromMaybe defSmp (nonEmpty smpServers)
xftp' = fromMaybe defXftp (nonEmpty xftpServers)
- in defaultServers {smp = smp', xftp = xftp', netCfg = networkConfig}
+ in defaultServers {smp = smp', xftp = xftp', netCfg = updateNetworkConfig defaultNetworkConfig simpleNetCfg}
agentServers :: ChatConfig -> IO InitialAgentServers
agentServers config@ChatConfig {defaultServers = defServers@DefaultAgentServers {ntf, netCfg}} = do
users <- withTransaction chatStore getUsers
@@ -321,6 +321,13 @@ newChatController
userServers :: User -> IO (NonEmpty (ProtoServerWithAuth p))
userServers user' = activeAgentServers config protocol <$> withTransaction chatStore (`getProtocolServers` user')
+updateNetworkConfig :: NetworkConfig -> SimpleNetCfg -> NetworkConfig
+updateNetworkConfig cfg SimpleNetCfg {socksProxy, smpProxyMode_, smpProxyFallback_, tcpTimeout_, logTLSErrors} =
+ let cfg1 = maybe cfg (\smpProxyMode -> cfg {smpProxyMode}) smpProxyMode_
+ cfg2 = maybe cfg1 (\smpProxyFallback -> cfg1 {smpProxyFallback}) smpProxyFallback_
+ cfg3 = maybe cfg2 (\tcpTimeout -> cfg2 {tcpTimeout, tcpConnectTimeout = (tcpTimeout * 3) `div` 2}) tcpTimeout_
+ in cfg3 {socksProxy, logTLSErrors}
+
withChatLock :: String -> CM a -> CM a
withChatLock name action = asks chatLock >>= \l -> withLock l name action
@@ -1342,7 +1349,11 @@ processChatCommand' vr = \case
processChatCommand $ APIGetChatItemTTL userId
APISetNetworkConfig cfg -> withUser' $ \_ -> lift (withAgent' (`setNetworkConfig` cfg)) >> ok_
APIGetNetworkConfig -> withUser' $ \_ ->
- lift $ CRNetworkConfig <$> withAgent' getNetworkConfig
+ CRNetworkConfig <$> lift getNetworkConfig
+ SetNetworkConfig netCfg -> do
+ cfg <- lift getNetworkConfig
+ void . processChatCommand $ APISetNetworkConfig $ updateNetworkConfig cfg netCfg
+ pure $ CRNetworkConfig cfg
APISetNetworkInfo info -> lift (withAgent' (`setUserNetworkInfo` info)) >> ok_
ReconnectAllServers -> withUser' $ \_ -> lift (withAgent' reconnectAllServers) >> ok_
APISetChatSettings (ChatRef cType chatId) chatSettings -> withUser $ \user -> case cType of
@@ -3194,7 +3205,7 @@ receiveViaCompleteFD user fileId RcvFileDescr {fileDescrText, fileDescrComplete}
pure $ filter (`notElem` knownSrvs) srvs
ipProtectedForSrvs :: [XFTPServer] -> CM Bool
ipProtectedForSrvs srvs = do
- netCfg <- lift $ withAgent' getNetworkConfig
+ netCfg <- lift getNetworkConfig
pure $ all (ipAddressProtected netCfg) srvs
relaysNotApproved :: [XFTPServer] -> CM ()
relaysNotApproved unknownSrvs = do
@@ -3202,6 +3213,9 @@ receiveViaCompleteFD user fileId RcvFileDescr {fileDescrText, fileDescrComplete}
forM_ aci_ $ \aci -> toView $ CRChatItemUpdated user aci
throwChatError $ CEFileNotApproved fileId unknownSrvs
+getNetworkConfig :: CM' NetworkConfig
+getNetworkConfig = withAgent' $ liftIO . getNetworkConfig'
+
resetRcvCIFileStatus :: User -> FileTransferId -> CIFileStatus 'MDRcv -> CM (Maybe AChatItem)
resetRcvCIFileStatus user fileId ciFileStatus = do
vr <- chatVersionRange
@@ -7365,7 +7379,7 @@ chatCommandP =
"/ttl" $> GetChatItemTTL,
"/_network info " *> (APISetNetworkInfo <$> jsonP),
"/_network " *> (APISetNetworkConfig <$> jsonP),
- ("/network " <|> "/net ") *> (APISetNetworkConfig <$> netCfgP),
+ ("/network " <|> "/net ") *> (SetNetworkConfig <$> netCfgP),
("/network" <|> "/net") $> APIGetNetworkConfig,
"/reconnect" $> ReconnectAllServers,
"/_settings " *> (APISetChatSettings <$> chatRefP <* A.space <*> jsonP),
@@ -7678,10 +7692,12 @@ chatCommandP =
<|> ("no" $> TMEDisableKeepTTL)
netCfgP = do
socksProxy <- "socks=" *> ("off" $> Nothing <|> "on" $> Just defaultSocksProxy <|> Just <$> strP)
+ smpProxyMode_ <- optional $ " smp-proxy=" *> strP
+ smpProxyFallback_ <- optional $ " smp-proxy-fallback=" *> strP
t_ <- optional $ " timeout=" *> A.decimal
- logErrors <- " log=" *> onOffP <|> pure False
- let tcpTimeout = 1000000 * fromMaybe (maybe 5 (const 10) socksProxy) t_
- pure $ fullNetworkConfig socksProxy tcpTimeout logErrors
+ logTLSErrors <- " log=" *> onOffP <|> pure False
+ let tcpTimeout_ = (1000000 *) <$> t_
+ pure $ SimpleNetCfg {socksProxy, smpProxyMode_, smpProxyFallback_, tcpTimeout_, logTLSErrors}
dbKeyP = nonEmptyKey <$?> strP
nonEmptyKey k@(DBEncryptionKey s) = if BA.null s then Left "empty key" else Right k
dbEncryptionConfig currentKey newKey = DBEncryptionConfig {currentKey, newKey, keepKey = Just False}
diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs
index 9053f673f0..77b14b5eac 100644
--- a/src/Simplex/Chat/Controller.hs
+++ b/src/Simplex/Chat/Controller.hs
@@ -75,6 +75,7 @@ import Simplex.Messaging.Agent.Protocol
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation, SQLiteStore, UpMigration, withTransaction)
import Simplex.Messaging.Agent.Store.SQLite.DB (SlowQueryStats (..))
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
+import Simplex.Messaging.Client (SMPProxyMode (..), SMPProxyFallback (..))
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Crypto.File (CryptoFile (..))
import qualified Simplex.Messaging.Crypto.File as CF
@@ -86,7 +87,7 @@ import Simplex.Messaging.Protocol (AProtoServerWithAuth, AProtocolType (..), Cor
import Simplex.Messaging.Server.QueueStore.QueueInfo
import Simplex.Messaging.TMap (TMap)
import Simplex.Messaging.Transport (TLS, simplexMQVersion)
-import Simplex.Messaging.Transport.Client (TransportHost)
+import Simplex.Messaging.Transport.Client (SocksProxy, TransportHost)
import Simplex.Messaging.Util (allFinally, catchAllErrors, catchAllErrors', tryAllErrors, tryAllErrors', (<$$>))
import Simplex.RemoteControl.Client
import Simplex.RemoteControl.Invitation (RCSignedInvitation, RCVerifiedInvitation)
@@ -351,6 +352,7 @@ data ChatCommand
| GetChatItemTTL
| APISetNetworkConfig NetworkConfig
| APIGetNetworkConfig
+ | SetNetworkConfig SimpleNetCfg
| APISetNetworkInfo UserNetworkInfo
| ReconnectAllServers
| APISetChatSettings ChatRef ChatSettings
@@ -961,6 +963,18 @@ data AppFilePathsConfig = AppFilePathsConfig
}
deriving (Show)
+data SimpleNetCfg = SimpleNetCfg
+ { socksProxy :: Maybe SocksProxy,
+ smpProxyMode_ :: Maybe SMPProxyMode,
+ smpProxyFallback_ :: Maybe SMPProxyFallback,
+ tcpTimeout_ :: Maybe Int,
+ logTLSErrors :: Bool
+ }
+ deriving (Show)
+
+defaultSimpleNetCfg :: SimpleNetCfg
+defaultSimpleNetCfg = SimpleNetCfg Nothing Nothing Nothing Nothing False
+
data ContactSubStatus = ContactSubStatus
{ contact :: Contact,
contactError :: Maybe ChatError
diff --git a/src/Simplex/Chat/Mobile.hs b/src/Simplex/Chat/Mobile.hs
index 5883c6042c..486e0d62f3 100644
--- a/src/Simplex/Chat/Mobile.hs
+++ b/src/Simplex/Chat/Mobile.hs
@@ -48,7 +48,6 @@ import Simplex.Chat.Types
import Simplex.Messaging.Agent.Client (agentClientStore)
import Simplex.Messaging.Agent.Env.SQLite (createAgentStore)
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..), MigrationError, closeSQLiteStore, reopenSQLiteStore)
-import Simplex.Messaging.Client (defaultNetworkConfig)
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Parsers (defaultJSON, dropPrefix, sumTypeJSON)
@@ -192,7 +191,7 @@ mobileChatOpts dbFilePrefix =
dbKey = "", -- for API database is already opened, and the key in options is not used
smpServers = [],
xftpServers = [],
- networkConfig = defaultNetworkConfig,
+ simpleNetCfg = defaultSimpleNetCfg,
logLevel = CLLImportant,
logConnections = False,
logServerHosts = True,
diff --git a/src/Simplex/Chat/Options.hs b/src/Simplex/Chat/Options.hs
index 871e3358ec..747414af37 100644
--- a/src/Simplex/Chat/Options.hs
+++ b/src/Simplex/Chat/Options.hs
@@ -13,7 +13,6 @@ module Simplex.Chat.Options
coreChatOptsP,
getChatOpts,
protocolServersP,
- fullNetworkConfig,
)
where
@@ -22,15 +21,17 @@ import qualified Data.Attoparsec.ByteString.Char8 as A
import Data.ByteArray (ScrubbedBytes)
import qualified Data.ByteString.Char8 as B
import Data.Text (Text)
+import qualified Data.Text as T
+import Data.Text.Encoding (encodeUtf8)
import Numeric.Natural (Natural)
import Options.Applicative
-import Simplex.Chat.Controller (ChatLogLevel (..), updateStr, versionNumber, versionString)
+import Simplex.Chat.Controller (ChatLogLevel (..), SimpleNetCfg (..), updateStr, versionNumber, versionString)
import Simplex.FileTransfer.Description (mb)
-import Simplex.Messaging.Client (NetworkConfig (..), defaultNetworkConfig)
+import Simplex.Messaging.Client (SMPProxyMode (..), SMPProxyFallback (..))
import Simplex.Messaging.Encoding.String
import Simplex.Messaging.Parsers (parseAll)
import Simplex.Messaging.Protocol (ProtoServerWithAuth, ProtocolTypeI, SMPServerWithAuth, XFTPServerWithAuth)
-import Simplex.Messaging.Transport.Client (SocksProxy, defaultSocksProxy)
+import Simplex.Messaging.Transport.Client (defaultSocksProxy)
import System.FilePath (combine)
data ChatOpts = ChatOpts
@@ -55,7 +56,7 @@ data CoreChatOpts = CoreChatOpts
dbKey :: ScrubbedBytes,
smpServers :: [SMPServerWithAuth],
xftpServers :: [XFTPServerWithAuth],
- networkConfig :: NetworkConfig,
+ simpleNetCfg :: SimpleNetCfg,
logLevel :: ChatLogLevel,
logConnections :: Bool,
logServerHosts :: Bool,
@@ -123,18 +124,34 @@ coreChatOptsP appDir defaultDbFileName = do
socksProxy <-
flag' (Just defaultSocksProxy) (short 'x' <> help "Use local SOCKS5 proxy at :9050")
<|> option
- parseSocksProxy
+ strParse
( long "socks-proxy"
<> metavar "SOCKS5"
<> help "Use SOCKS5 proxy at `ipv4:port` or `:port`"
<> value Nothing
)
+ smpProxyMode_ <-
+ optional $
+ option
+ strParse
+ ( long "smp-proxy"
+ <> metavar "SMP_PROXY_MODE"
+ <> help "Use private message routing: always, unknown, unprotected, never (default)"
+ )
+ smpProxyFallback_ <-
+ optional $
+ option
+ strParse
+ ( long "smp-proxy-fallback"
+ <> metavar "SMP_PROXY_FALLBACK_MODE"
+ <> help "Allow downgrade and connect directly: no, [when IP address is] protected, yes (default)"
+ )
t <-
option
auto
( long "tcp-timeout"
<> metavar "TIMEOUT"
- <> help "TCP timeout, seconds (default: 5/10 without/with SOCKS5 proxy)"
+ <> help "TCP timeout, seconds (default: 7/15 without/with SOCKS5 proxy)"
<> value 0
)
logLevel <-
@@ -149,7 +166,7 @@ coreChatOptsP appDir defaultDbFileName = do
logTLSErrors <-
switch
( long "log-tls-errors"
- <> help "Log TLS errors (also enabled with `-l debug`)"
+ <> help "Log TLS errors"
)
logConnections <-
switch
@@ -194,7 +211,7 @@ coreChatOptsP appDir defaultDbFileName = do
dbKey,
smpServers,
xftpServers,
- networkConfig = fullNetworkConfig socksProxy (useTcpTimeout socksProxy t) (logTLSErrors || logLevel == CLLDebug),
+ simpleNetCfg = SimpleNetCfg {socksProxy, smpProxyMode_, smpProxyFallback_, tcpTimeout_ = Just $ useTcpTimeout socksProxy t, logTLSErrors},
logLevel,
logConnections = logConnections || logLevel <= CLLInfo,
logServerHosts = logServerHosts || logLevel <= CLLInfo,
@@ -204,7 +221,7 @@ coreChatOptsP appDir defaultDbFileName = do
highlyAvailable
}
where
- useTcpTimeout p t = 1000000 * if t > 0 then t else maybe 5 (const 10) p
+ useTcpTimeout p t = 1000000 * if t > 0 then t else maybe 7 (const 15) p
defaultDbFilePath = combine appDir defaultDbFileName
chatOptsP :: FilePath -> FilePath -> Parser ChatOpts
@@ -321,16 +338,11 @@ chatOptsP appDir defaultDbFileName = do
maintenance
}
-fullNetworkConfig :: Maybe SocksProxy -> Int -> Bool -> NetworkConfig
-fullNetworkConfig socksProxy tcpTimeout logTLSErrors =
- let tcpConnectTimeout = (tcpTimeout * 3) `div` 2
- in defaultNetworkConfig {socksProxy, tcpTimeout, tcpConnectTimeout, logTLSErrors}
-
parseProtocolServers :: ProtocolTypeI p => ReadM [ProtoServerWithAuth p]
parseProtocolServers = eitherReader $ parseAll protocolServersP . B.pack
-parseSocksProxy :: ReadM (Maybe SocksProxy)
-parseSocksProxy = eitherReader $ parseAll strP . B.pack
+strParse :: StrEncoding a => ReadM a
+strParse = eitherReader $ parseAll strP . encodeUtf8 . T.pack
parseServerPort :: ReadM (Maybe String)
parseServerPort = eitherReader $ parseAll serverPortP . B.pack
diff --git a/src/Simplex/Chat/Terminal/Main.hs b/src/Simplex/Chat/Terminal/Main.hs
index 2b26bb1d66..3e7d933669 100644
--- a/src/Simplex/Chat/Terminal/Main.hs
+++ b/src/Simplex/Chat/Terminal/Main.hs
@@ -6,15 +6,16 @@ module Simplex.Chat.Terminal.Main where
import Control.Concurrent (forkIO, threadDelay)
import Control.Concurrent.STM
import Control.Monad
+import Data.Maybe (fromMaybe)
import Data.Time.Clock (getCurrentTime)
import Data.Time.LocalTime (getCurrentTimeZone)
import Network.Socket
-import Simplex.Chat.Controller (ChatConfig, ChatController (..), ChatResponse (..), currentRemoteHost, versionNumber, versionString)
+import Simplex.Chat.Controller (ChatConfig, ChatController (..), ChatResponse (..), SimpleNetCfg (..), currentRemoteHost, versionNumber, versionString)
import Simplex.Chat.Core
import Simplex.Chat.Options
import Simplex.Chat.Terminal
-import Simplex.Chat.View (serializeChatResponse)
-import Simplex.Messaging.Client (NetworkConfig (..))
+import Simplex.Chat.View (serializeChatResponse, smpProxyModeStr)
+import Simplex.Messaging.Client (NetworkConfig (..), defaultNetworkConfig)
import System.Directory (getAppUserDataDirectory)
import System.Exit (exitFailure)
import System.Terminal (withTerminal)
@@ -51,7 +52,7 @@ simplexChatCLI cfg server_ = do
putStrLn $ serializeChatResponse (rh, Just user) ts tz rh r
welcome :: ChatOpts -> IO ()
-welcome ChatOpts {coreOptions = CoreChatOpts {dbFilePrefix, networkConfig}} =
+welcome ChatOpts {coreOptions = CoreChatOpts {dbFilePrefix, simpleNetCfg = SimpleNetCfg {socksProxy, smpProxyMode_, smpProxyFallback_}}} =
mapM_
putStrLn
[ versionString versionNumber,
@@ -59,6 +60,9 @@ welcome ChatOpts {coreOptions = CoreChatOpts {dbFilePrefix, networkConfig}} =
maybe
"direct network connection - use `/network` command or `-x` CLI option to connect via SOCKS5 at :9050"
(("using SOCKS5 proxy " <>) . show)
- (socksProxy networkConfig),
+ socksProxy,
+ smpProxyModeStr
+ (fromMaybe (smpProxyMode defaultNetworkConfig) smpProxyMode_)
+ (fromMaybe (smpProxyFallback defaultNetworkConfig) smpProxyFallback_),
"type \"/help\" or \"/h\" for usage info"
]
diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs
index a315e755e1..6c02eac991 100644
--- a/src/Simplex/Chat/View.hs
+++ b/src/Simplex/Chat/View.hs
@@ -55,6 +55,7 @@ import Simplex.Messaging.Agent.Client (ProtocolTestFailure (..), ProtocolTestSte
import Simplex.Messaging.Agent.Env.SQLite (NetworkConfig (..))
import Simplex.Messaging.Agent.Protocol
import Simplex.Messaging.Agent.Store.SQLite.DB (SlowQueryStats (..))
+import Simplex.Messaging.Client (SMPProxyMode (..), SMPProxyFallback)
import qualified Simplex.Messaging.Crypto as C
import Simplex.Messaging.Crypto.File (CryptoFile (..), CryptoFileArgs (..))
import qualified Simplex.Messaging.Crypto.Ratchet as CR
@@ -64,7 +65,7 @@ import Simplex.Messaging.Parsers (dropPrefix, taggedObjectJSON)
import Simplex.Messaging.Protocol (AProtoServerWithAuth (..), AProtocolType, ProtoServerWithAuth, ProtocolServer (..), ProtocolTypeI, SProtocolType (..))
import qualified Simplex.Messaging.Protocol as SMP
import Simplex.Messaging.Transport.Client (TransportHost (..))
-import Simplex.Messaging.Util (tshow)
+import Simplex.Messaging.Util (bshow, safeDecodeUtf8, tshow)
import Simplex.Messaging.Version hiding (version)
import Simplex.RemoteControl.Types (RCCtrlAddress (..))
import System.Console.ANSI.Types
@@ -1213,12 +1214,17 @@ viewChatItemTTL = \case
deletedAfter ttlStr = ["old messages are set to be deleted after: " <> ttlStr]
viewNetworkConfig :: NetworkConfig -> [StyledString]
-viewNetworkConfig NetworkConfig {socksProxy, tcpTimeout} =
+viewNetworkConfig NetworkConfig {socksProxy, tcpTimeout, smpProxyMode, smpProxyFallback} =
[ plain $ maybe "direct network connection" (("using SOCKS5 proxy " <>) . show) socksProxy,
"TCP timeout: " <> sShow tcpTimeout,
- "use " <> highlight' "/network socks=[ timeout=]" <> " to change settings"
+ plain $ smpProxyModeStr smpProxyMode smpProxyFallback,
+ "use " <> highlight' "/network socks=[ timeout=][ smp-proxy=always/unknown/unprotected/never][ smp-proxy-fallback=no/protected/yes]" <> " to change settings"
]
+smpProxyModeStr :: SMPProxyMode -> SMPProxyFallback -> String
+smpProxyModeStr SPMNever _ = "private message routing disabled."
+smpProxyModeStr mode fallback = T.unpack $ safeDecodeUtf8 $ "private message routing mode: " <> strEncode mode <> ", fallback: " <> strEncode fallback
+
viewContactInfo :: Contact -> Maybe ConnectionStats -> Maybe Profile -> [StyledString]
viewContactInfo ct@Contact {contactId, profile = LocalProfile {localAlias, contactLink}, activeConn, uiThemes, customData} stats incognitoProfile =
["contact ID: " <> sShow contactId]
diff --git a/tests/ChatClient.hs b/tests/ChatClient.hs
index dfe7387372..589d880e8f 100644
--- a/tests/ChatClient.hs
+++ b/tests/ChatClient.hs
@@ -25,7 +25,7 @@ import Data.Maybe (isNothing)
import qualified Data.Text as T
import Network.Socket
import Simplex.Chat
-import Simplex.Chat.Controller (ChatCommand (..), ChatConfig (..), ChatController (..), ChatDatabase (..), ChatLogLevel (..))
+import Simplex.Chat.Controller (ChatCommand (..), ChatConfig (..), ChatController (..), ChatDatabase (..), ChatLogLevel (..), defaultSimpleNetCfg)
import Simplex.Chat.Core
import Simplex.Chat.Options
import Simplex.Chat.Protocol (currentChatVersion, pqEncryptionCompressionVersion)
@@ -44,7 +44,7 @@ import Simplex.Messaging.Agent.Protocol (currentSMPAgentVersion, duplexHandshake
import Simplex.Messaging.Agent.RetryInterval
import Simplex.Messaging.Agent.Store.SQLite (MigrationConfirmation (..), closeSQLiteStore)
import qualified Simplex.Messaging.Agent.Store.SQLite.DB as DB
-import Simplex.Messaging.Client (ProtocolClientConfig (..), defaultNetworkConfig)
+import Simplex.Messaging.Client (ProtocolClientConfig (..))
import Simplex.Messaging.Client.Agent (defaultSMPClientAgentConfig)
import Simplex.Messaging.Crypto.Ratchet (supportedE2EEncryptVRange)
import qualified Simplex.Messaging.Crypto.Ratchet as CR
@@ -94,7 +94,7 @@ testCoreOpts =
-- dbKey = "this is a pass-phrase to encrypt the database",
smpServers = ["smp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7001"],
xftpServers = ["xftp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=:server_password@localhost:7002"],
- networkConfig = defaultNetworkConfig,
+ simpleNetCfg = defaultSimpleNetCfg,
logLevel = CLLImportant,
logConnections = False,
logServerHosts = False,
@@ -473,7 +473,8 @@ xftpServerConfig =
serverStatsLogFile = "tests/tmp/xftp-server-stats.daily.log",
serverStatsBackupFile = Nothing,
controlPort = Nothing,
- transportConfig = defaultTransportServerConfig
+ transportConfig = defaultTransportServerConfig,
+ responseDelay = 0
}
withXFTPServer :: IO () -> IO ()
From 11d487218653cdf645dce89a465d4000a069ecf8 Mon Sep 17 00:00:00 2001
From: Evgeny Poberezkin
Date: Sat, 1 Jun 2024 00:22:26 +0100
Subject: [PATCH 12/19] core: 5.8.0.5 (simplexmq 5.8.0.10)
---
cabal.project | 2 +-
package.yaml | 2 +-
scripts/nix/sha256map.nix | 2 +-
simplex-chat.cabal | 2 +-
src/Simplex/Chat/Remote.hs | 4 ++--
5 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/cabal.project b/cabal.project
index 0754c5b439..6bd63f3bb2 100644
--- a/cabal.project
+++ b/cabal.project
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
- tag: e1017e2a7ffff80a779f66fbb99189849b68b547
+ tag: 2e4f507919dd3a08e5c4106fde193fee4414de3c
source-repository-package
type: git
diff --git a/package.yaml b/package.yaml
index accab5f0c4..2e73355d6f 100644
--- a/package.yaml
+++ b/package.yaml
@@ -1,5 +1,5 @@
name: simplex-chat
-version: 5.8.0.4
+version: 5.8.0.5
#synopsis:
#description:
homepage: https://github.com/simplex-chat/simplex-chat#readme
diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix
index f09bf7af57..6b74da3798 100644
--- a/scripts/nix/sha256map.nix
+++ b/scripts/nix/sha256map.nix
@@ -1,5 +1,5 @@
{
- "https://github.com/simplex-chat/simplexmq.git"."88f1b727e0e4bfef01a346d818b7f6d94a181b16" = "0i785dm8sm1c5lydq2kci1a3ix91q3hn89l7x80gnxyqgn4qq2gd";
+ "https://github.com/simplex-chat/simplexmq.git"."2e4f507919dd3a08e5c4106fde193fee4414de3c" = "1s035v77rpk8xs8gcfqm2ddp1mf5n35zrkq68gxqr634r2r9vbaj";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";
diff --git a/simplex-chat.cabal b/simplex-chat.cabal
index b70c2dd71b..5c4e9cd53f 100644
--- a/simplex-chat.cabal
+++ b/simplex-chat.cabal
@@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack
name: simplex-chat
-version: 5.8.0.4
+version: 5.8.0.5
category: Web, System, Services, Cryptography
homepage: https://github.com/simplex-chat/simplex-chat#readme
author: simplex.chat
diff --git a/src/Simplex/Chat/Remote.hs b/src/Simplex/Chat/Remote.hs
index 5b98ea119c..064fcc561e 100644
--- a/src/Simplex/Chat/Remote.hs
+++ b/src/Simplex/Chat/Remote.hs
@@ -72,11 +72,11 @@ import UnliftIO.Directory (copyFile, createDirectoryIfMissing, doesDirectoryExis
-- when acting as host
minRemoteCtrlVersion :: AppVersion
-minRemoteCtrlVersion = AppVersion [5, 8, 0, 2]
+minRemoteCtrlVersion = AppVersion [5, 8, 0, 4]
-- when acting as controller
minRemoteHostVersion :: AppVersion
-minRemoteHostVersion = AppVersion [5, 8, 0, 2]
+minRemoteHostVersion = AppVersion [5, 8, 0, 4]
currentAppVersion :: AppVersion
currentAppVersion = AppVersion SC.version
From ac8ee971f570cf3edcff18e03cb94cf31a585568 Mon Sep 17 00:00:00 2001
From: Evgeny Poberezkin
Date: Sat, 1 Jun 2024 09:15:41 +0100
Subject: [PATCH 13/19] 5.7.5: ios 222, android 216, desktop 51
---
apps/ios/SimpleX.xcodeproj/project.pbxproj | 64 +++++++++++-----------
apps/multiplatform/gradle.properties | 8 +--
2 files changed, 36 insertions(+), 36 deletions(-)
diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj
index be1ca4c444..9a15ef2f8a 100644
--- a/apps/ios/SimpleX.xcodeproj/project.pbxproj
+++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj
@@ -24,6 +24,11 @@
5C029EAA283942EA004A9677 /* CallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA9283942EA004A9677 /* CallController.swift */; };
5C05DF532840AA1D00C683F9 /* CallSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C05DF522840AA1D00C683F9 /* CallSettings.swift */; };
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; };
+ 5C0EA1312C0B05C000AD2E5E /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA12C2C0B05C000AD2E5E /* libgmp.a */; };
+ 5C0EA1322C0B05C000AD2E5E /* libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA12D2C0B05C000AD2E5E /* libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq-ghc9.6.3.a */; };
+ 5C0EA1332C0B05C000AD2E5E /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA12E2C0B05C000AD2E5E /* libffi.a */; };
+ 5C0EA1342C0B05C000AD2E5E /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA12F2C0B05C000AD2E5E /* libgmpxx.a */; };
+ 5C0EA1352C0B05C000AD2E5E /* libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1302C0B05C000AD2E5E /* libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq.a */; };
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */; };
5C10D88A28F187F300E58BF0 /* FullScreenMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C10D88928F187F300E58BF0 /* FullScreenMediaView.swift */; };
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
@@ -53,11 +58,6 @@
5C5E5D3B2824468B00B0488A /* ActiveCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5E5D3A2824468B00B0488A /* ActiveCallView.swift */; };
5C5F2B6D27EBC3FE006A9D5F /* ImagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5F2B6C27EBC3FE006A9D5F /* ImagePicker.swift */; };
5C5F2B7027EBC704006A9D5F /* ProfileImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5F2B6F27EBC704006A9D5F /* ProfileImage.swift */; };
- 5C614CFB2C021C1C000E7758 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C614CF62C021C1C000E7758 /* libffi.a */; };
- 5C614CFC2C021C1C000E7758 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C614CF72C021C1C000E7758 /* libgmpxx.a */; };
- 5C614CFD2C021C1C000E7758 /* libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C614CF82C021C1C000E7758 /* libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7-ghc9.6.3.a */; };
- 5C614CFE2C021C1C000E7758 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C614CF92C021C1C000E7758 /* libgmp.a */; };
- 5C614CFF2C021C1C000E7758 /* libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C614CFA2C021C1C000E7758 /* libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7.a */; };
5C65DAF929D0CC20003CEE45 /* DeveloperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C65DAF829D0CC20003CEE45 /* DeveloperView.swift */; };
5C65F343297D45E100B67AF3 /* VersionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C65F341297D3F3600B67AF3 /* VersionView.swift */; };
5C6BA667289BD954009B8ECC /* DismissSheets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6BA666289BD954009B8ECC /* DismissSheets.swift */; };
@@ -273,6 +273,11 @@
5C029EA9283942EA004A9677 /* CallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallController.swift; sourceTree = ""; };
5C05DF522840AA1D00C683F9 /* CallSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallSettings.swift; sourceTree = ""; };
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatPreviewView.swift; sourceTree = ""; };
+ 5C0EA12C2C0B05C000AD2E5E /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; };
+ 5C0EA12D2C0B05C000AD2E5E /* libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq-ghc9.6.3.a"; sourceTree = ""; };
+ 5C0EA12E2C0B05C000AD2E5E /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; };
+ 5C0EA12F2C0B05C000AD2E5E /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; };
+ 5C0EA1302C0B05C000AD2E5E /* libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq.a"; sourceTree = ""; };
5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionInfo.swift; sourceTree = ""; };
5C10D88928F187F300E58BF0 /* FullScreenMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenMediaView.swift; sourceTree = ""; };
5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestView.swift; sourceTree = ""; };
@@ -316,11 +321,6 @@
5C5E5D3C282447AB00B0488A /* CallTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallTypes.swift; sourceTree = ""; };
5C5F2B6C27EBC3FE006A9D5F /* ImagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePicker.swift; sourceTree = ""; };
5C5F2B6F27EBC704006A9D5F /* ProfileImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileImage.swift; sourceTree = ""; };
- 5C614CF62C021C1C000E7758 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; };
- 5C614CF72C021C1C000E7758 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; };
- 5C614CF82C021C1C000E7758 /* libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7-ghc9.6.3.a"; sourceTree = ""; };
- 5C614CF92C021C1C000E7758 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; };
- 5C614CFA2C021C1C000E7758 /* libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7.a"; sourceTree = ""; };
5C636F662AAB3D2400751C84 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = "uk.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = ""; };
5C636F672AAB3D2400751C84 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = ""; };
5C65DAE429C77136003CEE45 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; };
@@ -529,12 +529,12 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 5C614CFD2C021C1C000E7758 /* libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7-ghc9.6.3.a in Frameworks */,
- 5C614CFF2C021C1C000E7758 /* libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7.a in Frameworks */,
- 5C614CFC2C021C1C000E7758 /* libgmpxx.a in Frameworks */,
+ 5C0EA1342C0B05C000AD2E5E /* libgmpxx.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
- 5C614CFB2C021C1C000E7758 /* libffi.a in Frameworks */,
- 5C614CFE2C021C1C000E7758 /* libgmp.a in Frameworks */,
+ 5C0EA1352C0B05C000AD2E5E /* libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq.a in Frameworks */,
+ 5C0EA1312C0B05C000AD2E5E /* libgmp.a in Frameworks */,
+ 5C0EA1322C0B05C000AD2E5E /* libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq-ghc9.6.3.a in Frameworks */,
+ 5C0EA1332C0B05C000AD2E5E /* libffi.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -601,11 +601,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
- 5C614CF62C021C1C000E7758 /* libffi.a */,
- 5C614CF92C021C1C000E7758 /* libgmp.a */,
- 5C614CF72C021C1C000E7758 /* libgmpxx.a */,
- 5C614CF82C021C1C000E7758 /* libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7-ghc9.6.3.a */,
- 5C614CFA2C021C1C000E7758 /* libHSsimplex-chat-5.7.4.1-FMTNcSSNT86KdfUI39X2r7.a */,
+ 5C0EA12E2C0B05C000AD2E5E /* libffi.a */,
+ 5C0EA12C2C0B05C000AD2E5E /* libgmp.a */,
+ 5C0EA12F2C0B05C000AD2E5E /* libgmpxx.a */,
+ 5C0EA12D2C0B05C000AD2E5E /* libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq-ghc9.6.3.a */,
+ 5C0EA1302C0B05C000AD2E5E /* libHSsimplex-chat-5.7.5.0-IiqaTGbIKN89ePlb2e8Hnq.a */,
);
path = Libraries;
sourceTree = "";
@@ -1552,7 +1552,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 219;
+ CURRENT_PROJECT_VERSION = 222;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1577,7 +1577,7 @@
"@executable_path/Frameworks",
);
LLVM_LTO = YES_THIN;
- MARKETING_VERSION = 5.7.4;
+ MARKETING_VERSION = 5.7.5;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1601,7 +1601,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 219;
+ CURRENT_PROJECT_VERSION = 222;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1626,7 +1626,7 @@
"@executable_path/Frameworks",
);
LLVM_LTO = YES;
- MARKETING_VERSION = 5.7.4;
+ MARKETING_VERSION = 5.7.5;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1687,7 +1687,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 219;
+ CURRENT_PROJECT_VERSION = 222;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
@@ -1702,7 +1702,7 @@
"@executable_path/../../Frameworks",
);
LLVM_LTO = YES;
- MARKETING_VERSION = 5.7.4;
+ MARKETING_VERSION = 5.7.5;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1724,7 +1724,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 219;
+ CURRENT_PROJECT_VERSION = 222;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
@@ -1739,7 +1739,7 @@
"@executable_path/../../Frameworks",
);
LLVM_LTO = YES;
- MARKETING_VERSION = 5.7.4;
+ MARKETING_VERSION = 5.7.5;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1761,7 +1761,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 219;
+ CURRENT_PROJECT_VERSION = 222;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1787,7 +1787,7 @@
"$(PROJECT_DIR)/Libraries/sim",
);
LLVM_LTO = YES;
- MARKETING_VERSION = 5.7.4;
+ MARKETING_VERSION = 5.7.5;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
@@ -1812,7 +1812,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 219;
+ CURRENT_PROJECT_VERSION = 222;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1838,7 +1838,7 @@
"$(PROJECT_DIR)/Libraries/sim",
);
LLVM_LTO = YES;
- MARKETING_VERSION = 5.7.4;
+ MARKETING_VERSION = 5.7.5;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
diff --git a/apps/multiplatform/gradle.properties b/apps/multiplatform/gradle.properties
index 2c44f841f9..6e25eeafbc 100644
--- a/apps/multiplatform/gradle.properties
+++ b/apps/multiplatform/gradle.properties
@@ -26,11 +26,11 @@ android.enableJetifier=true
kotlin.mpp.androidSourceSetLayoutVersion=2
kotlin.jvm.target=11
-android.version_name=5.7.4
-android.version_code=212
+android.version_name=5.7.5
+android.version_code=216
-desktop.version_name=5.7.4
-desktop.version_code=48
+desktop.version_name=5.7.5
+desktop.version_code=51
kotlin.version=1.9.23
gradle.plugin.version=8.2.0
From 3fa70ba2171c556ac177c120bac6d2b824ca389d Mon Sep 17 00:00:00 2001
From: Evgeny Poberezkin
Date: Sat, 1 Jun 2024 11:03:22 +0100
Subject: [PATCH 14/19] 5.8-beta.5: ios 223, android 218, desktop 52
---
apps/ios/SimpleX.xcodeproj/project.pbxproj | 52 +++++++++++-----------
apps/multiplatform/gradle.properties | 8 ++--
2 files changed, 30 insertions(+), 30 deletions(-)
diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj
index 412ecc1258..ed889b5218 100644
--- a/apps/ios/SimpleX.xcodeproj/project.pbxproj
+++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj
@@ -24,11 +24,11 @@
5C029EAA283942EA004A9677 /* CallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA9283942EA004A9677 /* CallController.swift */; };
5C05DF532840AA1D00C683F9 /* CallSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C05DF522840AA1D00C683F9 /* CallSettings.swift */; };
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; };
- 5C0EA1272C08ADAF00AD2E5E /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1222C08ADAF00AD2E5E /* libgmp.a */; };
- 5C0EA1282C08ADAF00AD2E5E /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1232C08ADAF00AD2E5E /* libffi.a */; };
- 5C0EA1292C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1242C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a */; };
- 5C0EA12A2C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1252C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a */; };
- 5C0EA12B2C08ADAF00AD2E5E /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1262C08ADAF00AD2E5E /* libgmpxx.a */; };
+ 5C0EA13B2C0B176B00AD2E5E /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1362C0B176B00AD2E5E /* libgmp.a */; };
+ 5C0EA13C2C0B176B00AD2E5E /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1372C0B176B00AD2E5E /* libgmpxx.a */; };
+ 5C0EA13D2C0B176B00AD2E5E /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1382C0B176B00AD2E5E /* libffi.a */; };
+ 5C0EA13E2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA1392C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a */; };
+ 5C0EA13F2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C0EA13A2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a */; };
5C10D88828EED12E00E58BF0 /* ContactConnectionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */; };
5C10D88A28F187F300E58BF0 /* FullScreenMediaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C10D88928F187F300E58BF0 /* FullScreenMediaView.swift */; };
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
@@ -273,11 +273,11 @@
5C029EA9283942EA004A9677 /* CallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallController.swift; sourceTree = ""; };
5C05DF522840AA1D00C683F9 /* CallSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallSettings.swift; sourceTree = ""; };
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatPreviewView.swift; sourceTree = ""; };
- 5C0EA1222C08ADAF00AD2E5E /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; };
- 5C0EA1232C08ADAF00AD2E5E /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; };
- 5C0EA1242C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a"; sourceTree = ""; };
- 5C0EA1252C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a"; sourceTree = ""; };
- 5C0EA1262C08ADAF00AD2E5E /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; };
+ 5C0EA1362C0B176B00AD2E5E /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; };
+ 5C0EA1372C0B176B00AD2E5E /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; };
+ 5C0EA1382C0B176B00AD2E5E /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; };
+ 5C0EA1392C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a"; sourceTree = ""; };
+ 5C0EA13A2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a"; sourceTree = ""; };
5C10D88728EED12E00E58BF0 /* ContactConnectionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionInfo.swift; sourceTree = ""; };
5C10D88928F187F300E58BF0 /* FullScreenMediaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenMediaView.swift; sourceTree = ""; };
5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestView.swift; sourceTree = ""; };
@@ -529,13 +529,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 5C0EA13C2C0B176B00AD2E5E /* libgmpxx.a in Frameworks */,
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
- 5C0EA1272C08ADAF00AD2E5E /* libgmp.a in Frameworks */,
+ 5C0EA13B2C0B176B00AD2E5E /* libgmp.a in Frameworks */,
+ 5C0EA13D2C0B176B00AD2E5E /* libffi.a in Frameworks */,
+ 5C0EA13F2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
- 5C0EA12A2C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a in Frameworks */,
- 5C0EA1292C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a in Frameworks */,
- 5C0EA1282C08ADAF00AD2E5E /* libffi.a in Frameworks */,
- 5C0EA12B2C08ADAF00AD2E5E /* libgmpxx.a in Frameworks */,
+ 5C0EA13E2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -601,11 +601,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
- 5C0EA1232C08ADAF00AD2E5E /* libffi.a */,
- 5C0EA1222C08ADAF00AD2E5E /* libgmp.a */,
- 5C0EA1262C08ADAF00AD2E5E /* libgmpxx.a */,
- 5C0EA1242C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5-ghc9.6.3.a */,
- 5C0EA1252C08ADAF00AD2E5E /* libHSsimplex-chat-5.8.0.4-2QdMx3VWkTS77pHWzbDqa5.a */,
+ 5C0EA1382C0B176B00AD2E5E /* libffi.a */,
+ 5C0EA1362C0B176B00AD2E5E /* libgmp.a */,
+ 5C0EA1372C0B176B00AD2E5E /* libgmpxx.a */,
+ 5C0EA1392C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc-ghc9.6.3.a */,
+ 5C0EA13A2C0B176B00AD2E5E /* libHSsimplex-chat-5.8.0.5-Idqi6HXqzzs2zrnyZtMyhc.a */,
);
path = Libraries;
sourceTree = "";
@@ -1552,7 +1552,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 221;
+ CURRENT_PROJECT_VERSION = 223;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1601,7 +1601,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 221;
+ CURRENT_PROJECT_VERSION = 223;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1687,7 +1687,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 221;
+ CURRENT_PROJECT_VERSION = 223;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
@@ -1724,7 +1724,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 221;
+ CURRENT_PROJECT_VERSION = 223;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
@@ -1761,7 +1761,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 221;
+ CURRENT_PROJECT_VERSION = 223;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -1812,7 +1812,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 221;
+ CURRENT_PROJECT_VERSION = 223;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
diff --git a/apps/multiplatform/gradle.properties b/apps/multiplatform/gradle.properties
index 309369811f..6fa11a1bbc 100644
--- a/apps/multiplatform/gradle.properties
+++ b/apps/multiplatform/gradle.properties
@@ -26,11 +26,11 @@ android.enableJetifier=true
kotlin.mpp.androidSourceSetLayoutVersion=2
kotlin.jvm.target=11
-android.version_name=5.8-beta.4
-android.version_code=215
+android.version_name=5.8-beta.5
+android.version_code=218
-desktop.version_name=5.8-beta.4
-desktop.version_code=50
+desktop.version_name=5.8-beta.5
+desktop.version_code=52
kotlin.version=1.9.23
gradle.plugin.version=8.2.0
From d01515e755a4094deef06b4e2c4295a9cf4f1c40 Mon Sep 17 00:00:00 2001
From: Evgeny Poberezkin
Date: Sat, 1 Jun 2024 21:47:38 +0100
Subject: [PATCH 15/19] blog: Protecting Children's Safety Requires End-to-End
Encryption
---
...children-safety-requires-e2e-encryption.md | 32 ++++++++++++++++++
blog/README.md | 6 ++++
blog/images/20240601-eu-privacy.png | Bin 0 -> 17508 bytes
.../src/_includes/blog_previews/20240601.html | 2 ++
4 files changed, 40 insertions(+)
create mode 100644 blog/20240601-protecting-children-safety-requires-e2e-encryption.md
create mode 100644 blog/images/20240601-eu-privacy.png
create mode 100644 website/src/_includes/blog_previews/20240601.html
diff --git a/blog/20240601-protecting-children-safety-requires-e2e-encryption.md b/blog/20240601-protecting-children-safety-requires-e2e-encryption.md
new file mode 100644
index 0000000000..39a047f93f
--- /dev/null
+++ b/blog/20240601-protecting-children-safety-requires-e2e-encryption.md
@@ -0,0 +1,32 @@
+---
+layout: layouts/article.html
+title: "Protecting Children's Safety Requires End-to-End Encryption"
+date: 2024-06-01
+previewBody: blog_previews/20240601.html
+image: images/20240601-eu-privacy.png
+permalink: "/blog/20240601-protecting-children-safety-requires-e2e-encryption.html"
+---
+
+# Protecting Children's Safety Requires End-to-End Encryption
+
+As lawmakers grapple with the serious issue of child exploitation online, some proposed solutions would fuel the very problem they aim to solve. Despite expert warnings, the Belgian Presidency persists in pushing for the implementation of client-side scanning on encrypted messaging services, rebranding the effort as "upload moderation". Their [latest proposal](https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=COM%3A2022%3A209%3AFIN&qid=1652451192472) mandates that providers of private communication services obtain user consent for AI-based scanning of their private chats. If users do not consent, they will be prohibited from sharing images, videos, and URLs.
+
+Privacy critics have long pushed for measures like centralized scanning of private photos and messaging data, arguing it could detect illicit content. However, invasive monitoring of private communications would create detrimental risks that far outweigh any perceived benefits.
+
+## Why we’re taking action
+
+SimpleX Chat signed a [joint statement](https://www.globalencryption.org/2024/05/joint-statement-on-the-dangers-of-the-may-2024-council-of-the-eu-compromise-proposal-on-eu-csam/) about the dangers of the EU compromise proposal on EU CSAM because maintaining end-to-end encryption is crucial for protecting privacy and security for everyone, including and especially children.
+
+We urge the Ministers in the Council of the EU to stand firm against any scanning proposals that undermine end-to-end encryption, which would enable mass surveillance and misuse by bad actors, whether framed as client-side scanning, upload moderation, or any other terminology. Compromising this basic principle opens the door to devastating privacy violations. We also urge any organizations or individuals reading this to write to their representatives and voice their concerns. European Digital Rights has [outlined these issues](https://edri.org/our-work/be-scanned-or-get-banned/) in greater detail for anyone seeking more information.
+
+## Why compromising privacy endangers children
+
+The core issue is that compromising encryption and privacy makes innocent people vulnerable to malicious hackers and criminals seeking to exploit users data. Centralized scanning systems become a tempting target, potentially exposing millions of private family photos when breached. This would easily open up avenues for blackmail, abuse, and victimization of children. A case in point is the recent [criminal charges](https://techcrunch.com/2024/01/17/unredacted-meta-documents-reveal-historical-reluctance-to-protect-children-new-mexico-lawsuit/) against Meta in New Mexico, which highlights how the tech giant's algorithms enabled child exploitation by encouraging connections between minors and sexual predators. Privacy-eroding initiatives like client-side scanning would play into the hands of malicious actors by making more sensitive information accessible and weaponized in the same way that it has been on Meta platforms.
+
+## What should be done
+
+Rather than undermining privacy, to achieve child safety online users should be empowered with high standards for encryption and data control. For example, adopting a model where children (and users in general) cannot be discovered or approached on networks unless they or their parents permit it, similar to the SimpleX network privacy model. Intelligent multi-device synchronization could enable this oversight without compromising end-to-end encryption overall. It’s always possible to protect children without opening everyone, especially children themselves, to greater vulnerabilities due to such proposals.
+
+However, some recent legislative efforts have bizarrely moved in the opposite direction by seeking to limit parental access. The chilling truth is that the least private platforms have been major enablers of child exploitation. Eroding privacy protections on other services will only aid criminals further, not protect children. Preserving strong encryption and user privacy must be the foundation for any credible effort to combat online child exploitation. Initiatives trading privacy for supposed safety are not just technically flawed, but would achieve the exact opposite of their stated intent. We must avoid being gaslighted by narratives that defy logic, and instead provide users with the highest possible standards for privacy protections as a core principle.
+
+Protecting end-to-end encryption without carving out backdoors or vulnerabilities should be non-negotiable for children's and everyone’s safety. It is critical to redirect the discourse to focus on taking genuine privacy further by protecting against [metadata hoarding](https://simplex.chat/blog/20240416-dangers-of-metadata-in-messengers.html) and other means by which people’s data can be abused or subjected to surveillance.
diff --git a/blog/README.md b/blog/README.md
index a5f3d60b2e..a040833712 100644
--- a/blog/README.md
+++ b/blog/README.md
@@ -1,5 +1,11 @@
# Blog
+Jun 1, 2024 [Children's Safety Requires End-to-End Encryption](./20240601-children-safety-requires-e2e-encryption.md)
+
+As lawmakers grapple with the serious issue of child exploitation online, some proposed solutions would fuel the very problem they aim to solve.
+
+---
+
May 16, 2024 [SimpleX: Redefining Privacy by Making Hard Choices](./20240516-simplex-redefining-privacy-hard-choices.md)
When it comes to open source privacy tools, the status quo often dictates the limitations of existing protocols and structures. However, these norms need to be challenged to radically shift how we approach genuinely private communication. This requires doing some uncomfortable things, like making hard choices as it relates to funding, alternative decentralization models, doubling down on privacy over convenience, and more.
diff --git a/blog/images/20240601-eu-privacy.png b/blog/images/20240601-eu-privacy.png
new file mode 100644
index 0000000000000000000000000000000000000000..4ae1a17e30ba5b43e0fc6f39a84d23ac4b5737b6
GIT binary patch
literal 17508
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
C?4OAs lawmakers grapple with the serious issue of child exploitation online,
+ some proposed solutions would fuel the very problem they aim to solve.
\ No newline at end of file
From 4ad0e0f65e8285c69ca0ea1ff9c964c7e398a2d7 Mon Sep 17 00:00:00 2001
From: Evgeny Poberezkin
Date: Sun, 2 Jun 2024 19:20:46 +0100
Subject: [PATCH 16/19] ui: translations (#4273)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Translated using Weblate (Italian)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/
* Translated using Weblate (Italian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/
* Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/
* Translated using Weblate (Dutch)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/
* Translated using Weblate (Dutch)
Currently translated at 99.8% (1547 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/
* Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/
* Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/uk/
* Translated using Weblate (Turkish)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/
* Translated using Weblate (Turkish)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
* Translated using Weblate (Turkish)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/
* Translated using Weblate (Turkish)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/
* Translated using Weblate (Turkish)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
* Translated using Weblate (German)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/
* Translated using Weblate (German)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
* Translated using Weblate (French)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/
* Translated using Weblate (French)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
* Translated using Weblate (French)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/
* Translated using Weblate (Spanish)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/
* Translated using Weblate (Spanish)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/
* Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/
* Translated using Weblate (Persian)
Currently translated at 99.9% (1822 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/
* Translated using Weblate (Italian)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/
* Translated using Weblate (Italian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/it/
* Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/
* Translated using Weblate (Dutch)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/
* Translated using Weblate (Dutch)
Currently translated at 99.8% (1547 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/
* Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/uk/
* Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/uk/
* Translated using Weblate (Turkish)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/
* Translated using Weblate (Turkish)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
* Translated using Weblate (Turkish)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/
* Translated using Weblate (Turkish)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/tr/
* Translated using Weblate (Turkish)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/tr/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
* Translated using Weblate (German)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/
* Translated using Weblate (German)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1819 of 1819 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
* Translated using Weblate (French)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fr/
* Translated using Weblate (French)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
* Translated using Weblate (French)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/fr/
* Translated using Weblate (Spanish)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/
* Translated using Weblate (Spanish)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/
* Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/zh_Hans/
* Translated using Weblate (Persian)
Currently translated at 99.9% (1822 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/
* Translated using Weblate (Italian)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/it/
* Translated using Weblate (Romanian)
Currently translated at 13.0% (237 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ro/
* Translated using Weblate (German)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/
* Translated using Weblate (German)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/
* Translated using Weblate (Spanish)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/es/
* Translated using Weblate (Spanish)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/es/
* Translated using Weblate (Dutch)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/nl/
* Translated using Weblate (Dutch)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/nl/
* Translated using Weblate (Polish)
Currently translated at 99.9% (1822 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/pl/
* Translated using Weblate (Polish)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/pl/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/hu/
* Translated using Weblate (Persian)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/fa/
* Translated using Weblate (Romanian)
Currently translated at 17.6% (322 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ro/
* Translated using Weblate (Hungarian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/hu/
* Translated using Weblate (German)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/
* Translated using Weblate (Japanese)
Currently translated at 96.9% (1767 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ja/
* Translated using Weblate (Arabic)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ar/
* Translated using Weblate (German)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/de/
* Translated using Weblate (Russian)
Currently translated at 100.0% (1823 of 1823 strings)
Translation: SimpleX Chat/SimpleX Chat Android
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/android/ru/
* Translated using Weblate (German)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/de/
* Translated using Weblate (Russian)
Currently translated at 100.0% (1549 of 1549 strings)
Translation: SimpleX Chat/SimpleX Chat iOS
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/ios/ru/
* import/export localizations
---------
Co-authored-by: Random
Co-authored-by: 大王叫我来巡山
Co-authored-by: M1K4
Co-authored-by: Maksym Lukashenko
Co-authored-by: z0rden
Co-authored-by: summoner001
Co-authored-by: J R
Co-authored-by: mlanp
Co-authored-by: Ophiushi <41908476+ishi-sama@users.noreply.github.com>
Co-authored-by: Ghost of Sparta
Co-authored-by: khalidbelk
Co-authored-by: Siavash
Co-authored-by: Flavian <3zorro.1@gmail.com>
Co-authored-by: No name
Co-authored-by: B.O.S.S
Co-authored-by: Ninja Left
Co-authored-by: Miyu Sakatsuki
Co-authored-by: jonnysemon
---
.../bg.xcloc/Localized Contents/bg.xliff | 14 ++
.../cs.xcloc/Localized Contents/cs.xliff | 14 ++
.../de.xcloc/Localized Contents/de.xliff | 62 ++++-
.../en.xcloc/Localized Contents/en.xliff | 19 ++
.../es.xcloc/Localized Contents/es.xliff | 58 ++++-
.../fi.xcloc/Localized Contents/fi.xliff | 14 ++
.../fr.xcloc/Localized Contents/fr.xliff | 54 +++++
.../hu.xcloc/Localized Contents/hu.xliff | 80 ++++++-
.../it.xcloc/Localized Contents/it.xliff | 54 +++++
.../ja.xcloc/Localized Contents/ja.xliff | 14 ++
.../nl.xcloc/Localized Contents/nl.xliff | 54 +++++
.../pl.xcloc/Localized Contents/pl.xliff | 54 +++++
.../ru.xcloc/Localized Contents/ru.xliff | 54 +++++
.../th.xcloc/Localized Contents/th.xliff | 14 ++
.../tr.xcloc/Localized Contents/tr.xliff | 66 ++++-
.../uk.xcloc/Localized Contents/uk.xliff | 92 +++++++
.../Localized Contents/zh-Hans.xliff | 14 ++
.../SimpleX NSE/de.lproj/InfoPlist.strings | 2 +-
apps/ios/de.lproj/Localizable.strings | 117 ++++++++-
apps/ios/es.lproj/Localizable.strings | 115 ++++++++-
apps/ios/fr.lproj/Localizable.strings | 111 +++++++++
apps/ios/hu.lproj/Localizable.strings | 137 ++++++++++-
apps/ios/it.lproj/Localizable.strings | 111 +++++++++
apps/ios/nl.lproj/Localizable.strings | 111 +++++++++
apps/ios/pl.lproj/Localizable.strings | 111 +++++++++
apps/ios/ru.lproj/Localizable.strings | 111 +++++++++
apps/ios/tr.lproj/Localizable.strings | 123 +++++++++-
apps/ios/uk.lproj/Localizable.strings | 225 ++++++++++++++++++
.../commonMain/resources/MR/ar/strings.xml | 21 ++
.../commonMain/resources/MR/de/strings.xml | 47 +++-
.../commonMain/resources/MR/es/strings.xml | 37 ++-
.../commonMain/resources/MR/fa/strings.xml | 52 +++-
.../commonMain/resources/MR/fr/strings.xml | 52 +++-
.../commonMain/resources/MR/hu/strings.xml | 36 ++-
.../commonMain/resources/MR/it/strings.xml | 21 ++
.../commonMain/resources/MR/ja/strings.xml | 18 ++
.../commonMain/resources/MR/nl/strings.xml | 52 +++-
.../commonMain/resources/MR/pl/strings.xml | 21 ++
.../commonMain/resources/MR/ro/strings.xml | 149 ++++++++++++
.../commonMain/resources/MR/ru/strings.xml | 93 +++++++-
.../commonMain/resources/MR/tr/strings.xml | 39 ++-
.../commonMain/resources/MR/uk/strings.xml | 61 +++++
.../resources/MR/zh-rCN/strings.xml | 21 ++
43 files changed, 2630 insertions(+), 95 deletions(-)
diff --git a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff
index 28abc7221a..673d6668f9 100644
--- a/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff
+++ b/apps/ios/SimpleX Localizations/bg.xcloc/Localized Contents/bg.xliff
@@ -1717,6 +1717,10 @@ This is your own one-time link!
Базата данни ще бъде мигрирана, когато приложението се рестартира
No comment provided by engineer.
+
+ Debug delivery
+ No comment provided by engineer.
+
Decentralized
Децентрализиран
@@ -3684,6 +3688,10 @@ This is your link for group %@!
Чернова на съобщение
No comment provided by engineer.
+
+ Message queue info
+ No comment provided by engineer.
+
Message reactions
Реакции на съобщения
@@ -7539,6 +7547,12 @@ SimpleX сървърите не могат да видят вашия профи
изпрати лично съобщение
No comment provided by engineer.
+
+ server queue info: %1$@
+
+last received msg: %2$@
+ queue info
+
set new contact address
зададен нов адрес за контакт
diff --git a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff
index 41e770b180..24c71a3487 100644
--- a/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff
+++ b/apps/ios/SimpleX Localizations/cs.xcloc/Localized Contents/cs.xliff
@@ -1647,6 +1647,10 @@ This is your own one-time link!
Databáze bude přenesena po restartu aplikace
No comment provided by engineer.
+
+ Debug delivery
+ No comment provided by engineer.
+
Decentralized
Decentralizované
@@ -3541,6 +3545,10 @@ This is your link for group %@!
Návrh zprávy
No comment provided by engineer.
+
+ Message queue info
+ No comment provided by engineer.
+
Message reactions
Reakce na zprávy
@@ -7247,6 +7255,12 @@ Servery SimpleX nevidí váš profil.
odeslat přímou zprávu
No comment provided by engineer.
+
+ server queue info: %1$@
+
+last received msg: %2$@
+ queue info
+
set new contact address
profile update event chat item
diff --git a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff
index 5c3c74ba77..4889950d33 100644
--- a/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff
+++ b/apps/ios/SimpleX Localizations/de.xcloc/Localized Contents/de.xliff
@@ -715,6 +715,7 @@
Allow downgrade
+ Herabstufung erlauben
No comment provided by engineer.
@@ -814,6 +815,7 @@
Always use private routing.
+ Sie nutzen immer privates Routing.
No comment provided by engineer.
@@ -1098,6 +1100,7 @@
Capacity exceeded - recipient did not receive previously sent messages.
+ Kapazität überschritten - der Empfänger hat die zuvor gesendeten Nachrichten nicht empfangen.
snd error text
@@ -1298,6 +1301,7 @@
Confirm files from unknown servers.
+ Dateien von unbekannten Servern bestätigen.
No comment provided by engineer.
@@ -1717,6 +1721,10 @@ Das ist Ihr eigener Einmal-Link!
Die Datenbank wird beim nächsten Start der App migriert
No comment provided by engineer.
+
+ Debug delivery
+ No comment provided by engineer.
+
Decentralized
Dezentral
@@ -1966,6 +1974,7 @@ Das kann nicht rückgängig gemacht werden!
Destination server error: %@
+ Zielserver-Fehler: %@
snd error text
@@ -2075,15 +2084,17 @@ Das kann nicht rückgängig gemacht werden!
Do NOT send messages directly, even if your or destination server does not support private routing.
+ Nachrichten werden nicht direkt versendet, selbst wenn Ihr oder der Zielserver kein privates Routing unterstützt.
No comment provided by engineer.
Do NOT use SimpleX for emergency calls.
- Nutzen Sie SimpleX nicht für Notrufe.
+ SimpleX NICHT für Notrufe nutzen.
No comment provided by engineer.
Do NOT use private routing.
+ Sie nutzen KEIN privates Routing.
No comment provided by engineer.
@@ -2743,6 +2754,7 @@ Das kann nicht rückgängig gemacht werden!
Files
+ Dateien
No comment provided by engineer.
@@ -2853,11 +2865,15 @@ Das kann nicht rückgängig gemacht werden!
Forwarding server: %1$@
Destination server error: %2$@
+ Weiterleitungsserver: %1$@
+Zielserver Fehler: %2$@
snd error text
Forwarding server: %1$@
Error: %2$@
+ Weiterleitungsserver: %1$@
+Fehler: %2$@
snd error text
@@ -3677,6 +3693,7 @@ Das ist Ihr Link für die Gruppe %@!
Message delivery warning
+ Warnung bei der Nachrichtenzustellung
item status text
@@ -3684,6 +3701,10 @@ Das ist Ihr Link für die Gruppe %@!
Nachrichtenentwurf
No comment provided by engineer.
+
+ Message queue info
+ No comment provided by engineer.
+
Message reactions
Reaktionen auf Nachrichten
@@ -3701,10 +3722,12 @@ Das ist Ihr Link für die Gruppe %@!
Message routing fallback
+ Fallback für das Nachrichten-Routing
No comment provided by engineer.
Message routing mode
+ Modus für das Nachrichten-Routing
No comment provided by engineer.
@@ -3869,6 +3892,7 @@ Das ist Ihr Link für die Gruppe %@!
Network issues - message expired after many attempts to send it.
+ Netzwerk-Fehler - die Nachricht ist nach vielen Sende-Versuchen abgelaufen.
snd error text
@@ -4414,10 +4438,12 @@ Fehler: %@
Private message routing
+ Privates Nachrichten-Routing
No comment provided by engineer.
Private message routing 🚀
+ Privates Nachrichten-Routing 🚀
No comment provided by engineer.
@@ -4427,6 +4453,7 @@ Fehler: %@
Private routing
+ Privates Routing
No comment provided by engineer.
@@ -4511,6 +4538,7 @@ Fehler: %@
Protect IP address
+ IP-Adresse schützen
No comment provided by engineer.
@@ -4521,6 +4549,8 @@ Fehler: %@
Protect your IP address from the messaging relays chosen by your contacts.
Enable in *Network & servers* settings.
+ Schützen Sie Ihre IP-Adresse vor den Nachrichten-Relais , die Ihre Kontakte ausgewählt haben.
+Aktivieren Sie es in den *Netzwerk & Server* Einstellungen.
No comment provided by engineer.
@@ -4865,6 +4895,7 @@ Enable in *Network & servers* settings.
Safely receive files
+ Dateien sicher empfangen
No comment provided by engineer.
@@ -5094,10 +5125,12 @@ Enable in *Network & servers* settings.
Send messages directly when IP address is protected and your or destination server does not support private routing.
+ Nachrichten werden direkt versendet, wenn die IP-Adresse geschützt ist, und Ihr oder der Zielserver kein privates Routing unterstützt.
No comment provided by engineer.
Send messages directly when your or destination server does not support private routing.
+ Nachrichten werden direkt versendet, wenn Ihr oder der Zielserver kein privates Routing unterstützt.
No comment provided by engineer.
@@ -5207,6 +5240,7 @@ Enable in *Network & servers* settings.
Server address is incompatible with network settings.
+ Die Server-Adresse ist nicht mit den Netzwerk-Einstellungen kompatibel.
srv error text.
@@ -5226,6 +5260,7 @@ Enable in *Network & servers* settings.
Server version is incompatible with network settings.
+ Die Server-Version ist nicht mit den Netzwerk-Einstellungen kompatibel.
srv error text
@@ -5350,6 +5385,7 @@ Enable in *Network & servers* settings.
Show message status
+ Nachrichtenstatus anzeigen
No comment provided by engineer.
@@ -5359,6 +5395,7 @@ Enable in *Network & servers* settings.
Show → on messages sent via private routing.
+ Bei Nachrichten, die über privates Routing versendet wurden, → anzeigen.
No comment provided by engineer.
@@ -5685,6 +5722,7 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro
The app will ask to confirm downloads from unknown file servers (except .onion).
+ Die App wird eine Bestätigung bei Downloads von unbekannten Datei-Servern anfordern (außer bei .onion).
No comment provided by engineer.
@@ -5874,6 +5912,7 @@ Dies kann passieren, wenn es einen Fehler gegeben hat oder die Verbindung kompro
To protect your IP address, private routing uses your SMP servers to deliver messages.
+ Zum Schutz Ihrer IP-Adresse, wird für die Nachrichten-Auslieferung privates Routing über Ihre konfigurierten SMP-Server genutzt.
No comment provided by engineer.
@@ -6015,6 +6054,7 @@ Sie werden aufgefordert, die Authentifizierung abzuschließen, bevor diese Funkt
Unknown servers!
+ Unbekannte Server!
No comment provided by engineer.
@@ -6136,7 +6176,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
Use current profile
- Das aktuelle Profil nutzen
+ Aktuelles Profil nutzen
No comment provided by engineer.
@@ -6156,7 +6196,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
Use new incognito profile
- Ein neues Inkognito-Profil nutzen
+ Neues Inkognito-Profil nutzen
No comment provided by engineer.
@@ -6166,10 +6206,12 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
Use private routing with unknown servers when IP address is not protected.
+ Sie nutzen privates Routing mit unbekannten Servern, wenn Ihre IP-Adresse nicht geschützt ist.
No comment provided by engineer.
Use private routing with unknown servers.
+ Sie nutzen privates Routing mit unbekannten Servern.
No comment provided by engineer.
@@ -6409,10 +6451,12 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
Without Tor or VPN, your IP address will be visible to file servers.
+ Ohne Tor- oder VPN-Nutzung wird Ihre IP-Adresse für Datei-Server sichtbar sein.
No comment provided by engineer.
Without Tor or VPN, your IP address will be visible to these XFTP relays: %@.
+ Ohne Tor- oder VPN-Nutzung wird Ihre IP-Adresse für diese XFTP-Relais sichtbar sein: %@.
No comment provided by engineer.
@@ -6422,6 +6466,7 @@ Bitten Sie Ihren Kontakt darum einen weiteren Verbindungs-Link zu erzeugen, um s
Wrong key or unknown connection - most likely this connection is deleted.
+ Falscher Schlüssel oder unbekannte Verbindung - höchstwahrscheinlich ist diese Verbindung gelöscht worden.
snd error text
@@ -7539,6 +7584,12 @@ SimpleX-Server können Ihr Profil nicht einsehen.
Direktnachricht senden
No comment provided by engineer.
+
+ server queue info: %1$@
+
+last received msg: %2$@
+ queue info
+
set new contact address
Es wurde eine neue Kontaktadresse festgelegt
@@ -7581,6 +7632,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.
unknown relays
+ Unbekannte Relais
No comment provided by engineer.
@@ -7590,6 +7642,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.
unprotected
+ Ungeschützt
No comment provided by engineer.
@@ -7659,6 +7712,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.
when IP hidden
+ Wenn die IP-Adresse versteckt ist
No comment provided by engineer.
@@ -7797,7 +7851,7 @@ SimpleX-Server können Ihr Profil nicht einsehen.
Copyright © 2022 SimpleX Chat. All rights reserved.
- Copyright © 2022 SimpleX Chat. All rights reserved.
+ Copyright © 2024 SimpleX Chat. All rights reserved.
Copyright (human-readable)