mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2024-12-17 17:20:21 +01:00
Merge branch 'master' into master-ghc8107
This commit is contained in:
+4
-5
@@ -370,7 +370,6 @@ fun CallInfoView(call: Call, alignment: Alignment.Horizontal) {
|
||||
InfoText(call.callState.text)
|
||||
|
||||
val connInfo = call.connectionInfo
|
||||
// val connInfoText = if (connInfo == null) "" else " (${connInfo.text}, ${connInfo.protocolText})"
|
||||
val connInfoText = if (connInfo == null) "" else " (${connInfo.text})"
|
||||
InfoText(call.encryptionStatus + connInfoText)
|
||||
}
|
||||
@@ -585,8 +584,8 @@ fun PreviewActiveCallOverlayVideo() {
|
||||
localMedia = CallMediaType.Video,
|
||||
peerMedia = CallMediaType.Video,
|
||||
connectionInfo = ConnectionInfo(
|
||||
RTCIceCandidate(RTCIceCandidateType.Host, "tcp", null),
|
||||
RTCIceCandidate(RTCIceCandidateType.Host, "tcp", null)
|
||||
RTCIceCandidate(RTCIceCandidateType.Host, "tcp"),
|
||||
RTCIceCandidate(RTCIceCandidateType.Host, "tcp")
|
||||
)
|
||||
),
|
||||
speakerCanBeEnabled = true,
|
||||
@@ -611,8 +610,8 @@ fun PreviewActiveCallOverlayAudio() {
|
||||
localMedia = CallMediaType.Audio,
|
||||
peerMedia = CallMediaType.Audio,
|
||||
connectionInfo = ConnectionInfo(
|
||||
RTCIceCandidate(RTCIceCandidateType.Host, "udp", null),
|
||||
RTCIceCandidate(RTCIceCandidateType.Host, "udp", null)
|
||||
RTCIceCandidate(RTCIceCandidateType.Host, "udp"),
|
||||
RTCIceCandidate(RTCIceCandidateType.Host, "udp")
|
||||
)
|
||||
),
|
||||
speakerCanBeEnabled = true,
|
||||
|
||||
+16
-25
@@ -173,6 +173,8 @@ class AppPreferences {
|
||||
val connectRemoteViaMulticastAuto = mkBoolPreference(SHARED_PREFS_CONNECT_REMOTE_VIA_MULTICAST_AUTO, true)
|
||||
val offerRemoteMulticast = mkBoolPreference(SHARED_PREFS_OFFER_REMOTE_MULTICAST, true)
|
||||
|
||||
val desktopWindowState = mkStrPreference(SHARED_PREFS_DESKTOP_WINDOW_STATE, null)
|
||||
|
||||
private fun mkIntPreference(prefName: String, default: Int) =
|
||||
SharedPreference(
|
||||
get = fun() = settings.getInt(prefName, default),
|
||||
@@ -317,6 +319,7 @@ class AppPreferences {
|
||||
private const val SHARED_PREFS_CONNECT_REMOTE_VIA_MULTICAST = "ConnectRemoteViaMulticast"
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -891,20 +894,21 @@ object ChatController {
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiConnect(rh: Long?, incognito: Boolean, connReq: String): Boolean {
|
||||
suspend fun apiConnect(rh: Long?, incognito: Boolean, connReq: String): PendingContactConnection? {
|
||||
val userId = chatModel.currentUser.value?.userId ?: run {
|
||||
Log.e(TAG, "apiConnect: no current user")
|
||||
return false
|
||||
return null
|
||||
}
|
||||
val r = sendCmd(rh, CC.APIConnect(userId, incognito, connReq))
|
||||
when {
|
||||
r is CR.SentConfirmation || r is CR.SentInvitation -> return true
|
||||
r is CR.SentConfirmation -> return r.connection
|
||||
r is CR.SentInvitation -> return r.connection
|
||||
r is CR.ContactAlreadyExists -> {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
generalGetString(MR.strings.contact_already_exists),
|
||||
String.format(generalGetString(MR.strings.you_are_already_connected_to_vName_via_this_link), r.contact.displayName)
|
||||
)
|
||||
return false
|
||||
return null
|
||||
}
|
||||
r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorChat
|
||||
&& r.chatError.errorType is ChatErrorType.InvalidConnReq -> {
|
||||
@@ -912,7 +916,7 @@ object ChatController {
|
||||
generalGetString(MR.strings.invalid_connection_link),
|
||||
generalGetString(MR.strings.please_check_correct_link_and_maybe_ask_for_a_new_one)
|
||||
)
|
||||
return false
|
||||
return null
|
||||
}
|
||||
r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorAgent
|
||||
&& r.chatError.agentError is AgentErrorType.SMP
|
||||
@@ -921,13 +925,13 @@ object ChatController {
|
||||
generalGetString(MR.strings.connection_error_auth),
|
||||
generalGetString(MR.strings.connection_error_auth_desc)
|
||||
)
|
||||
return false
|
||||
return null
|
||||
}
|
||||
else -> {
|
||||
if (!(networkErrorAlert(r))) {
|
||||
apiErrorAlert("apiConnect", generalGetString(MR.strings.connection_error), r)
|
||||
}
|
||||
return false
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1526,16 +1530,6 @@ object ChatController {
|
||||
fun active(user: UserLike): Boolean = activeUser(rhId, user)
|
||||
chatModel.addTerminalItem(TerminalItem.resp(rhId, r))
|
||||
when (r) {
|
||||
is CR.NewContactConnection -> {
|
||||
if (active(r.user)) {
|
||||
chatModel.updateContactConnection(rhId, r.connection)
|
||||
}
|
||||
}
|
||||
is CR.ContactConnectionDeleted -> {
|
||||
if (active(r.user)) {
|
||||
chatModel.removeChat(rhId, r.connection.id)
|
||||
}
|
||||
}
|
||||
is CR.ContactDeletedByContact -> {
|
||||
if (active(r.user) && r.contact.directOrUsed) {
|
||||
chatModel.updateContact(rhId, r.contact)
|
||||
@@ -3707,8 +3701,8 @@ sealed class CR {
|
||||
@Serializable @SerialName("invitation") class Invitation(val user: UserRef, val connReqInvitation: String, val connection: PendingContactConnection): CR()
|
||||
@Serializable @SerialName("connectionIncognitoUpdated") class ConnectionIncognitoUpdated(val user: UserRef, val toConnection: PendingContactConnection): CR()
|
||||
@Serializable @SerialName("connectionPlan") class CRConnectionPlan(val user: UserRef, val connectionPlan: ConnectionPlan): CR()
|
||||
@Serializable @SerialName("sentConfirmation") class SentConfirmation(val user: UserRef): CR()
|
||||
@Serializable @SerialName("sentInvitation") class SentInvitation(val user: UserRef): CR()
|
||||
@Serializable @SerialName("sentConfirmation") class SentConfirmation(val user: UserRef, val connection: PendingContactConnection): CR()
|
||||
@Serializable @SerialName("sentInvitation") class SentInvitation(val user: UserRef, val connection: PendingContactConnection): CR()
|
||||
@Serializable @SerialName("sentInvitationToContact") class SentInvitationToContact(val user: UserRef, val contact: Contact, val customUserProfile: Profile?): CR()
|
||||
@Serializable @SerialName("contactAlreadyExists") class ContactAlreadyExists(val user: UserRef, val contact: Contact): CR()
|
||||
@Serializable @SerialName("contactRequestAlreadyAccepted") class ContactRequestAlreadyAccepted(val user: UserRef, val contact: Contact): CR()
|
||||
@@ -3802,7 +3796,6 @@ sealed class CR {
|
||||
@Serializable @SerialName("callAnswer") class CallAnswer(val user: UserRef, val contact: Contact, val answer: WebRTCSession): CR()
|
||||
@Serializable @SerialName("callExtraInfo") class CallExtraInfo(val user: UserRef, val contact: Contact, val extraInfo: WebRTCExtraInfo): CR()
|
||||
@Serializable @SerialName("callEnded") class CallEnded(val user: UserRef, val contact: Contact): CR()
|
||||
@Serializable @SerialName("newContactConnection") class NewContactConnection(val user: UserRef, val connection: PendingContactConnection): CR()
|
||||
@Serializable @SerialName("contactConnectionDeleted") class ContactConnectionDeleted(val user: UserRef, val connection: PendingContactConnection): CR()
|
||||
// remote events (desktop)
|
||||
@Serializable @SerialName("remoteHostList") class RemoteHostList(val remoteHosts: List<RemoteHostInfo>): CR()
|
||||
@@ -3951,7 +3944,6 @@ sealed class CR {
|
||||
is CallAnswer -> "callAnswer"
|
||||
is CallExtraInfo -> "callExtraInfo"
|
||||
is CallEnded -> "callEnded"
|
||||
is NewContactConnection -> "newContactConnection"
|
||||
is ContactConnectionDeleted -> "contactConnectionDeleted"
|
||||
is RemoteHostList -> "remoteHostList"
|
||||
is CurrentRemoteHost -> "currentRemoteHost"
|
||||
@@ -4006,11 +3998,11 @@ sealed class CR {
|
||||
is ContactCode -> withUser(user, "contact: ${json.encodeToString(contact)}\nconnectionCode: $connectionCode")
|
||||
is GroupMemberCode -> withUser(user, "groupInfo: ${json.encodeToString(groupInfo)}\nmember: ${json.encodeToString(member)}\nconnectionCode: $connectionCode")
|
||||
is ConnectionVerified -> withUser(user, "verified: $verified\nconnectionCode: $expectedCode")
|
||||
is Invitation -> withUser(user, connReqInvitation)
|
||||
is Invitation -> withUser(user, "connReqInvitation: $connReqInvitation\nconnection: $connection")
|
||||
is ConnectionIncognitoUpdated -> withUser(user, json.encodeToString(toConnection))
|
||||
is CRConnectionPlan -> withUser(user, json.encodeToString(connectionPlan))
|
||||
is SentConfirmation -> withUser(user, noDetails())
|
||||
is SentInvitation -> withUser(user, noDetails())
|
||||
is SentConfirmation -> withUser(user, json.encodeToString(connection))
|
||||
is SentInvitation -> withUser(user, json.encodeToString(connection))
|
||||
is SentInvitationToContact -> withUser(user, json.encodeToString(contact))
|
||||
is ContactAlreadyExists -> withUser(user, json.encodeToString(contact))
|
||||
is ContactRequestAlreadyAccepted -> withUser(user, json.encodeToString(contact))
|
||||
@@ -4098,7 +4090,6 @@ sealed class CR {
|
||||
is CallAnswer -> withUser(user, "contact: ${contact.id}\nanswer: ${json.encodeToString(answer)}")
|
||||
is CallExtraInfo -> withUser(user, "contact: ${contact.id}\nextraInfo: ${json.encodeToString(extraInfo)}")
|
||||
is CallEnded -> withUser(user, "contact: ${contact.id}")
|
||||
is NewContactConnection -> withUser(user, json.encodeToString(connection))
|
||||
is ContactConnectionDeleted -> withUser(user, json.encodeToString(connection))
|
||||
// remote events (mobile)
|
||||
is RemoteHostList -> json.encodeToString(remoteHosts)
|
||||
|
||||
+1
-9
@@ -127,18 +127,10 @@ sealed class WCallResponse {
|
||||
"${local?.value ?: "unknown"} / ${remote?.value ?: "unknown"}"
|
||||
}
|
||||
}
|
||||
|
||||
val protocolText: String get() {
|
||||
val local = localCandidate?.protocol?.uppercase(Locale.ROOT) ?: "unknown"
|
||||
val localRelay = localCandidate?.relayProtocol?.uppercase(Locale.ROOT) ?: "unknown"
|
||||
val remote = remoteCandidate?.protocol?.uppercase(Locale.ROOT) ?: "unknown"
|
||||
val localText = if (localRelay == local || localCandidate?.relayProtocol == null) local else "$local ($localRelay)"
|
||||
return if (local == remote) localText else "$localText / $remote"
|
||||
}
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate
|
||||
@Serializable data class RTCIceCandidate(val candidateType: RTCIceCandidateType?, val protocol: String?, val relayProtocol: String?)
|
||||
@Serializable data class RTCIceCandidate(val candidateType: RTCIceCandidateType?, val protocol: String?)
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer
|
||||
@Serializable data class RTCIceServer(val urls: List<String>, val username: String? = null, val credential: String? = null)
|
||||
|
||||
|
||||
+1
@@ -108,6 +108,7 @@ private fun createInvitation(
|
||||
withApi {
|
||||
val r = m.controller.apiAddContact(rhId, incognito = m.controller.appPrefs.incognito.get())
|
||||
if (r != null) {
|
||||
m.updateContactConnection(rhId, r.second)
|
||||
connReqInvitation.value = r.first
|
||||
contactConnection.value = r.second
|
||||
} else {
|
||||
|
||||
+4
-4
@@ -283,10 +283,11 @@ suspend fun connectViaUri(
|
||||
incognito: Boolean,
|
||||
connectionPlan: ConnectionPlan?,
|
||||
close: (() -> Unit)?
|
||||
): Boolean {
|
||||
val r = chatModel.controller.apiConnect(rhId, incognito, uri.toString())
|
||||
) {
|
||||
val pcc = chatModel.controller.apiConnect(rhId, incognito, uri.toString())
|
||||
val connLinkType = if (connectionPlan != null) planToConnectionLinkType(connectionPlan) else ConnectionLinkType.INVITATION
|
||||
if (r) {
|
||||
if (pcc != null) {
|
||||
chatModel.updateContactConnection(rhId, pcc)
|
||||
close?.invoke()
|
||||
AlertManager.shared.showAlertMsg(
|
||||
title = generalGetString(MR.strings.connection_request_sent),
|
||||
@@ -299,7 +300,6 @@ suspend fun connectViaUri(
|
||||
hostDevice = hostDevice(rhId),
|
||||
)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
fun planToConnectionLinkType(connectionPlan: ConnectionPlan): ConnectionLinkType {
|
||||
|
||||
@@ -15,7 +15,6 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.*
|
||||
import chat.simplex.common.model.ChatController
|
||||
import chat.simplex.common.model.ChatModel
|
||||
import chat.simplex.common.platform.desktopPlatform
|
||||
import chat.simplex.common.ui.theme.DEFAULT_START_MODAL_WIDTH
|
||||
import chat.simplex.common.ui.theme.SimpleXTheme
|
||||
import chat.simplex.common.views.TerminalView
|
||||
@@ -31,10 +30,30 @@ import java.io.File
|
||||
val simplexWindowState = SimplexWindowState()
|
||||
|
||||
fun showApp() = application {
|
||||
// For some reason on Linux actual width will be 10.dp less after specifying it here. If we specify 1366,
|
||||
// it will show 1356. But after that we can still update it to 1366 by changing window state. Just making it +10 now here
|
||||
val width = if (desktopPlatform.isLinux()) 1376.dp else 1366.dp
|
||||
val windowState = rememberWindowState(placement = WindowPlacement.Floating, width = width, height = 768.dp)
|
||||
// Creates file if not exists; comes with proper defaults
|
||||
val state = getStoredWindowState()
|
||||
|
||||
val windowState: WindowState = rememberWindowState(
|
||||
placement = WindowPlacement.Floating,
|
||||
width = state.width.dp,
|
||||
height = state.height.dp,
|
||||
position = WindowPosition(state.x.dp, state.y.dp)
|
||||
)
|
||||
|
||||
LaunchedEffect(
|
||||
windowState.position.x.value,
|
||||
windowState.position.y.value,
|
||||
windowState.size.width.value,
|
||||
windowState.size.height.value
|
||||
) {
|
||||
storeWindowState(WindowPositionSize(
|
||||
x = windowState.position.x.value.toInt(),
|
||||
y = windowState.position.y.value.toInt(),
|
||||
width = windowState.size.width.value.toInt(),
|
||||
height = windowState.size.height.value.toInt()
|
||||
))
|
||||
}
|
||||
|
||||
simplexWindowState.windowState = windowState
|
||||
// Reload all strings in all @Composable's after language change at runtime
|
||||
if (remember { ChatController.appPrefs.appLanguage.state }.value != "") {
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package chat.simplex.common
|
||||
|
||||
import chat.simplex.common.model.json
|
||||
import chat.simplex.common.platform.appPreferences
|
||||
import chat.simplex.common.platform.desktopPlatform
|
||||
import kotlinx.serialization.*
|
||||
|
||||
@Serializable
|
||||
data class WindowPositionSize(
|
||||
val width: Int = 1366,
|
||||
val height: Int = 768,
|
||||
val x: Int = 0,
|
||||
val y: Int = 0,
|
||||
)
|
||||
|
||||
fun getStoredWindowState(): WindowPositionSize =
|
||||
try {
|
||||
val str = appPreferences.desktopWindowState.get()
|
||||
var state = if (str == null) {
|
||||
WindowPositionSize()
|
||||
} else {
|
||||
json.decodeFromString(str)
|
||||
}
|
||||
|
||||
// For some reason on Linux actual width will be 10.dp less after specifying it here. If we specify 1366,
|
||||
// it will show 1356. But after that we can still update it to 1366 by changing window state. Just making it +10 now here
|
||||
if (desktopPlatform.isLinux() && state.width == 1366) {
|
||||
state = state.copy(width = 1376)
|
||||
}
|
||||
state
|
||||
} catch (e: Throwable) {
|
||||
WindowPositionSize()
|
||||
}
|
||||
|
||||
fun storeWindowState(state: WindowPositionSize) =
|
||||
appPreferences.desktopWindowState.set(json.encodeToString(state))
|
||||
-1
@@ -136,7 +136,6 @@ private fun SendStateUpdates() {
|
||||
.collect { call ->
|
||||
val state = call.callState.text
|
||||
val connInfo = call.connectionInfo
|
||||
// val connInfoText = if (connInfo == null) "" else " (${connInfo.text}, ${connInfo.protocolText})"
|
||||
val connInfoText = if (connInfo == null) "" else " (${connInfo.text})"
|
||||
val description = call.encryptionStatus + connInfoText
|
||||
chatModel.callCommand.add(WCallCommand.Description(state, description))
|
||||
|
||||
Reference in New Issue
Block a user