mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-03-30 20:45:49 +00:00
multiplatform: SMP proxy support (#4179)
* android: SMP proxy support * android types * show in meta * reserve * remove comment * texts
This commit is contained in:
@@ -1900,6 +1900,7 @@ data class ChatItem (
|
||||
ts: Instant = Clock.System.now(),
|
||||
text: String = "hello\nthere",
|
||||
status: CIStatus = CIStatus.SndNew(),
|
||||
sentViaProxy: Boolean? = null,
|
||||
quotedItem: CIQuote? = null,
|
||||
file: CIFile? = null,
|
||||
itemForwarded: CIForwardedFrom? = null,
|
||||
@@ -1911,7 +1912,7 @@ data class ChatItem (
|
||||
) =
|
||||
ChatItem(
|
||||
chatDir = dir,
|
||||
meta = CIMeta.getSample(id, ts, text, status, itemForwarded, itemDeleted, itemEdited, itemTimed, deletable, editable),
|
||||
meta = CIMeta.getSample(id, ts, text, status, sentViaProxy, itemForwarded, itemDeleted, itemEdited, itemTimed, deletable, editable),
|
||||
content = CIContent.SndMsgContent(msgContent = MsgContent.MCText(text)),
|
||||
quotedItem = quotedItem,
|
||||
reactions = listOf(),
|
||||
@@ -1993,6 +1994,7 @@ data class ChatItem (
|
||||
itemTs = Clock.System.now(),
|
||||
itemText = generalGetString(MR.strings.deleted_description),
|
||||
itemStatus = CIStatus.RcvRead(),
|
||||
sentViaProxy = null,
|
||||
createdAt = Clock.System.now(),
|
||||
updatedAt = Clock.System.now(),
|
||||
itemForwarded = null,
|
||||
@@ -2016,6 +2018,7 @@ data class ChatItem (
|
||||
itemTs = Clock.System.now(),
|
||||
itemText = "",
|
||||
itemStatus = CIStatus.RcvRead(),
|
||||
sentViaProxy = null,
|
||||
createdAt = Clock.System.now(),
|
||||
updatedAt = Clock.System.now(),
|
||||
itemForwarded = null,
|
||||
@@ -2118,6 +2121,7 @@ data class CIMeta (
|
||||
val itemTs: Instant,
|
||||
val itemText: String,
|
||||
val itemStatus: CIStatus,
|
||||
val sentViaProxy: Boolean?,
|
||||
val createdAt: Instant,
|
||||
val updatedAt: Instant,
|
||||
val itemForwarded: CIForwardedFrom?,
|
||||
@@ -2144,7 +2148,7 @@ data class CIMeta (
|
||||
|
||||
companion object {
|
||||
fun getSample(
|
||||
id: Long, ts: Instant, text: String, status: CIStatus = CIStatus.SndNew(),
|
||||
id: Long, ts: Instant, text: String, status: CIStatus = CIStatus.SndNew(), sentViaProxy: Boolean? = null,
|
||||
itemForwarded: CIForwardedFrom? = null, itemDeleted: CIDeleted? = null, itemEdited: Boolean = false,
|
||||
itemTimed: CITimed? = null, itemLive: Boolean = false, deletable: Boolean = true, editable: Boolean = true
|
||||
): CIMeta =
|
||||
@@ -2153,6 +2157,7 @@ data class CIMeta (
|
||||
itemTs = ts,
|
||||
itemText = text,
|
||||
itemStatus = status,
|
||||
sentViaProxy = sentViaProxy,
|
||||
createdAt = ts,
|
||||
updatedAt = ts,
|
||||
itemForwarded = itemForwarded,
|
||||
@@ -2171,6 +2176,7 @@ data class CIMeta (
|
||||
itemTs = Clock.System.now(),
|
||||
itemText = "invalid JSON",
|
||||
itemStatus = CIStatus.SndNew(),
|
||||
sentViaProxy = null,
|
||||
createdAt = Clock.System.now(),
|
||||
updatedAt = Clock.System.now(),
|
||||
itemForwarded = null,
|
||||
@@ -2227,7 +2233,8 @@ sealed class CIStatus {
|
||||
@Serializable @SerialName("sndSent") class SndSent(val sndProgress: SndCIStatusProgress): CIStatus()
|
||||
@Serializable @SerialName("sndRcvd") class SndRcvd(val msgRcptStatus: MsgReceiptStatus, val sndProgress: SndCIStatusProgress): CIStatus()
|
||||
@Serializable @SerialName("sndErrorAuth") class SndErrorAuth: CIStatus()
|
||||
@Serializable @SerialName("sndError") class SndError(val agentError: String): CIStatus()
|
||||
@Serializable @SerialName("sndError") class CISSndError(val agentError: SndError): CIStatus()
|
||||
@Serializable @SerialName("sndWarning") class SndWarning(val agentError: SndError): CIStatus()
|
||||
@Serializable @SerialName("rcvNew") class RcvNew: CIStatus()
|
||||
@Serializable @SerialName("rcvRead") class RcvRead: CIStatus()
|
||||
@Serializable @SerialName("invalid") class Invalid(val text: String): CIStatus()
|
||||
@@ -2251,7 +2258,8 @@ sealed class CIStatus {
|
||||
MsgReceiptStatus.BadMsgHash -> MR.images.ic_double_check to Color.Red
|
||||
}
|
||||
is SndErrorAuth -> MR.images.ic_close to Color.Red
|
||||
is SndError -> MR.images.ic_warning_filled to WarningYellow
|
||||
is CISSndError -> MR.images.ic_close to Color.Red
|
||||
is SndWarning -> MR.images.ic_warning_filled to WarningOrange
|
||||
is RcvNew -> MR.images.ic_circle_filled to primaryColor
|
||||
is RcvRead -> null
|
||||
is CIStatus.Invalid -> MR.images.ic_question_mark to metaColor
|
||||
@@ -2262,13 +2270,48 @@ sealed class CIStatus {
|
||||
is SndSent -> null
|
||||
is SndRcvd -> null
|
||||
is SndErrorAuth -> generalGetString(MR.strings.message_delivery_error_title) to generalGetString(MR.strings.message_delivery_error_desc)
|
||||
is SndError -> generalGetString(MR.strings.message_delivery_error_title) to (generalGetString(MR.strings.unknown_error) + ": $agentError")
|
||||
is CISSndError -> generalGetString(MR.strings.message_delivery_error_title) to agentError.errorInfo
|
||||
is SndWarning -> generalGetString(MR.strings.message_delivery_warning_title) to agentError.errorInfo
|
||||
is RcvNew -> null
|
||||
is RcvRead -> null
|
||||
is Invalid -> "Invalid status" to this.text
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
sealed class SndError {
|
||||
@Serializable @SerialName("auth") class Auth: SndError()
|
||||
@Serializable @SerialName("quota") class Quota: SndError()
|
||||
@Serializable @SerialName("expired") class Expired: SndError()
|
||||
@Serializable @SerialName("relay") class Relay(val srvError: SrvError): SndError()
|
||||
@Serializable @SerialName("proxy") class Proxy(val proxyServer: String, val srvError: SrvError): SndError()
|
||||
@Serializable @SerialName("proxyRelay") class ProxyRelay(val proxyServer: String, val srvError: SrvError): SndError()
|
||||
@Serializable @SerialName("other") class Other(val sndError: String): SndError()
|
||||
|
||||
val errorInfo: String get() = when (this) {
|
||||
is SndError.Auth -> generalGetString(MR.strings.snd_error_auth)
|
||||
is SndError.Quota -> generalGetString(MR.strings.snd_error_quota)
|
||||
is SndError.Expired -> generalGetString(MR.strings.snd_error_expired)
|
||||
is SndError.Relay -> generalGetString(MR.strings.snd_error_relay).format(srvError.errorInfo)
|
||||
is SndError.Proxy -> generalGetString(MR.strings.snd_error_proxy).format(proxyServer, srvError.errorInfo)
|
||||
is SndError.ProxyRelay -> generalGetString(MR.strings.snd_error_proxy_relay).format(proxyServer, srvError.errorInfo)
|
||||
is SndError.Other -> generalGetString(MR.strings.ci_status_other_error).format(sndError)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
sealed class SrvError {
|
||||
@Serializable @SerialName("host") class Host: SrvError()
|
||||
@Serializable @SerialName("version") class Version: SrvError()
|
||||
@Serializable @SerialName("other") class Other(val srvError: String): SrvError()
|
||||
|
||||
val errorInfo: String get() = when (this) {
|
||||
is SrvError.Host -> generalGetString(MR.strings.srv_error_host)
|
||||
is SrvError.Version -> generalGetString(MR.strings.srv_error_version)
|
||||
is SrvError.Other -> srvError
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class MsgReceiptStatus {
|
||||
@SerialName("ok") Ok,
|
||||
@@ -3354,7 +3397,8 @@ data class ChatItemVersion(
|
||||
@Serializable
|
||||
data class MemberDeliveryStatus(
|
||||
val groupMemberId: Long,
|
||||
val memberDeliveryStatus: CIStatus
|
||||
val memberDeliveryStatus: CIStatus,
|
||||
val sentViaProxy: Boolean?
|
||||
)
|
||||
|
||||
enum class NotificationPreviewMode {
|
||||
|
||||
@@ -130,6 +130,8 @@ class AppPreferences {
|
||||
},
|
||||
set = fun(mode: TransportSessionMode) { _networkSessionMode.set(mode.name) }
|
||||
)
|
||||
val networkSMPProxyMode = mkStrPreference(SHARED_PREFS_NETWORK_SMP_PROXY_MODE, SMPProxyMode.Never.name)
|
||||
val networkSMPProxyFallback = mkStrPreference(SHARED_PREFS_NETWORK_SMP_PROXY_FALLBACK, SMPProxyFallback.Allow.name)
|
||||
val networkHostMode = mkStrPreference(SHARED_PREFS_NETWORK_HOST_MODE, HostMode.OnionViaSocks.name)
|
||||
val networkRequiredHostMode = mkBoolPreference(SHARED_PREFS_NETWORK_REQUIRED_HOST_MODE, false)
|
||||
val networkTCPConnectTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT, NetCfg.defaults.tcpConnectTimeout, NetCfg.proxyDefaults.tcpConnectTimeout)
|
||||
@@ -185,6 +187,8 @@ class AppPreferences {
|
||||
|
||||
val desktopWindowState = mkStrPreference(SHARED_PREFS_DESKTOP_WINDOW_STATE, null)
|
||||
|
||||
val showSentViaProxy = mkBoolPreference(SHARED_PREFS_SHOW_SENT_VIA_RPOXY, false)
|
||||
|
||||
|
||||
val iosCallKitEnabled = mkBoolPreference(SHARED_PREFS_IOS_CALL_KIT_ENABLED, true)
|
||||
val iosCallKitCallsInRecents = mkBoolPreference(SHARED_PREFS_IOS_CALL_KIT_CALLS_IN_RECENTS, false)
|
||||
@@ -306,6 +310,8 @@ class AppPreferences {
|
||||
private const val SHARED_PREFS_NETWORK_USE_SOCKS_PROXY = "NetworkUseSocksProxy"
|
||||
private const val SHARED_PREFS_NETWORK_PROXY_HOST_PORT = "NetworkProxyHostPort"
|
||||
private const val SHARED_PREFS_NETWORK_SESSION_MODE = "NetworkSessionMode"
|
||||
private const val SHARED_PREFS_NETWORK_SMP_PROXY_MODE = "NetworkSMPProxyMode"
|
||||
private const val SHARED_PREFS_NETWORK_SMP_PROXY_FALLBACK = "NetworkSMPProxyFallback"
|
||||
private const val SHARED_PREFS_NETWORK_HOST_MODE = "NetworkHostMode"
|
||||
private const val SHARED_PREFS_NETWORK_REQUIRED_HOST_MODE = "NetworkRequiredHostMode"
|
||||
private const val SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT = "NetworkTCPConnectTimeout"
|
||||
@@ -348,6 +354,7 @@ class AppPreferences {
|
||||
private const val SHARED_PREFS_CONNECT_REMOTE_VIA_MULTICAST_AUTO = "ConnectRemoteViaMulticastAuto"
|
||||
private const val SHARED_PREFS_OFFER_REMOTE_MULTICAST = "OfferRemoteMulticast"
|
||||
private const val SHARED_PREFS_DESKTOP_WINDOW_STATE = "DesktopWindowState"
|
||||
private const val SHARED_PREFS_SHOW_SENT_VIA_RPOXY = "showSentViaProxy"
|
||||
|
||||
private const val SHARED_PREFS_IOS_CALL_KIT_ENABLED = "iOSCallKitEnabled"
|
||||
private const val SHARED_PREFS_IOS_CALL_KIT_CALLS_IN_RECENTS = "iOSCallKitCallsInRecents"
|
||||
@@ -2310,6 +2317,8 @@ object ChatController {
|
||||
val hostMode = HostMode.valueOf(appPrefs.networkHostMode.get()!!)
|
||||
val requiredHostMode = appPrefs.networkRequiredHostMode.get()
|
||||
val sessionMode = appPrefs.networkSessionMode.get()
|
||||
val smpProxyMode = SMPProxyMode.valueOf(appPrefs.networkSMPProxyMode.get()!!)
|
||||
val smpProxyFallback = SMPProxyFallback.valueOf(appPrefs.networkSMPProxyFallback.get()!!)
|
||||
val tcpConnectTimeout = appPrefs.networkTCPConnectTimeout.get()
|
||||
val tcpTimeout = appPrefs.networkTCPTimeout.get()
|
||||
val tcpTimeoutPerKb = appPrefs.networkTCPTimeoutPerKb.get()
|
||||
@@ -2330,6 +2339,8 @@ object ChatController {
|
||||
hostMode = hostMode,
|
||||
requiredHostMode = requiredHostMode,
|
||||
sessionMode = sessionMode,
|
||||
smpProxyMode = smpProxyMode,
|
||||
smpProxyFallback = smpProxyFallback,
|
||||
tcpConnectTimeout = tcpConnectTimeout,
|
||||
tcpTimeout = tcpTimeout,
|
||||
tcpTimeoutPerKb = tcpTimeoutPerKb,
|
||||
@@ -2348,6 +2359,8 @@ object ChatController {
|
||||
appPrefs.networkHostMode.set(cfg.hostMode.name)
|
||||
appPrefs.networkRequiredHostMode.set(cfg.requiredHostMode)
|
||||
appPrefs.networkSessionMode.set(cfg.sessionMode)
|
||||
appPrefs.networkSMPProxyMode.set(cfg.smpProxyMode.name)
|
||||
appPrefs.networkSMPProxyFallback.set(cfg.smpProxyFallback.name)
|
||||
appPrefs.networkTCPConnectTimeout.set(cfg.tcpConnectTimeout)
|
||||
appPrefs.networkTCPTimeout.set(cfg.tcpTimeout)
|
||||
appPrefs.networkTCPTimeoutPerKb.set(cfg.tcpTimeoutPerKb)
|
||||
@@ -3033,9 +3046,12 @@ data class ParsedServerAddress (
|
||||
@Serializable
|
||||
data class NetCfg(
|
||||
val socksProxy: String?,
|
||||
val socksMode: SocksMode = SocksMode.Always,
|
||||
val hostMode: HostMode,
|
||||
val requiredHostMode: Boolean,
|
||||
val sessionMode: TransportSessionMode,
|
||||
val smpProxyMode: SMPProxyMode,
|
||||
val smpProxyFallback: SMPProxyFallback,
|
||||
val tcpConnectTimeout: Long, // microseconds
|
||||
val tcpTimeout: Long, // microseconds
|
||||
val tcpTimeoutPerKb: Long, // microseconds
|
||||
@@ -3064,6 +3080,8 @@ data class NetCfg(
|
||||
hostMode = HostMode.OnionViaSocks,
|
||||
requiredHostMode = false,
|
||||
sessionMode = TransportSessionMode.User,
|
||||
smpProxyMode = SMPProxyMode.Never,
|
||||
smpProxyFallback = SMPProxyFallback.Allow,
|
||||
tcpConnectTimeout = 25_000_000,
|
||||
tcpTimeout = 15_000_000,
|
||||
tcpTimeoutPerKb = 10_000,
|
||||
@@ -3079,6 +3097,8 @@ data class NetCfg(
|
||||
hostMode = HostMode.OnionViaSocks,
|
||||
requiredHostMode = false,
|
||||
sessionMode = TransportSessionMode.User,
|
||||
smpProxyMode = SMPProxyMode.Never,
|
||||
smpProxyFallback = SMPProxyFallback.Allow,
|
||||
tcpConnectTimeout = 35_000_000,
|
||||
tcpTimeout = 20_000_000,
|
||||
tcpTimeoutPerKb = 15_000,
|
||||
@@ -3117,6 +3137,35 @@ enum class HostMode {
|
||||
@SerialName("public") Public;
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class SocksMode {
|
||||
@SerialName("always") Always,
|
||||
@SerialName("onion") Onion;
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class SMPProxyMode {
|
||||
@SerialName("always") Always,
|
||||
@SerialName("unknown") Unknown,
|
||||
@SerialName("unprotected") Unprotected,
|
||||
@SerialName("never") Never;
|
||||
|
||||
companion object {
|
||||
val default = Never
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class SMPProxyFallback {
|
||||
@SerialName("allow") Allow,
|
||||
@SerialName("allowProtected") AllowProtected,
|
||||
@SerialName("prohibit") Prohibit;
|
||||
|
||||
companion object {
|
||||
val default = Allow
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
enum class TransportSessionMode {
|
||||
@SerialName("user") User,
|
||||
|
||||
@@ -304,7 +304,7 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MemberDeliveryStatusView(member: GroupMember, status: CIStatus) {
|
||||
fun MemberDeliveryStatusView(member: GroupMember, status: CIStatus, sentViaProxy: Boolean?) {
|
||||
SectionItemView(
|
||||
padding = PaddingValues(horizontal = 0.dp)
|
||||
) {
|
||||
@@ -317,6 +317,18 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Spacer(Modifier.fillMaxWidth().weight(1f))
|
||||
if (sentViaProxy == true) {
|
||||
Box(
|
||||
Modifier.size(36.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Icon(
|
||||
painterResource(MR.images.ic_arrow_forward),
|
||||
contentDescription = null,
|
||||
tint = CurrentColors.value.colors.secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
val statusIcon = status.statusIcon(MaterialTheme.colors.primary, CurrentColors.value.colors.secondary)
|
||||
var modifier = Modifier.size(36.dp).clip(RoundedCornerShape(20.dp))
|
||||
val info = status.statusInto
|
||||
@@ -357,8 +369,8 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
|
||||
if (mss.isNotEmpty()) {
|
||||
SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
|
||||
Text(stringResource(MR.strings.delivery), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = DEFAULT_PADDING))
|
||||
mss.forEach { (member, status) ->
|
||||
MemberDeliveryStatusView(member, status)
|
||||
mss.forEach { (member, status, sentViaProxy) ->
|
||||
MemberDeliveryStatusView(member, status, sentViaProxy)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -482,10 +494,10 @@ fun ChatItemInfoView(chatRh: Long?, ci: ChatItem, ciInfo: ChatItemInfo, devTools
|
||||
}
|
||||
}
|
||||
|
||||
private fun membersStatuses(chatModel: ChatModel, memberDeliveryStatuses: List<MemberDeliveryStatus>): List<Pair<GroupMember, CIStatus>> {
|
||||
private fun membersStatuses(chatModel: ChatModel, memberDeliveryStatuses: List<MemberDeliveryStatus>): List<Triple<GroupMember, CIStatus, Boolean?>> {
|
||||
return memberDeliveryStatuses.mapNotNull { mds ->
|
||||
chatModel.getGroupMember(mds.groupMemberId)?.let { mem ->
|
||||
mem to mds.memberDeliveryStatus
|
||||
Triple(mem, mds.memberDeliveryStatus, mds.sentViaProxy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,6 +479,7 @@ fun ChatView(chatId: String, chatModel: ChatModel, onComposed: suspend (chatId:
|
||||
},
|
||||
onComposed,
|
||||
developerTools = chatModel.controller.appPrefs.developerTools.get(),
|
||||
showViaProxy = chatModel.controller.appPrefs.showSentViaProxy.get(),
|
||||
)
|
||||
}
|
||||
is ChatInfo.ContactConnection -> {
|
||||
@@ -548,6 +549,7 @@ fun ChatLayout(
|
||||
onSearchValueChanged: (String) -> Unit,
|
||||
onComposed: suspend (chatId: String) -> Unit,
|
||||
developerTools: Boolean,
|
||||
showViaProxy: Boolean
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val attachmentDisabled = remember { derivedStateOf { composeState.value.attachmentDisabled } }
|
||||
@@ -606,7 +608,7 @@ fun ChatLayout(
|
||||
useLinkPreviews, linkMode, showMemberInfo, loadPrevMessages, deleteMessage, deleteMessages,
|
||||
receiveFile, cancelFile, joinGroup, acceptCall, acceptFeature, openDirectChat,
|
||||
updateContactStats, updateMemberStats, syncContactConnection, syncMemberConnection, findModelChat, findModelMember,
|
||||
setReaction, showItemDetails, markRead, setFloatingButton, onComposed, developerTools,
|
||||
setReaction, showItemDetails, markRead, setFloatingButton, onComposed, developerTools, showViaProxy,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -885,6 +887,7 @@ fun BoxWithConstraintsScope.ChatItemsList(
|
||||
setFloatingButton: (@Composable () -> Unit) -> Unit,
|
||||
onComposed: suspend (chatId: String) -> Unit,
|
||||
developerTools: Boolean,
|
||||
showViaProxy: Boolean
|
||||
) {
|
||||
val listState = rememberLazyListState()
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -975,7 +978,7 @@ fun BoxWithConstraintsScope.ChatItemsList(
|
||||
tryOrShowError("${cItem.id}ChatItem", error = {
|
||||
CIBrokenComposableView(if (cItem.chatDir.sent) Alignment.CenterEnd else Alignment.CenterStart)
|
||||
}) {
|
||||
ChatItemView(chat.remoteHostId, chat.chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, revealed = revealed, range = range, deleteMessage = deleteMessage, deleteMessages = deleteMessages, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, openDirectChat = openDirectChat, updateContactStats = updateContactStats, updateMemberStats = updateMemberStats, syncContactConnection = syncContactConnection, syncMemberConnection = syncMemberConnection, findModelChat = findModelChat, findModelMember = findModelMember, scrollToItem = scrollToItem, setReaction = setReaction, showItemDetails = showItemDetails, developerTools = developerTools)
|
||||
ChatItemView(chat.remoteHostId, chat.chatInfo, cItem, composeState, provider, useLinkPreviews = useLinkPreviews, linkMode = linkMode, revealed = revealed, range = range, deleteMessage = deleteMessage, deleteMessages = deleteMessages, receiveFile = receiveFile, cancelFile = cancelFile, joinGroup = joinGroup, acceptCall = acceptCall, acceptFeature = acceptFeature, openDirectChat = openDirectChat, updateContactStats = updateContactStats, updateMemberStats = updateMemberStats, syncContactConnection = syncContactConnection, syncMemberConnection = syncMemberConnection, findModelChat = findModelChat, findModelMember = findModelMember, scrollToItem = scrollToItem, setReaction = setReaction, showItemDetails = showItemDetails, developerTools = developerTools, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1543,6 +1546,7 @@ fun PreviewChatLayout() {
|
||||
onSearchValueChanged = {},
|
||||
onComposed = {},
|
||||
developerTools = false,
|
||||
showViaProxy = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1615,6 +1619,7 @@ fun PreviewGroupChatLayout() {
|
||||
onSearchValueChanged = {},
|
||||
onComposed = {},
|
||||
developerTools = false,
|
||||
showViaProxy = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ fun CICallItemView(
|
||||
CICallStatus.Error -> {}
|
||||
}
|
||||
|
||||
CIMetaView(cItem, timedMessagesTTL, showStatus = false, showEdited = false)
|
||||
CIMetaView(cItem, timedMessagesTTL, showStatus = false, showEdited = false, showViaProxy = false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ fun CIGroupInvitationView(
|
||||
}
|
||||
}
|
||||
|
||||
CIMetaView(ci, timedMessagesTTL, showStatus = false, showEdited = false)
|
||||
CIMetaView(ci, timedMessagesTTL, showStatus = false, showEdited = false, showViaProxy = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@ fun CIMetaView(
|
||||
blue = minOf(metaColor.red * 1.33F, 1F))
|
||||
},
|
||||
showStatus: Boolean = true,
|
||||
showEdited: Boolean = true
|
||||
showEdited: Boolean = true,
|
||||
showViaProxy: Boolean
|
||||
) {
|
||||
Row(Modifier.padding(start = 3.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
if (chatItem.isDeletedContent) {
|
||||
@@ -53,7 +54,8 @@ fun CIMetaView(
|
||||
metaColor,
|
||||
paleMetaColor,
|
||||
showStatus = showStatus,
|
||||
showEdited = showEdited
|
||||
showEdited = showEdited,
|
||||
showViaProxy = showViaProxy
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -68,7 +70,8 @@ private fun CIMetaText(
|
||||
color: Color,
|
||||
paleColor: Color,
|
||||
showStatus: Boolean = true,
|
||||
showEdited: Boolean = true
|
||||
showEdited: Boolean = true,
|
||||
showViaProxy: Boolean
|
||||
) {
|
||||
if (showEdited && meta.itemEdited) {
|
||||
StatusIconText(painterResource(MR.images.ic_edit), color)
|
||||
@@ -82,6 +85,9 @@ private fun CIMetaText(
|
||||
}
|
||||
Spacer(Modifier.width(4.dp))
|
||||
}
|
||||
if (showViaProxy && meta.sentViaProxy == true) {
|
||||
Icon(painterResource(MR.images.ic_arrow_forward), null, Modifier.height(17.dp), tint = CurrentColors.value.colors.secondary)
|
||||
}
|
||||
if (showStatus) {
|
||||
val statusIcon = meta.statusIcon(MaterialTheme.colors.primary, color, paleColor)
|
||||
if (statusIcon != null) {
|
||||
@@ -105,7 +111,14 @@ private fun CIMetaText(
|
||||
}
|
||||
|
||||
// the conditions in this function should match CIMetaText
|
||||
fun reserveSpaceForMeta(meta: CIMeta, chatTTL: Int?, encrypted: Boolean?, showStatus: Boolean = true, showEdited: Boolean = true): String {
|
||||
fun reserveSpaceForMeta(
|
||||
meta: CIMeta,
|
||||
chatTTL: Int?,
|
||||
encrypted: Boolean?,
|
||||
showStatus: Boolean = true,
|
||||
showEdited: Boolean = true,
|
||||
showViaProxy: Boolean = false
|
||||
): String {
|
||||
val iconSpace = " "
|
||||
var res = ""
|
||||
if (showEdited && meta.itemEdited) res += iconSpace
|
||||
@@ -116,6 +129,9 @@ fun reserveSpaceForMeta(meta: CIMeta, chatTTL: Int?, encrypted: Boolean?, showSt
|
||||
res += shortTimeText(ttl)
|
||||
}
|
||||
}
|
||||
if (showViaProxy && meta.sentViaProxy == true) {
|
||||
res += iconSpace
|
||||
}
|
||||
if (showStatus && (meta.statusIcon(CurrentColors.value.colors.secondary) != null || !meta.disappearing)) {
|
||||
res += iconSpace
|
||||
}
|
||||
@@ -137,7 +153,8 @@ fun PreviewCIMetaView() {
|
||||
chatItem = ChatItem.getSampleData(
|
||||
1, CIDirection.DirectSnd(), Clock.System.now(), "hello"
|
||||
),
|
||||
null
|
||||
null,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -149,7 +166,8 @@ fun PreviewCIMetaViewUnread() {
|
||||
1, CIDirection.DirectSnd(), Clock.System.now(), "hello",
|
||||
status = CIStatus.RcvNew()
|
||||
),
|
||||
null
|
||||
null,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -159,9 +177,10 @@ fun PreviewCIMetaViewSendFailed() {
|
||||
CIMetaView(
|
||||
chatItem = ChatItem.getSampleData(
|
||||
1, CIDirection.DirectSnd(), Clock.System.now(), "hello",
|
||||
status = CIStatus.SndError("CMD SYNTAX")
|
||||
status = CIStatus.CISSndError(SndError.Other("CMD SYNTAX"))
|
||||
),
|
||||
null
|
||||
null,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -172,7 +191,8 @@ fun PreviewCIMetaViewSendNoAuth() {
|
||||
chatItem = ChatItem.getSampleData(
|
||||
1, CIDirection.DirectSnd(), Clock.System.now(), "hello", status = CIStatus.SndErrorAuth()
|
||||
),
|
||||
null
|
||||
null,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -183,7 +203,8 @@ fun PreviewCIMetaViewSendSent() {
|
||||
chatItem = ChatItem.getSampleData(
|
||||
1, CIDirection.DirectSnd(), Clock.System.now(), "hello", status = CIStatus.SndSent(SndCIStatusProgress.Complete)
|
||||
),
|
||||
null
|
||||
null,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -195,7 +216,8 @@ fun PreviewCIMetaViewEdited() {
|
||||
1, CIDirection.DirectSnd(), Clock.System.now(), "hello",
|
||||
itemEdited = true
|
||||
),
|
||||
null
|
||||
null,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -208,7 +230,8 @@ fun PreviewCIMetaViewEditedUnread() {
|
||||
itemEdited = true,
|
||||
status= CIStatus.RcvNew()
|
||||
),
|
||||
null
|
||||
null,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -221,7 +244,8 @@ fun PreviewCIMetaViewEditedSent() {
|
||||
itemEdited = true,
|
||||
status= CIStatus.SndSent(SndCIStatusProgress.Complete)
|
||||
),
|
||||
null
|
||||
null,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -230,6 +254,7 @@ fun PreviewCIMetaViewEditedSent() {
|
||||
fun PreviewCIMetaViewDeletedContent() {
|
||||
CIMetaView(
|
||||
chatItem = ChatItem.getDeletedContentSampleData(),
|
||||
null
|
||||
null,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ fun DecryptionErrorItemFixButton(
|
||||
)
|
||||
}
|
||||
}
|
||||
CIMetaView(ci, timedMessagesTTL = null)
|
||||
CIMetaView(ci, timedMessagesTTL = null, showViaProxy = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,7 +202,7 @@ fun DecryptionErrorItem(
|
||||
},
|
||||
style = MaterialTheme.typography.body1.copy(lineHeight = 22.sp)
|
||||
)
|
||||
CIMetaView(ci, timedMessagesTTL = null)
|
||||
CIMetaView(ci, timedMessagesTTL = null, showViaProxy = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ fun CIVoiceView(
|
||||
hasText: Boolean,
|
||||
ci: ChatItem,
|
||||
timedMessagesTTL: Int?,
|
||||
showViaProxy: Boolean,
|
||||
longClick: () -> Unit,
|
||||
receiveFile: (Long) -> Unit,
|
||||
) {
|
||||
@@ -76,7 +77,7 @@ fun CIVoiceView(
|
||||
durationText(time / 1000)
|
||||
}
|
||||
}
|
||||
VoiceLayout(file, ci, text, audioPlaying, progress, duration, brokenAudio, sent, hasText, timedMessagesTTL, play, pause, longClick, receiveFile) {
|
||||
VoiceLayout(file, ci, text, audioPlaying, progress, duration, brokenAudio, sent, hasText, timedMessagesTTL, showViaProxy, play, pause, longClick, receiveFile) {
|
||||
AudioPlayer.seekTo(it, progress, fileSource.value?.filePath)
|
||||
}
|
||||
} else {
|
||||
@@ -102,6 +103,7 @@ private fun VoiceLayout(
|
||||
sent: Boolean,
|
||||
hasText: Boolean,
|
||||
timedMessagesTTL: Int?,
|
||||
showViaProxy: Boolean,
|
||||
play: () -> Unit,
|
||||
pause: () -> Unit,
|
||||
longClick: () -> Unit,
|
||||
@@ -171,7 +173,7 @@ private fun VoiceLayout(
|
||||
VoiceMsgIndicator(file, audioPlaying.value, sent, hasText, progress, duration, brokenAudio, play, pause, longClick, receiveFile)
|
||||
}
|
||||
Box(Modifier.padding(top = 6.dp, end = 6.dp)) {
|
||||
CIMetaView(ci, timedMessagesTTL)
|
||||
CIMetaView(ci, timedMessagesTTL, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,7 +188,7 @@ private fun VoiceLayout(
|
||||
}
|
||||
}
|
||||
Box(Modifier.padding(top = 6.dp)) {
|
||||
CIMetaView(ci, timedMessagesTTL)
|
||||
CIMetaView(ci, timedMessagesTTL, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ fun ChatItemView(
|
||||
setReaction: (ChatInfo, ChatItem, Boolean, MsgReaction) -> Unit,
|
||||
showItemDetails: (ChatInfo, ChatItem) -> Unit,
|
||||
developerTools: Boolean,
|
||||
showViaProxy: Boolean
|
||||
) {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
val sent = cItem.chatDir.sent
|
||||
@@ -83,17 +84,15 @@ fun ChatItemView(
|
||||
.fillMaxWidth(),
|
||||
contentAlignment = alignment,
|
||||
) {
|
||||
val onClick = {
|
||||
when (cItem.meta.itemStatus) {
|
||||
is CIStatus.SndErrorAuth -> {
|
||||
showMsgDeliveryErrorAlert(generalGetString(MR.strings.message_delivery_error_desc))
|
||||
}
|
||||
is CIStatus.SndError -> {
|
||||
showMsgDeliveryErrorAlert(generalGetString(MR.strings.unknown_error) + ": ${cItem.meta.itemStatus.agentError}")
|
||||
}
|
||||
else -> {}
|
||||
val info = cItem.meta.itemStatus.statusInto
|
||||
val onClick = if (info != null) {
|
||||
{
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = info.first,
|
||||
text = info.second,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else { {} }
|
||||
|
||||
@Composable
|
||||
fun ChatItemReactions() {
|
||||
@@ -130,7 +129,7 @@ fun ChatItemView(
|
||||
) {
|
||||
@Composable
|
||||
fun framedItemView() {
|
||||
FramedItemView(cInfo, cItem, uriHandler, imageProvider, linkMode = linkMode, showMenu, receiveFile, onLinkLongClick, scrollToItem)
|
||||
FramedItemView(cInfo, cItem, uriHandler, imageProvider, linkMode = linkMode, showViaProxy = showViaProxy, showMenu, receiveFile, onLinkLongClick, scrollToItem)
|
||||
}
|
||||
|
||||
fun deleteMessageQuestionText(): String {
|
||||
@@ -334,14 +333,14 @@ fun ChatItemView(
|
||||
fun ContentItem() {
|
||||
val mc = cItem.content.msgContent
|
||||
if (cItem.meta.itemDeleted != null && (!revealed.value || cItem.isDeletedContent)) {
|
||||
MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, revealed)
|
||||
MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, revealed, showViaProxy = showViaProxy)
|
||||
MarkedDeletedItemDropdownMenu()
|
||||
} else {
|
||||
if (cItem.quotedItem == null && cItem.meta.itemForwarded == null && cItem.meta.itemDeleted == null && !cItem.meta.isLive) {
|
||||
if (mc is MsgContent.MCText && isShortEmoji(cItem.content.text)) {
|
||||
EmojiItemView(cItem, cInfo.timedMessagesTTL)
|
||||
EmojiItemView(cItem, cInfo.timedMessagesTTL, showViaProxy = showViaProxy)
|
||||
} else if (mc is MsgContent.MCVoice && cItem.content.text.isEmpty()) {
|
||||
CIVoiceView(mc.duration, cItem.file, cItem.meta.itemEdited, cItem.chatDir.sent, hasText = false, cItem, cInfo.timedMessagesTTL, longClick = { onLinkLongClick("") }, receiveFile)
|
||||
CIVoiceView(mc.duration, cItem.file, cItem.meta.itemEdited, cItem.chatDir.sent, hasText = false, cItem, cInfo.timedMessagesTTL, showViaProxy = showViaProxy, longClick = { onLinkLongClick("") }, receiveFile)
|
||||
} else {
|
||||
framedItemView()
|
||||
}
|
||||
@@ -353,7 +352,7 @@ fun ChatItemView(
|
||||
}
|
||||
|
||||
@Composable fun LegacyDeletedItem() {
|
||||
DeletedItemView(cItem, cInfo.timedMessagesTTL)
|
||||
DeletedItemView(cItem, cInfo.timedMessagesTTL, showViaProxy = showViaProxy)
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
ItemInfoAction(cInfo, cItem, showItemDetails, showMenu)
|
||||
DeleteItemAction(cItem, revealed, showMenu, questionText = deleteMessageQuestionText(), deleteMessage, deleteMessages)
|
||||
@@ -406,7 +405,7 @@ fun ChatItemView(
|
||||
|
||||
@Composable
|
||||
fun DeletedItem() {
|
||||
MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, revealed)
|
||||
MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, revealed, showViaProxy = showViaProxy)
|
||||
DefaultDropdownMenu(showMenu) {
|
||||
ItemInfoAction(cInfo, cItem, showItemDetails, showMenu)
|
||||
DeleteItemAction(cItem, revealed, showMenu, questionText = generalGetString(MR.strings.delete_message_cannot_be_undone_warning), deleteMessage, deleteMessages)
|
||||
@@ -816,13 +815,6 @@ fun moderateMessageAlertDialog(chatItem: ChatItem, questionText: String, deleteM
|
||||
)
|
||||
}
|
||||
|
||||
private fun showMsgDeliveryErrorAlert(description: String) {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.message_delivery_error_title),
|
||||
text = description,
|
||||
)
|
||||
}
|
||||
|
||||
expect fun copyItemToClipboard(cItem: ChatItem, clipboard: ClipboardManager)
|
||||
|
||||
@Preview
|
||||
@@ -858,6 +850,7 @@ fun PreviewChatItemView() {
|
||||
setReaction = { _, _, _, _ -> },
|
||||
showItemDetails = { _, _ -> },
|
||||
developerTools = false,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -893,6 +886,7 @@ fun PreviewChatItemViewDeletedContent() {
|
||||
setReaction = { _, _, _, _ -> },
|
||||
showItemDetails = { _, _ -> },
|
||||
developerTools = false,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import chat.simplex.common.model.ChatItem
|
||||
import chat.simplex.common.ui.theme.*
|
||||
|
||||
@Composable
|
||||
fun DeletedItemView(ci: ChatItem, timedMessagesTTL: Int?) {
|
||||
fun DeletedItemView(ci: ChatItem, timedMessagesTTL: Int?, showViaProxy: Boolean) {
|
||||
val sent = ci.chatDir.sent
|
||||
val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage
|
||||
val receivedColor = CurrentColors.collectAsState().value.appColors.receivedMessage
|
||||
@@ -36,7 +36,7 @@ fun DeletedItemView(ci: ChatItem, timedMessagesTTL: Int?) {
|
||||
style = MaterialTheme.typography.body1.copy(lineHeight = 22.sp),
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
CIMetaView(ci, timedMessagesTTL)
|
||||
CIMetaView(ci, timedMessagesTTL, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,8 @@ fun PreviewDeletedItemView() {
|
||||
SimpleXTheme {
|
||||
DeletedItemView(
|
||||
ChatItem.getDeletedContentSampleData(),
|
||||
null
|
||||
null,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,13 @@ val largeEmojiFont: TextStyle = TextStyle(fontSize = 48.sp, fontFamily = EmojiFo
|
||||
val mediumEmojiFont: TextStyle = TextStyle(fontSize = 36.sp, fontFamily = EmojiFont)
|
||||
|
||||
@Composable
|
||||
fun EmojiItemView(chatItem: ChatItem, timedMessagesTTL: Int?) {
|
||||
fun EmojiItemView(chatItem: ChatItem, timedMessagesTTL: Int?, showViaProxy: Boolean) {
|
||||
Column(
|
||||
Modifier.padding(vertical = 8.dp, horizontal = 12.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
EmojiText(chatItem.content.text)
|
||||
CIMetaView(chatItem, timedMessagesTTL)
|
||||
CIMetaView(chatItem, timedMessagesTTL, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ fun FramedItemView(
|
||||
uriHandler: UriHandler? = null,
|
||||
imageProvider: (() -> ImageGalleryProvider)? = null,
|
||||
linkMode: SimplexLinkMode,
|
||||
showViaProxy: Boolean,
|
||||
showMenu: MutableState<Boolean>,
|
||||
receiveFile: (Long) -> Unit,
|
||||
onLinkLongClick: (link: String) -> Unit = {},
|
||||
@@ -180,7 +181,7 @@ fun FramedItemView(
|
||||
fun ciFileView(ci: ChatItem, text: String) {
|
||||
CIFileView(ci.file, ci.meta.itemEdited, showMenu, receiveFile)
|
||||
if (text != "" || ci.meta.isLive) {
|
||||
CIMarkdownText(ci, chatTTL, linkMode = linkMode, uriHandler)
|
||||
CIMarkdownText(ci, chatTTL, linkMode = linkMode, uriHandler, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +245,7 @@ fun FramedItemView(
|
||||
if (mc.text == "" && !ci.meta.isLive) {
|
||||
metaColor = Color.White
|
||||
} else {
|
||||
CIMarkdownText(ci, chatTTL, linkMode, uriHandler)
|
||||
CIMarkdownText(ci, chatTTL, linkMode, uriHandler, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
is MsgContent.MCVideo -> {
|
||||
@@ -252,35 +253,35 @@ fun FramedItemView(
|
||||
if (mc.text == "" && !ci.meta.isLive) {
|
||||
metaColor = Color.White
|
||||
} else {
|
||||
CIMarkdownText(ci, chatTTL, linkMode, uriHandler)
|
||||
CIMarkdownText(ci, chatTTL, linkMode, uriHandler, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
is MsgContent.MCVoice -> {
|
||||
CIVoiceView(mc.duration, ci.file, ci.meta.itemEdited, ci.chatDir.sent, hasText = true, ci, timedMessagesTTL = chatTTL, longClick = { onLinkLongClick("") }, receiveFile)
|
||||
CIVoiceView(mc.duration, ci.file, ci.meta.itemEdited, ci.chatDir.sent, hasText = true, ci, timedMessagesTTL = chatTTL, showViaProxy = showViaProxy, longClick = { onLinkLongClick("") }, receiveFile)
|
||||
if (mc.text != "") {
|
||||
CIMarkdownText(ci, chatTTL, linkMode, uriHandler)
|
||||
CIMarkdownText(ci, chatTTL, linkMode, uriHandler, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
is MsgContent.MCFile -> ciFileView(ci, mc.text)
|
||||
is MsgContent.MCUnknown ->
|
||||
if (ci.file == null) {
|
||||
CIMarkdownText(ci, chatTTL, linkMode, uriHandler, onLinkLongClick)
|
||||
CIMarkdownText(ci, chatTTL, linkMode, uriHandler, onLinkLongClick, showViaProxy = showViaProxy)
|
||||
} else {
|
||||
ciFileView(ci, mc.text)
|
||||
}
|
||||
is MsgContent.MCLink -> {
|
||||
ChatItemLinkView(mc.preview)
|
||||
Box(Modifier.widthIn(max = DEFAULT_MAX_IMAGE_WIDTH)) {
|
||||
CIMarkdownText(ci, chatTTL, linkMode, uriHandler, onLinkLongClick)
|
||||
CIMarkdownText(ci, chatTTL, linkMode, uriHandler, onLinkLongClick, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
else -> CIMarkdownText(ci, chatTTL, linkMode, uriHandler, onLinkLongClick)
|
||||
else -> CIMarkdownText(ci, chatTTL, linkMode, uriHandler, onLinkLongClick, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Box(Modifier.padding(bottom = 6.dp, end = 12.dp)) {
|
||||
CIMetaView(ci, chatTTL, metaColor)
|
||||
CIMetaView(ci, chatTTL, metaColor, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,14 +293,15 @@ fun CIMarkdownText(
|
||||
chatTTL: Int?,
|
||||
linkMode: SimplexLinkMode,
|
||||
uriHandler: UriHandler?,
|
||||
onLinkLongClick: (link: String) -> Unit = {}
|
||||
onLinkLongClick: (link: String) -> Unit = {},
|
||||
showViaProxy: Boolean
|
||||
) {
|
||||
Box(Modifier.padding(vertical = 6.dp, horizontal = 12.dp)) {
|
||||
val text = if (ci.meta.isLive) ci.content.msgContent?.text ?: ci.text else ci.text
|
||||
MarkdownText(
|
||||
text, if (text.isEmpty()) emptyList() else ci.formattedText, toggleSecrets = true,
|
||||
meta = ci.meta, chatTTL = chatTTL, linkMode = linkMode,
|
||||
uriHandler = uriHandler, senderBold = true, onLinkLongClick = onLinkLongClick
|
||||
uriHandler = uriHandler, senderBold = true, onLinkLongClick = onLinkLongClick, showViaProxy = showViaProxy
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ fun CIMsgError(ci: ChatItem, timedMessagesTTL: Int?, onClick: () -> Unit) {
|
||||
style = MaterialTheme.typography.body1.copy(lineHeight = 22.sp),
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
CIMetaView(ci, timedMessagesTTL)
|
||||
CIMetaView(ci, timedMessagesTTL, showViaProxy = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import dev.icerock.moko.resources.compose.stringResource
|
||||
import kotlinx.datetime.Clock
|
||||
|
||||
@Composable
|
||||
fun MarkedDeletedItemView(ci: ChatItem, timedMessagesTTL: Int?, revealed: MutableState<Boolean>) {
|
||||
fun MarkedDeletedItemView(ci: ChatItem, timedMessagesTTL: Int?, revealed: MutableState<Boolean>, showViaProxy: Boolean) {
|
||||
val sentColor = CurrentColors.collectAsState().value.appColors.sentMessage
|
||||
val receivedColor = CurrentColors.collectAsState().value.appColors.receivedMessage
|
||||
Surface(
|
||||
@@ -35,7 +35,7 @@ fun MarkedDeletedItemView(ci: ChatItem, timedMessagesTTL: Int?, revealed: Mutabl
|
||||
Box(Modifier.weight(1f, false)) {
|
||||
MergedMarkedDeletedText(ci, revealed)
|
||||
}
|
||||
CIMetaView(ci, timedMessagesTTL)
|
||||
CIMetaView(ci, timedMessagesTTL, showViaProxy = showViaProxy)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,8 @@ fun PreviewMarkedDeletedItemView() {
|
||||
SimpleXTheme {
|
||||
DeletedItemView(
|
||||
ChatItem.getSampleData(itemDeleted = CIDeleted.Deleted(Clock.System.now())),
|
||||
null
|
||||
null,
|
||||
showViaProxy = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,8 @@ fun MarkdownText (
|
||||
modifier: Modifier = Modifier,
|
||||
linkMode: SimplexLinkMode,
|
||||
inlineContent: Pair<AnnotatedString.Builder.() -> Unit, Map<String, InlineTextContent>>? = null,
|
||||
onLinkLongClick: (link: String) -> Unit = {}
|
||||
onLinkLongClick: (link: String) -> Unit = {},
|
||||
showViaProxy: Boolean = false
|
||||
) {
|
||||
val textLayoutDirection = remember (text) {
|
||||
if (isRtl(text.subSequence(0, kotlin.math.min(50, text.length)))) LayoutDirection.Rtl else LayoutDirection.Ltr
|
||||
@@ -77,7 +78,7 @@ fun MarkdownText (
|
||||
val reserve = if (textLayoutDirection != LocalLayoutDirection.current && meta != null) {
|
||||
"\n"
|
||||
} else if (meta != null) {
|
||||
reserveSpaceForMeta(meta, chatTTL, null) // LALAL
|
||||
reserveSpaceForMeta(meta, chatTTL, null, showViaProxy = showViaProxy)
|
||||
} else {
|
||||
" "
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
|
||||
hostMode = currentCfg.value.hostMode,
|
||||
requiredHostMode = currentCfg.value.requiredHostMode,
|
||||
sessionMode = currentCfg.value.sessionMode,
|
||||
smpProxyMode = currentCfg.value.smpProxyMode,
|
||||
smpProxyFallback = currentCfg.value.smpProxyFallback,
|
||||
tcpConnectTimeout = networkTCPConnectTimeout.value,
|
||||
tcpTimeout = networkTCPTimeout.value,
|
||||
tcpTimeoutPerKb = networkTCPTimeoutPerKb.value,
|
||||
|
||||
@@ -255,8 +255,20 @@
|
||||
|
||||
<!-- Chat Alerts - ChatItemView.kt -->
|
||||
<string name="message_delivery_error_title">Message delivery error</string>
|
||||
<string name="message_delivery_warning_title">Message delivery warning</string>
|
||||
<string name="message_delivery_error_desc">Most likely this contact has deleted the connection with you.</string>
|
||||
|
||||
<!-- CIStatus errors -->
|
||||
<string name="ci_status_other_error">Error: %1$s</string>
|
||||
<string name="snd_error_auth">Wrong key or unknown connection - most likely this connection is deleted.</string>
|
||||
<string name="snd_error_quota">Capacity exceeded - recipient did not receive previously sent messages.</string>
|
||||
<string name="snd_error_expired">Network issues - message expired after many attempts to send it.</string>
|
||||
<string name="snd_error_relay">Destination server error: %1$s</string>
|
||||
<string name="snd_error_proxy">Forwarding server: %1$s\nError: %2$s</string>
|
||||
<string name="snd_error_proxy_relay">Forwarding server: %1$s\nDestination server error: %2$s</string>
|
||||
<string name="srv_error_host">Server address is incompatible with network settings.</string>
|
||||
<string name="srv_error_version">Server version is incompatible with network settings.</string>
|
||||
|
||||
<!-- Chat Actions - ChatItemView.kt (and general) -->
|
||||
<string name="reply_verb">Reply</string>
|
||||
<string name="share_verb">Share</string>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" fill="#5f6368"><path d="M629-446.5H235.48q-13.79 0-23.64-9.79-9.84-9.79-9.84-23.5t9.84-23.71q9.85-10 23.64-10H629L455.79-686.71Q445.5-697 445.25-710.5t10.25-24.48q10.5-10.52 24-10.27t23.81 10.57L734.1-503.59q4.9 4.91 7.65 10.97 2.75 6.06 2.75 12.78 0 6.71-2.75 12.78Q739-461 734.5-456.5l-231 231q-11 11-23.75 10.5t-23.25-11.02Q446-237 446-250.42q0-13.41 10.5-23.58L629-446.5Z"/></svg>
|
||||
|
After Width: | Height: | Size: 472 B |
Reference in New Issue
Block a user