mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-10-23 19:23:36 +00:00
Merge branch 'master' into master-android
This commit is contained in:
95 files changed
+4754
-484
No files matched your search
+3
-3
@@ -132,7 +132,7 @@ actual fun ActiveCallView() {
|
||||
}
|
||||
Box(Modifier.fillMaxSize()) {
|
||||
WebRTCView(chatModel.callCommand) { apiMsg ->
|
||||
Log.d(TAG, "received from WebRTCView: $apiMsg")
|
||||
Log.d(TAG, "received from WebRTCView: ${apiMsg.resp.javaClass.simpleName}")
|
||||
val call = chatModel.activeCall.value
|
||||
if (call != null) {
|
||||
val callState = call.androidCallState as ActiveCallState
|
||||
@@ -711,7 +711,7 @@ fun WebRTCView(callCommand: SnapshotStateList<WCallCommand>, onResponse: (WVAPIM
|
||||
.collect {
|
||||
while (callCommand.isNotEmpty()) {
|
||||
val cmd = callCommand.removeFirstOrNull()
|
||||
Log.d(TAG, "WebRTCView LaunchedEffect executing $cmd")
|
||||
Log.d(TAG, "WebRTCView LaunchedEffect executing ${cmd?.javaClass?.simpleName}")
|
||||
if (cmd != null) {
|
||||
processCommand(wv, cmd)
|
||||
}
|
||||
@@ -785,7 +785,7 @@ class WebRTCInterface(private val onResponse: (WVAPIMessage) -> Unit) {
|
||||
// onResponse(message)
|
||||
onResponse(json.decodeFromString(message))
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "failed parsing WebView message: $message")
|
||||
Log.e(TAG, "failed parsing WebView message")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,6 +269,7 @@ object AppLock {
|
||||
fun elapsedRealtime(): Long = System.nanoTime() / 1_000_000
|
||||
|
||||
fun recheckAuthState() {
|
||||
if (ChatModel.showCallView.value) return
|
||||
val enteredBackgroundVal = enteredBackground.value
|
||||
val delay = ChatController.appPrefs.laLockDelay.get()
|
||||
if (enteredBackgroundVal == null || elapsedRealtime() - enteredBackgroundVal >= delay * 1000) {
|
||||
|
||||
@@ -3555,6 +3555,7 @@ data class ChatItem (
|
||||
is RcvGroupEvent.MemberCreatedContact -> false
|
||||
is RcvGroupEvent.MemberProfileUpdated -> false
|
||||
is RcvGroupEvent.NewMemberPendingReview -> true
|
||||
is RcvGroupEvent.MsgBadSignature -> false
|
||||
}
|
||||
is CIContent.SndGroupEventContent -> false
|
||||
is CIContent.RcvConnEventContent -> false
|
||||
@@ -5461,6 +5462,7 @@ sealed class RcvGroupEvent() {
|
||||
@Serializable @SerialName("memberCreatedContact") class MemberCreatedContact(): RcvGroupEvent()
|
||||
@Serializable @SerialName("memberProfileUpdated") class MemberProfileUpdated(val fromProfile: Profile, val toProfile: Profile): RcvGroupEvent()
|
||||
@Serializable @SerialName("newMemberPendingReview") class NewMemberPendingReview(): RcvGroupEvent()
|
||||
@Serializable @SerialName("msgBadSignature") class MsgBadSignature(): RcvGroupEvent()
|
||||
|
||||
val text: String get() = text(isChannel = false)
|
||||
|
||||
@@ -5485,6 +5487,7 @@ sealed class RcvGroupEvent() {
|
||||
is MemberCreatedContact -> generalGetString(MR.strings.rcv_group_event_member_created_contact)
|
||||
is MemberProfileUpdated -> profileUpdatedText(fromProfile, toProfile)
|
||||
is NewMemberPendingReview -> generalGetString(MR.strings.rcv_group_event_new_member_pending_review)
|
||||
is MsgBadSignature -> generalGetString(MR.strings.rcv_group_event_msg_bad_signature)
|
||||
}
|
||||
|
||||
private fun profileUpdatedText(from: Profile, to: Profile): String =
|
||||
|
||||
+6
-7
@@ -941,7 +941,7 @@ object ChatController {
|
||||
val r = json.decodeFromString<API>(rStr)
|
||||
if (log) {
|
||||
Log.d(TAG, "sendCmd response type ${r.responseType}")
|
||||
if (r is API.Result && (r.res is CR.Response || r.res is CR.Invalid)) {
|
||||
if (r is API.Result && ((r.res is CR.Response && !r.res.type.startsWith("call")) || r.res is CR.Invalid)) {
|
||||
Log.d(TAG, "sendCmd response json $rStr")
|
||||
}
|
||||
chatModel.addTerminalItem(TerminalItem.resp(rhId, r))
|
||||
@@ -958,7 +958,7 @@ object ChatController {
|
||||
} else {
|
||||
val r = json.decodeFromString<API>(rStr)
|
||||
Log.d(TAG, "chatRecvMsg: ${r.responseType}")
|
||||
if (r is API.Result && (r.res is CR.Response || r.res is CR.Invalid)) Log.d(TAG, "chatRecvMsg json: $rStr")
|
||||
if (r is API.Result && ((r.res is CR.Response && !r.res.type.startsWith("call")) || r.res is CR.Invalid)) Log.d(TAG, "chatRecvMsg json: $rStr")
|
||||
r
|
||||
}
|
||||
}
|
||||
@@ -3367,10 +3367,9 @@ object ChatController {
|
||||
// TODO askConfirmation?
|
||||
// TODO check encryption is compatible
|
||||
withCall(r, r.contact) { call ->
|
||||
chatModel.activeCall.value = call.copy(callState = CallState.OfferReceived, sharedKey = r.sharedKey)
|
||||
chatModel.activeCall.value = call.copy(callState = CallState.OfferReceived, hasSharedKey = r.sharedKey != null)
|
||||
val useRelay = appPrefs.webrtcPolicyRelay.get()
|
||||
val iceServers = getIceServers()
|
||||
Log.d(TAG, ".callOffer iceServers $iceServers")
|
||||
chatModel.callCommand.add(WCallCommand.Offer(
|
||||
offer = r.offer.rtcSession,
|
||||
iceCandidates = r.offer.rtcIceCandidates,
|
||||
@@ -7215,9 +7214,9 @@ sealed class CR {
|
||||
is SndStandaloneFileComplete -> withUser(user, rcvURIs.size.toString())
|
||||
is SndFileError -> withUser(user, "errorMessage: ${json.encodeToString(errorMessage)}\nchatItem: ${json.encodeToString(chatItem_)}")
|
||||
is SndFileWarning -> withUser(user, "errorMessage: ${json.encodeToString(errorMessage)}\nchatItem: ${json.encodeToString(chatItem_)}")
|
||||
is CallInvitations -> "callInvitations: ${json.encodeToString(callInvitations)}"
|
||||
is CallInvitation -> "contact: ${callInvitation.contact.id}\ncallType: $callInvitation.callType\nsharedKey: ${callInvitation.sharedKey ?: ""}"
|
||||
is CallOffer -> withUser(user, "contact: ${contact.id}\ncallType: $callType\nsharedKey: ${sharedKey ?: ""}\naskConfirmation: $askConfirmation\noffer: ${json.encodeToString(offer)}")
|
||||
is CallInvitations -> "callInvitations: ${json.encodeToString(callInvitations.map { it.copy(sharedKey = null) })}"
|
||||
is CallInvitation -> "contact: ${callInvitation.contact.id}\ncallType: ${callInvitation.callType}"
|
||||
is CallOffer -> withUser(user, "contact: ${contact.id}\ncallType: $callType\naskConfirmation: $askConfirmation\noffer: ${json.encodeToString(offer)}")
|
||||
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}")
|
||||
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
package chat.simplex.common.views.call
|
||||
|
||||
import chat.simplex.common.AppLock
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.views.helpers.withBGApi
|
||||
@@ -51,13 +52,12 @@ class CallManager(val chatModel: ChatModel) {
|
||||
callUUID = invitation.callUUID,
|
||||
callState = CallState.InvitationAccepted,
|
||||
initialCallType = invitation.callType.media,
|
||||
sharedKey = invitation.sharedKey,
|
||||
hasSharedKey = invitation.sharedKey != null,
|
||||
androidCallState = platform.androidCreateActiveCallState()
|
||||
)
|
||||
showCallView.value = true
|
||||
val useRelay = controller.appPrefs.webrtcPolicyRelay.get()
|
||||
val iceServers = getIceServers()
|
||||
Log.d(TAG, "answerIncomingCall iceServers: $iceServers")
|
||||
callCommand.add(WCallCommand.Start(
|
||||
media = invitation.callType.media,
|
||||
aesKey = invitation.sharedKey,
|
||||
@@ -79,6 +79,7 @@ class CallManager(val chatModel: ChatModel) {
|
||||
|
||||
// Don't destroy WebView if you plan to accept next call right after this one
|
||||
if (!switchingCall.value) {
|
||||
AppLock.appWasHidden()
|
||||
showCallView.value = false
|
||||
activeCall.value?.androidCallState?.close()
|
||||
activeCall.value = null
|
||||
|
||||
+4
-4
@@ -21,7 +21,7 @@ data class Call(
|
||||
val localMediaSources: CallMediaSources = CallMediaSources(mic = true, camera = initialCallType == CallMediaType.Video),
|
||||
val localCapabilities: CallCapabilities? = null,
|
||||
val peerMediaSources: CallMediaSources = CallMediaSources(),
|
||||
val sharedKey: String? = null,
|
||||
val hasSharedKey: Boolean = false,
|
||||
var localCamera: VideoCamera = VideoCamera.User,
|
||||
val connectionInfo: ConnectionInfo? = null,
|
||||
var connectedAt: Instant? = null,
|
||||
@@ -32,14 +32,14 @@ data class Call(
|
||||
|
||||
val androidCallState: Closeable
|
||||
) {
|
||||
val encrypted: Boolean get() = localEncrypted && sharedKey != null
|
||||
val encrypted: Boolean get() = localEncrypted && hasSharedKey
|
||||
private val localEncrypted: Boolean get() = localCapabilities?.encryption ?: false
|
||||
|
||||
val encryptionStatus: String get() = when(callState) {
|
||||
CallState.WaitCapabilities -> ""
|
||||
CallState.InvitationSent -> generalGetString(if (localEncrypted) MR.strings.status_e2e_encrypted else MR.strings.status_no_e2e_encryption)
|
||||
CallState.InvitationAccepted -> generalGetString(if (sharedKey == null) MR.strings.status_contact_has_no_e2e_encryption else MR.strings.status_contact_has_e2e_encryption)
|
||||
else -> generalGetString(if (!localEncrypted) MR.strings.status_no_e2e_encryption else if (sharedKey == null) MR.strings.status_contact_has_no_e2e_encryption else MR.strings.status_e2e_encrypted)
|
||||
CallState.InvitationAccepted -> generalGetString(if (!hasSharedKey) MR.strings.status_contact_has_no_e2e_encryption else MR.strings.status_contact_has_e2e_encryption)
|
||||
else -> generalGetString(if (!localEncrypted) MR.strings.status_no_e2e_encryption else if (!hasSharedKey) MR.strings.status_contact_has_no_e2e_encryption else MR.strings.status_e2e_encrypted)
|
||||
}
|
||||
|
||||
val hasVideo: Boolean
|
||||
|
||||
+4
@@ -556,12 +556,16 @@ suspend fun deleteChatAsync(m: ChatModel) {
|
||||
fun deleteChatDatabaseFilesAndState() {
|
||||
val chat = File(dataDir, chatDatabaseFileName)
|
||||
val chatBak = File(dataDir, "$chatDatabaseFileName.bak")
|
||||
val chatExported = File(dataDir, "$chatDatabaseFileName.exported")
|
||||
val agent = File(dataDir, agentDatabaseFileName)
|
||||
val agentBak = File(dataDir, "$agentDatabaseFileName.bak")
|
||||
val agentExported = File(dataDir, "$agentDatabaseFileName.exported")
|
||||
chat.delete()
|
||||
chatBak.delete()
|
||||
chatExported.delete()
|
||||
agent.delete()
|
||||
agentBak.delete()
|
||||
agentExported.delete()
|
||||
filesDir.deleteRecursively()
|
||||
filesDir.mkdir()
|
||||
remoteHostsDir.deleteRecursively()
|
||||
|
||||
@@ -1784,6 +1784,7 @@
|
||||
<string name="rcv_group_event_invited_via_your_group_link">invited via your group link</string>
|
||||
<string name="rcv_group_event_member_created_contact">requested connection</string>
|
||||
<string name="rcv_group_event_new_member_pending_review">New member wants to join the group.</string>
|
||||
<string name="rcv_group_event_msg_bad_signature">message rejected: bad signature</string>
|
||||
<string name="snd_group_event_changed_member_role">you changed role of %s to %s</string>
|
||||
<string name="snd_group_event_changed_role_for_yourself">you changed role for yourself to %s</string>
|
||||
<string name="snd_group_event_member_blocked">you blocked %s</string>
|
||||
|
||||
@@ -182,9 +182,10 @@ private fun ApplicationScope.AppWindow(closedByError: MutableState<Boolean>) {
|
||||
}
|
||||
}
|
||||
var windowFocused by remember { simplexWindowState.windowFocused }
|
||||
LaunchedEffect(windowFocused) {
|
||||
val showCallView = ChatModel.showCallView.value
|
||||
LaunchedEffect(windowFocused, showCallView) {
|
||||
val delay = ChatController.appPrefs.laLockDelay.get()
|
||||
if (!windowFocused && ChatModel.showAuthScreen.value && delay > 0) {
|
||||
if (!windowFocused && !showCallView && ChatModel.showAuthScreen.value && delay > 0) {
|
||||
delay(delay * 1000L)
|
||||
// Trigger auth state check when delay ends (and if it ends)
|
||||
AppLock.recheckAuthState()
|
||||
|
||||
+3
-3
@@ -31,7 +31,7 @@ val connections = ArrayList<WebSocket>()
|
||||
actual fun ActiveCallView() {
|
||||
val scope = rememberCoroutineScope()
|
||||
WebRTCController(chatModel.callCommand) { apiMsg ->
|
||||
Log.d(TAG, "received from WebRTCController: $apiMsg")
|
||||
Log.d(TAG, "received from WebRTCController: ${apiMsg.resp.javaClass.simpleName}")
|
||||
val call = chatModel.activeCall.value
|
||||
if (call != null) {
|
||||
Log.d(TAG, "has active call $call")
|
||||
@@ -202,7 +202,7 @@ fun WebRTCController(callCommand: SnapshotStateList<WCallCommand>, onResponse: (
|
||||
}
|
||||
while (callCommand.isNotEmpty()) {
|
||||
val cmd = callCommand.removeFirstOrNull()
|
||||
Log.d(TAG, "WebRTCController LaunchedEffect executing $cmd")
|
||||
Log.d(TAG, "WebRTCController LaunchedEffect executing ${cmd?.javaClass?.simpleName}")
|
||||
if (cmd != null) {
|
||||
processCommand(cmd)
|
||||
}
|
||||
@@ -289,7 +289,7 @@ class MyWebSocket(val onResponse: (WVAPIMessage) -> Unit, handshakeRequest: IHTT
|
||||
// onResponse(message.textPayload)
|
||||
onResponse(json.decodeFromString(message.textPayload))
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "failed parsing browser message: $message")
|
||||
Log.e(TAG, "failed parsing browser message")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user