From fc0879ebb7249bb5e6a02d1dc4f59a60c6887382 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Sat, 28 Sep 2024 04:04:16 +0700 Subject: [PATCH 1/9] android, desktop: fix Safari sound (#4947) * android, desktop: fix Safari sound * another approach * test * Revert "test" This reverts commit f89a30a88eef665b29191652b8ba4533f048b513. * Revert "another approach" This reverts commit 824ab7047c9b2c9c359bb16a6576b0cb51a9c1f6. * Revert "android, desktop: fix Safari sound" This reverts commit 80a866d4726f78c9760fb8a775dbe924a76123dd. * android, desktop: fix Safari sound * dependencies --- .../commonMain/resources/assets/www/call.js | 34 ++++++++++-------- packages/simplex-chat-webrtc/package.json | 4 +-- packages/simplex-chat-webrtc/src/call.ts | 36 +++++++++++-------- 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js b/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js index b5dcc9a2c2..97d157b762 100644 --- a/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js +++ b/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js @@ -186,6 +186,7 @@ const processCommand = (function () { localStream, localScreenStream, remoteStream, + remoteTracks: new Map(), remoteScreenStream, peerMediaSources: { mic: false, @@ -548,14 +549,6 @@ const processCommand = (function () { call.worker = new Worker(URL.createObjectURL(new Blob([workerCode], { type: "text/javascript" }))); call.worker.onerror = ({ error, filename, lineno, message }) => console.log({ error, filename, lineno, message }); // call.worker.onmessage = ({data}) => console.log(JSON.stringify({message: data})) - call.worker.onmessage = ({ data }) => { - console.log(JSON.stringify({ message: data })); - const transceiverMid = data.transceiverMid; - const mute = data.mute; - if (transceiverMid && mute != undefined) { - onMediaMuteUnmute(transceiverMid, mute); - } - }; } } } @@ -661,12 +654,7 @@ const processCommand = (function () { } setupMuteUnmuteListener(event.transceiver, track); const mediaSource = mediaSourceFromTransceiverMid(event.transceiver.mid); - if (mediaSource == CallMediaSource.ScreenAudio || mediaSource == CallMediaSource.ScreenVideo) { - call.remoteScreenStream.addTrack(track); - } - else { - call.remoteStream.addTrack(track); - } + call.remoteTracks.set(mediaSource, track); console.log(`ontrack success`); } catch (e) { @@ -1023,10 +1011,26 @@ const processCommand = (function () { if (!mute) videos.remoteScreen.play().catch((e) => console.log(e)); } + if (!mute) + addRemoteTracksWhenUnmuted(source, activeCall); localOrPeerMediaSourcesChanged(activeCall); // Make sure that remote camera and remote screen video in their places and shown/hidden based on layout type currently in use changeLayout(activeCall.layout); } + /* + When new remote tracks are coming, they don't get added to remote streams. They are stored in a map and once any of them "unmuted", + that track is added to the stream. Such workaround needed because Safari doesn't play one stream + if another one is not playing too, eg. no audio if only audio is playing while video track is present too but muted. + But we have possibility to have only one currently active track, even no active track at all. + */ + function addRemoteTracksWhenUnmuted(source, call) { + const track = call.remoteTracks.get(source); + if (track) { + const stream = source == CallMediaSource.Mic || source == CallMediaSource.Camera ? call.remoteStream : call.remoteScreenStream; + stream.addTrack(track); + call.remoteTracks.delete(source); + } + } async function getLocalMediaStream(mic, camera, facingMode) { if (!mic && !camera) return new MediaStream(); @@ -1136,7 +1140,7 @@ const processCommand = (function () { if (peerHasOldVersion) { console.log("The peer has an old version.", "Tracks size:", activeCall.remoteStream.getAudioTracks().length, activeCall.remoteStream.getVideoTracks().length); onMediaMuteUnmute("0", false); - if (activeCall.remoteStream.getVideoTracks().length > 0) { + if (activeCall.remoteStream.getVideoTracks().length > 0 || activeCall.remoteTracks.get(CallMediaSource.Camera)) { onMediaMuteUnmute("1", false); } if (activeCall.localMediaSources.camera && !activeCall.peerMediaSources.camera) { diff --git a/packages/simplex-chat-webrtc/package.json b/packages/simplex-chat-webrtc/package.json index f11ea36343..a6598b6ce7 100644 --- a/packages/simplex-chat-webrtc/package.json +++ b/packages/simplex-chat-webrtc/package.json @@ -27,7 +27,7 @@ "author": "SimpleX Chat", "license": "AGPL-3.0-or-later", "devDependencies": { - "@types/lz-string": "^1.3.34", + "@types/lz-string": "1.3.34", "husky": "^7.0.4", "isomorphic-webcrypto": "^2.3.8", "lint-staged": "^12.4.1", @@ -38,6 +38,6 @@ "**/*": "prettier --write --ignore-unknown" }, "dependencies": { - "lz-string": "^1.4.4" + "lz-string": "1.5.0" } } diff --git a/packages/simplex-chat-webrtc/src/call.ts b/packages/simplex-chat-webrtc/src/call.ts index 793bc8e5c2..cf91af07dc 100644 --- a/packages/simplex-chat-webrtc/src/call.ts +++ b/packages/simplex-chat-webrtc/src/call.ts @@ -248,7 +248,10 @@ interface Call { localCamera: VideoCamera localStream: MediaStream localScreenStream: MediaStream + // has no tracks in the beggining, see addRemoteTracksWhenUnmuted remoteStream: MediaStream + remoteTracks: Map + // has no tracks in the beggining too remoteScreenStream: MediaStream peerMediaSources: CallMediaSources aesKey?: string @@ -439,6 +442,7 @@ const processCommand = (function () { localStream, localScreenStream, remoteStream, + remoteTracks: new Map(), remoteScreenStream, peerMediaSources: { mic: false, @@ -794,14 +798,6 @@ const processCommand = (function () { call.worker = new Worker(URL.createObjectURL(new Blob([workerCode], {type: "text/javascript"}))) call.worker.onerror = ({error, filename, lineno, message}: ErrorEvent) => console.log({error, filename, lineno, message}) // call.worker.onmessage = ({data}) => console.log(JSON.stringify({message: data})) - call.worker.onmessage = ({data}) => { - console.log(JSON.stringify({message: data})) - const transceiverMid: string = data.transceiverMid - const mute: boolean = data.mute - if (transceiverMid && mute != undefined) { - onMediaMuteUnmute(transceiverMid, mute) - } - } } } } @@ -927,11 +923,7 @@ const processCommand = (function () { setupMuteUnmuteListener(event.transceiver, track) const mediaSource = mediaSourceFromTransceiverMid(event.transceiver.mid) - if (mediaSource == CallMediaSource.ScreenAudio || mediaSource == CallMediaSource.ScreenVideo) { - call.remoteScreenStream.addTrack(track) - } else { - call.remoteStream.addTrack(track) - } + call.remoteTracks.set(mediaSource, track) console.log(`ontrack success`) } catch (e) { console.log(`ontrack error: ${(e as Error).message}`) @@ -1296,11 +1288,27 @@ const processCommand = (function () { sendMessageToNative({resp: resp}) if (!mute) videos.remoteScreen.play().catch((e) => console.log(e)) } + if (!mute) addRemoteTracksWhenUnmuted(source, activeCall) localOrPeerMediaSourcesChanged(activeCall) // Make sure that remote camera and remote screen video in their places and shown/hidden based on layout type currently in use changeLayout(activeCall.layout) } + /* + When new remote tracks are coming, they don't get added to remote streams. They are stored in a map and once any of them "unmuted", + that track is added to the stream. Such workaround needed because Safari doesn't play one stream + if another one is not playing too, eg. no audio if only audio is playing while video track is present too but muted. + But we have possibility to have only one currently active track, even no active track at all. + */ + function addRemoteTracksWhenUnmuted(source: CallMediaSource, call: Call) { + const track = call.remoteTracks.get(source) + if (track) { + const stream = source == CallMediaSource.Mic || source == CallMediaSource.Camera ? call.remoteStream : call.remoteScreenStream + stream.addTrack(track) + call.remoteTracks.delete(source) + } + } + async function getLocalMediaStream(mic: boolean, camera: boolean, facingMode: VideoCamera): Promise { if (!mic && !camera) return new MediaStream() const constraints = callMediaConstraints(mic, camera, facingMode) @@ -1422,7 +1430,7 @@ const processCommand = (function () { activeCall.remoteStream.getVideoTracks().length ) onMediaMuteUnmute("0", false) - if (activeCall.remoteStream.getVideoTracks().length > 0) { + if (activeCall.remoteStream.getVideoTracks().length > 0 || activeCall.remoteTracks.get(CallMediaSource.Camera)) { onMediaMuteUnmute("1", false) } if (activeCall.localMediaSources.camera && !activeCall.peerMediaSources.camera) { From d20d444e6e488850b582c1b9ca278bf7a217516a Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Fri, 27 Sep 2024 22:29:23 +0100 Subject: [PATCH 2/9] readme: update group links --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e62fb8c8b3..c2df084477 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ You must: Messages not following these rules will be deleted, the right to send messages may be revoked, and the access to the new members to the group may be temporarily restricted, to prevent re-joining under a different name - our imperfect group moderation does not have a better solution at the moment. -You can join an English-speaking users group if you want to ask any questions: [#SimpleX users group](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2Fos8FftfoV8zjb2T89fUEjJtF7y64p5av%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAQqMgh0fw2lPhjn3PDIEfAKA_E0-gf8Hr8zzhYnDivRs%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22lBPiveK2mjfUH43SN77R0w%3D%3D%22%7D) +You can join an English-speaking users group if you want to ask any questions: [#SimpleX users group](https://simplex.chat/contact#/?v=2-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2Fos8FftfoV8zjb2T89fUEjJtF7y64p5av%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAQqMgh0fw2lPhjn3PDIEfAKA_E0-gf8Hr8zzhYnDivRs%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22lBPiveK2mjfUH43SN77R0w%3D%3D%22%7D) There is also a group [#simplex-devs](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FvYCRjIflKNMGYlfTkuHe4B40qSlQ0439%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAHNdcqNbzXZhyMoSBjT2R0-Eb1EPaLyUg3KZjn-kmM1w%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22PD20tcXjw7IpkkMCfR6HLA%3D%3D%22%7D) for developers who build on SimpleX platform: @@ -83,7 +83,7 @@ There is also a group [#simplex-devs](https://simplex.chat/contact#/?v=1-4&smp=s There are groups in other languages, that we have the apps interface translated into. These groups are for testing, and asking questions to other SimpleX Chat users: -[\#SimpleX-DE](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FkIEl7OQzcp-J6aDmjdlQbRJwqkcZE7XR%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAR16PCu02MobRmKAsjzhDWMZcWP9hS8l5AUZi-Gs8z18%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22puYPMCQt11yPUvgmI5jCiw%3D%3D%22%7D) (German-speaking), [\#SimpleX-ES](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FaJ8O1O8A8GbeoaHTo_V8dcefaCl7ouPb%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEA034qWTA3sWcTsi6aWhNf9BA34vKVCFaEBdP2R66z6Ao%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22wiZ1v_wNjLPlT-nCSB-bRA%3D%3D%22%7D) (Spanish-speaking), [\#SimpleX-FR](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FvIHQDxTor53nwnWWTy5cHNwQQAdWN5Hw%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAPdgK1eBnETmgiqEQufbUkydKBJafoRx4iRrtrC2NAGc%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%221FyUryBPza-1ZFFE80Ekbg%3D%3D%22%7D) (French-speaking), [\#SimpleX-RU](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FXZyt3hJmWsycpN7Dqve_wbrAqb6myk1R%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAMFVIoytozTEa_QXOgoZFq_oe0IwZBYKvW50trSFXzXo%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22xz05ngjA3pNIxLZ32a8Vxg%3D%3D%22%7D) (Russian-speaking), [\#SimpleX-IT](https://simplex.chat/contact#/?v=1-2&smp=smp%3A%2F%2Fu2dS9sG8nMNURyZwqASV4yROM28Er0luVTx5X1CsMrU%3D%40smp4.simplex.im%2F0weR-ZgDUl7ruOtI_8TZwEsnJP6UiImA%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAq4PSThO9Fvb5ydF48wB0yNbpzCbuQJCW3vZ9BGUfcxk%253D%26srv%3Do5vmywmrnaxalvz6wi3zicyftgio6psuvyniis6gco6bp6ekl4cqj4id.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22e-iceLA0SctC62eARgYDWg%3D%3D%22%7D) (Italian-speaking). +[\#SimpleX-DE](https://simplex.chat/contact#/?v=1-4&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FmfiivxDKWFuowXrQOp11jsY8TuP__rBL%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAiz3pKNwvKudckFYMUfgoT0s96B0jfZ7ALHAu7rtE9HQ%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22jZeJpXGrRXQJU_-MSJ_v2A%3D%3D%22%7D) (German-speaking), [\#SimpleX-ES](https://simplex.chat/contact#/?v=2-4&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FJ5ES83pJimY2BRklS8fvy_iQwIU37xra%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEA0F0STP6UqN_12_k2cjjTrIjFgBGeWhOAmbY1qlk3pnM%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22VmUU0fqmYdCRmVCyvStvHA%3D%3D%22%7D) (Spanish-speaking), [\#SimpleX-FR](https://simplex.chat/contact#/?v=2-7&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FxCHBE_6PBRMqNEpm4UQDHXb9cz-mN7dd%23%2F%3Fv%3D1-3%26dh%3DMCowBQYDK2VuAyEAetqlcM7zTCRw-iatnwCrvpJSto7lq5Yv6AsBMWv7GSM%253D%26srv%3Dbylepyau3ty4czmn77q4fglvperknl4bi2eb2fdy2bh4jxtf32kf73yd.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22foO5Xw4hhjOa_x7zET7otw%3D%3D%22%7D) (French-speaking), [\#SimpleX-RU](https://simplex.chat/contact#/?v=2-4&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FVXQTB0J2lLjYkgjWByhl6-1qmb5fgZHh%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAI6JaEWezfSwvcoTEkk6au-gkjrXR2ew2OqZYMYBvayk%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%22ORH9OEe8Duissh-hslfeVg%3D%3D%22%7D) (Russian-speaking), [\#SimpleX-IT](https://simplex.chat/contact#/?v=2-7&smp=smp%3A%2F%2Fhpq7_4gGJiilmz5Rf-CswuU5kZGkm_zOIooSw6yALRg%3D%40smp5.simplex.im%2FqpHu0psOUdYfc11yQCzSyq5JhijrBzZT%23%2F%3Fv%3D1-3%26dh%3DMCowBQYDK2VuAyEACZ_7fbwlM45wl6cGif8cY47oPQ_AMdP0ATqOYLA6zHY%253D%26srv%3Djjbyvoemxysm7qxap7m5d5m35jzv5qq6gnlv7s4rsn7tdwwmuqciwpid.onion&data=%7B%22type%22%3A%22group%22%2C%22groupLinkId%22%3A%229uRQRTir3ealdcSfB0zsrw%3D%3D%22%7D) (Italian-speaking). You can join either by opening these links in the app or by opening them in a desktop browser and scanning the QR code. From fc83bc692ae7a7983ba00db2e9573b8bf4de6e4d Mon Sep 17 00:00:00 2001 From: Diogo Date: Sat, 28 Sep 2024 18:26:43 +0100 Subject: [PATCH 3/9] android, desktop: make space on chat bubble end consistent (#4946) * android, desktop: make space on chat bubble end consistent * use non breaking spaces for reserve space * avoid first white space non breaking to not drag content down --- .../chat/simplex/common/views/chat/item/CIMetaView.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIMetaView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIMetaView.kt index 68077d31f8..4ec2a885e7 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIMetaView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/item/CIMetaView.kt @@ -125,9 +125,9 @@ fun reserveSpaceForMeta( showViaProxy: Boolean = false, showTimestamp: Boolean ): String { - val iconSpace = " " - val whiteSpace = " " - var res = iconSpace + val iconSpace = " \u00A0\u00A0\u00A0" + val whiteSpace = "\u00A0" + var res = if (showTimestamp) "" else iconSpace var space: String? = null fun appendSpace() { From ab034e626fa0ee271d72fbd65833e770dcc8e156 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Mon, 30 Sep 2024 14:53:36 +0400 Subject: [PATCH 4/9] core: update simplexmq (#4952) --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 40 +++++++++---------- apps/ios/SimpleXChat/APITypes.swift | 1 + .../chat/simplex/common/model/SimpleXAPI.kt | 1 + cabal.project | 16 +++++++- scripts/nix/sha256map.nix | 4 +- tests/ChatClient.hs | 34 ++++++++++------ tests/ChatTests/Groups.hs | 2 +- tests/ChatTests/Profiles.hs | 2 +- 8 files changed, 64 insertions(+), 36 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 9629fba1d2..1fea71f3c2 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -147,6 +147,11 @@ 6407BA83295DA85D0082BA18 /* CIInvalidJSONView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */; }; 6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */; }; 6419EC582AB97507004A607A /* CIMemberCreatedContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */; }; + 64227CFA2CAAA7C200E910A3 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64227CF52CAAA7C200E910A3 /* libgmpxx.a */; }; + 64227CFB2CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64227CF62CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a */; }; + 64227CFC2CAAA7C200E910A3 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64227CF72CAAA7C200E910A3 /* libgmp.a */; }; + 64227CFD2CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64227CF82CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a */; }; + 64227CFE2CAAA7C200E910A3 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64227CF92CAAA7C200E910A3 /* libffi.a */; }; 6432857C2925443C00FBE5C8 /* GroupPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */; }; 6440CA00288857A10062C672 /* CIEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440C9FF288857A10062C672 /* CIEventView.swift */; }; 6440CA03288AECA70062C672 /* AddGroupMembersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440CA02288AECA70062C672 /* AddGroupMembersView.swift */; }; @@ -218,11 +223,6 @@ D77B92DC2952372200A5A1CC /* SwiftyGif in Frameworks */ = {isa = PBXBuildFile; productRef = D77B92DB2952372200A5A1CC /* SwiftyGif */; }; D7F0E33929964E7E0068AF69 /* LZString in Frameworks */ = {isa = PBXBuildFile; productRef = D7F0E33829964E7E0068AF69 /* LZString */; }; E51CC1E62C62085600DB91FE /* OneHandUICard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51CC1E52C62085600DB91FE /* OneHandUICard.swift */; }; - E5D826852CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D826802CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a */; }; - E5D826862CA5F56100A9B74D /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D826812CA5F56100A9B74D /* libffi.a */; }; - E5D826872CA5F56100A9B74D /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D826822CA5F56100A9B74D /* libgmp.a */; }; - E5D826882CA5F56100A9B74D /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D826832CA5F56100A9B74D /* libgmpxx.a */; }; - E5D826892CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E5D826842CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a */; }; E5DCF8DB2C56FAC1007928CC /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; }; E5DCF9712C590272007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF96F2C590272007928CC /* Localizable.strings */; }; E5DCF9842C5902CE007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF9822C5902CE007928CC /* Localizable.strings */; }; @@ -488,6 +488,11 @@ 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIInvalidJSONView.swift; sourceTree = ""; }; 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextInvitingContactMemberView.swift; sourceTree = ""; }; 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMemberCreatedContactView.swift; sourceTree = ""; }; + 64227CF52CAAA7C200E910A3 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; + 64227CF62CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a"; sourceTree = ""; }; + 64227CF72CAAA7C200E910A3 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + 64227CF82CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a"; sourceTree = ""; }; + 64227CF92CAAA7C200E910A3 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; 6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupPreferencesView.swift; sourceTree = ""; }; 6440C9FF288857A10062C672 /* CIEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIEventView.swift; sourceTree = ""; }; 6440CA02288AECA70062C672 /* AddGroupMembersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGroupMembersView.swift; sourceTree = ""; }; @@ -558,11 +563,6 @@ D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; }; D7AA2C3429A936B400737B40 /* MediaEncryption.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; name = MediaEncryption.playground; path = Shared/MediaEncryption.playground; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; E51CC1E52C62085600DB91FE /* OneHandUICard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OneHandUICard.swift; sourceTree = ""; }; - E5D826802CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a"; sourceTree = ""; }; - E5D826812CA5F56100A9B74D /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; - E5D826822CA5F56100A9B74D /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - E5D826832CA5F56100A9B74D /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; - E5D826842CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a"; sourceTree = ""; }; E5DCF9702C590272007928CC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; E5DCF9722C590274007928CC /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = ""; }; E5DCF9732C590275007928CC /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; @@ -653,14 +653,14 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E5D826852CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a in Frameworks */, + 64227CFA2CAAA7C200E910A3 /* libgmpxx.a in Frameworks */, 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, - E5D826892CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a in Frameworks */, + 64227CFD2CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a in Frameworks */, + 64227CFE2CAAA7C200E910A3 /* libffi.a in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, - E5D826862CA5F56100A9B74D /* libffi.a in Frameworks */, - E5D826872CA5F56100A9B74D /* libgmp.a in Frameworks */, + 64227CFB2CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a in Frameworks */, + 64227CFC2CAAA7C200E910A3 /* libgmp.a in Frameworks */, CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */, - E5D826882CA5F56100A9B74D /* libgmpxx.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -737,11 +737,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - E5D826812CA5F56100A9B74D /* libffi.a */, - E5D826822CA5F56100A9B74D /* libgmp.a */, - E5D826832CA5F56100A9B74D /* libgmpxx.a */, - E5D826802CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi-ghc9.6.3.a */, - E5D826842CA5F56100A9B74D /* libHSsimplex-chat-6.1.0.4-5C0H3SCWHuhICcJbTCMAKi.a */, + 64227CF92CAAA7C200E910A3 /* libffi.a */, + 64227CF72CAAA7C200E910A3 /* libgmp.a */, + 64227CF52CAAA7C200E910A3 /* libgmpxx.a */, + 64227CF82CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a */, + 64227CF62CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a */, ); path = Libraries; sourceTree = ""; diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index b0cd62a867..96371ff0e0 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -1353,6 +1353,7 @@ public struct NetCfg: Codable, Equatable { public var sessionMode = TransportSessionMode.user public var smpProxyMode: SMPProxyMode = .unknown public var smpProxyFallback: SMPProxyFallback = .allowProtected + var smpWebPort = false public var tcpConnectTimeout: Int // microseconds public var tcpTimeout: Int // microseconds public var tcpTimeoutPerKb: Int // microseconds 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 09b0ececb0..0297536577 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 @@ -3653,6 +3653,7 @@ data class NetCfg( val sessionMode: TransportSessionMode = TransportSessionMode.User, val smpProxyMode: SMPProxyMode = SMPProxyMode.Unknown, val smpProxyFallback: SMPProxyFallback = SMPProxyFallback.AllowProtected, + val smpWebPort: Boolean = false, val tcpConnectTimeout: Long, // microseconds val tcpTimeout: Long, // microseconds val tcpTimeoutPerKb: Long, // microseconds diff --git a/cabal.project b/cabal.project index 3823a31790..ca3aaede2d 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: 03168b9fbfd8a507a5374ff3375609e705225e29 + tag: a9576935cf1967082f6d7997cce3cd6a634c4ef7 source-repository-package type: git @@ -49,3 +49,17 @@ source-repository-package type: git location: https://github.com/simplex-chat/zip.git tag: bd421c6b19cc4c465cd7af1f6f26169fb8ee1ebc + +-- waiting for published warp-tls-3.4.7 +source-repository-package + type: git + location: https://github.com/yesodweb/wai.git + tag: ec5e017d896a78e787a5acea62b37a4e677dec2e + subdir: warp-tls + +-- backported fork due http-5.0 +source-repository-package + type: git + location: https://github.com/simplex-chat/wai.git + tag: 2f6e5aa5f05ba9140ac99e195ee647b4f7d926b0 + subdir: warp diff --git a/scripts/nix/sha256map.nix b/scripts/nix/sha256map.nix index eaa7f0d129..db4e731152 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."03168b9fbfd8a507a5374ff3375609e705225e29" = "0g6xry0far2wppfxv99hqh3ckldglmpazib5l8vsvcmivcz5zww1"; + "https://github.com/simplex-chat/simplexmq.git"."a9576935cf1967082f6d7997cce3cd6a634c4ef7" = "013s1q74k5wp8x7377qqrrqwpxfybjlim90qzv6jzl8smi0613dk"; "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"; @@ -7,4 +7,6 @@ "https://github.com/simplex-chat/haskell-terminal.git"."f708b00009b54890172068f168bf98508ffcd495" = "0zmq7lmfsk8m340g47g5963yba7i88n4afa6z93sg9px5jv1mijj"; "https://github.com/simplex-chat/android-support.git"."9aa09f148089d6752ce563b14c2df1895718d806" = "0pbf2pf13v2kjzi397nr13f1h3jv0imvsq8rpiyy2qyx5vd50pqn"; "https://github.com/simplex-chat/zip.git"."bd421c6b19cc4c465cd7af1f6f26169fb8ee1ebc" = "1csqfjhvc8wb5h4kxxndmb6iw7b4ib9ff2n81hrizsmnf45a6gg0"; + "https://github.com/yesodweb/wai.git"."ec5e017d896a78e787a5acea62b37a4e677dec2e" = "1ckcpmpjfy9jiqrb52q20lj7ln4hmq9v2jk6kpkf3m68c1m9c2bx"; + "https://github.com/simplex-chat/wai.git"."2f6e5aa5f05ba9140ac99e195ee647b4f7d926b0" = "199g4rjdf1zp1fcw8nqdsyr1h36hmg424qqx03071jk7j00z7ay4"; } diff --git a/tests/ChatClient.hs b/tests/ChatClient.hs index 42c12f1c6e..9a5c9f2a92 100644 --- a/tests/ChatClient.hs +++ b/tests/ChatClient.hs @@ -52,7 +52,7 @@ import Simplex.Messaging.Protocol (srvHostnamesSMPClientVersion) import Simplex.Messaging.Server (runSMPServerBlocking) import Simplex.Messaging.Server.Env.STM import Simplex.Messaging.Transport -import Simplex.Messaging.Transport.Server (TransportServerConfig (..), defaultTransportServerConfig) +import Simplex.Messaging.Transport.Server (ServerCredentials (..), TransportServerConfig (..), defaultTransportServerConfig) import Simplex.Messaging.Version import Simplex.Messaging.Version.Internal import System.Directory (createDirectoryIfMissing, removeDirectoryRecursive) @@ -420,7 +420,7 @@ concurrentlyN_ = mapConcurrently_ id smpServerCfg :: ServerConfig smpServerCfg = ServerConfig - { transports = [(serverPort, transport @TLS)], + { transports = [(serverPort, transport @TLS, False)], tbqSize = 1, -- serverTbqSize = 1, msgQueueQuota = 16, @@ -428,23 +428,30 @@ smpServerCfg = msgIdBytes = 6, storeLogFile = Nothing, storeMsgsFile = Nothing, + storeNtfsFile = Nothing, allowNewQueues = True, -- server password is disabled as otherwise v1 tests fail newQueueBasicAuth = Nothing, -- Just "server_password", controlPortUserAuth = Nothing, controlPortAdminAuth = Nothing, messageExpiration = Just defaultMessageExpiration, + notificationExpiration = defaultNtfExpiration, inactiveClientExpiration = Just defaultInactiveClientExpiration, - caCertificateFile = "tests/fixtures/tls/ca.crt", - privateKeyFile = "tests/fixtures/tls/server.key", - certificateFile = "tests/fixtures/tls/server.crt", + smpCredentials = + ServerCredentials + { caCertificateFile = Just "tests/fixtures/tls/ca.crt", + privateKeyFile = "tests/fixtures/tls/server.key", + certificateFile = "tests/fixtures/tls/server.crt" + }, + httpCredentials = Nothing, logStatsInterval = Nothing, logStatsStartTime = 0, serverStatsLogFile = "tests/smp-server-stats.daily.log", serverStatsBackupFile = Nothing, pendingENDInterval = 500000, + ntfDeliveryInterval = 200000, smpServerVRange = supportedServerSMPRelayVRange, - transportConfig = defaultTransportServerConfig {alpn = Just supportedSMPHandshakes}, + transportConfig = defaultTransportServerConfig, smpHandshakeTimeout = 1000000, controlPort = Nothing, smpAgentCfg = defaultSMPClientAgentConfig, @@ -457,7 +464,7 @@ withSmpServer :: IO () -> IO () withSmpServer = withSmpServer' smpServerCfg withSmpServer' :: ServerConfig -> IO () -> IO () -withSmpServer' cfg = serverBracket (`runSMPServerBlocking` cfg) +withSmpServer' cfg = serverBracket (\started -> runSMPServerBlocking started cfg Nothing) xftpTestPort :: ServiceName xftpTestPort = "7002" @@ -481,16 +488,19 @@ xftpServerConfig = fileExpiration = Just defaultFileExpiration, fileTimeout = 10000000, inactiveClientExpiration = Just defaultInactiveClientExpiration, - caCertificateFile = "tests/fixtures/tls/ca.crt", - privateKeyFile = "tests/fixtures/tls/server.key", - certificateFile = "tests/fixtures/tls/server.crt", + xftpCredentials = + ServerCredentials + { caCertificateFile = Just "tests/fixtures/tls/ca.crt", + privateKeyFile = "tests/fixtures/tls/server.key", + certificateFile = "tests/fixtures/tls/server.crt" + }, xftpServerVRange = supportedFileServerVRange, logStatsInterval = Nothing, logStatsStartTime = 0, serverStatsLogFile = "tests/tmp/xftp-server-stats.daily.log", serverStatsBackupFile = Nothing, controlPort = Nothing, - transportConfig = defaultTransportServerConfig {alpn = Just supportedXFTPhandshakes}, + transportConfig = defaultTransportServerConfig, responseDelay = 0 } @@ -502,7 +512,7 @@ withXFTPServer' cfg = serverBracket ( \started -> do createDirectoryIfMissing False xftpServerFiles - runXFTPServerBlocking started cfg + runXFTPServerBlocking started cfg Nothing ) serverBracket :: (TMVar Bool -> IO ()) -> IO () -> IO () diff --git a/tests/ChatTests/Groups.hs b/tests/ChatTests/Groups.hs index c65c7b8085..1d12625cdc 100644 --- a/tests/ChatTests/Groups.hs +++ b/tests/ChatTests/Groups.hs @@ -6419,7 +6419,7 @@ testGroupMemberInactive tmp = do where serverCfg' = smpServerCfg - { transports = [("7003", transport @TLS)], + { transports = [("7003", transport @TLS, False)], msgQueueQuota = 2 } fastRetryInterval = defaultReconnectInterval {initialInterval = 50_000} -- same as in agent tests diff --git a/tests/ChatTests/Profiles.hs b/tests/ChatTests/Profiles.hs index a36eef8ca9..003fba7cfe 100644 --- a/tests/ChatTests/Profiles.hs +++ b/tests/ChatTests/Profiles.hs @@ -1689,7 +1689,7 @@ testChangePCCUserDiffSrv tmp = do where serverCfg' = smpServerCfg - { transports = [("7003", transport @TLS), ("7002", transport @TLS)], + { transports = [("7003", transport @TLS, False), ("7002", transport @TLS, False)], msgQueueQuota = 2 } From 15ca662805782ad35ce6ae2b540a53c54d050cec Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Mon, 30 Sep 2024 21:44:35 +0700 Subject: [PATCH 5/9] android, desktop: support old Android WebViews (up to 69) (#4953) * android, desktop: support old Android WebViews (up to 69) * refactor * WebView 70 * comment --- .../common/views/call/CallView.android.kt | 6 +- .../commonMain/resources/MR/base/strings.xml | 1 + .../commonMain/resources/assets/www/call.js | 50 +++++++++++++--- .../resources/assets/www/lz-string.min.js | 2 +- packages/simplex-chat-webrtc/src/call.ts | 58 ++++++++++++++++--- 5 files changed, 100 insertions(+), 17 deletions(-) diff --git a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt index e7fd11f5ac..dbcd05b3c7 100644 --- a/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt +++ b/apps/multiplatform/common/src/androidMain/kotlin/chat/simplex/common/views/call/CallView.android.kt @@ -737,7 +737,11 @@ fun WebRTCView(callCommand: SnapshotStateList, onResponse: (WVAPIM } } catch (e: Exception) { Log.e(TAG, "Error initializing WebView: ${e.stackTraceToString()}") - AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error), generalGetString(MR.strings.error_initializing_web_view).format(e.stackTraceToString())) + if (e.stackTraceToString().contains("/lib64")) { + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error), generalGetString(MR.strings.error_initializing_web_view_wrong_arch).format(e.stackTraceToString())) + } else { + AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error), generalGetString(MR.strings.error_initializing_web_view).format(e.stackTraceToString())) + } return@AndroidView View(androidAppContext) } } 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 901a0565e1..429ca4af09 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -989,6 +989,7 @@ Headphones Bluetooth Error initializing WebView. Update your system to the new version. Please contact developers.\nError: %s + Error initializing WebView. Make sure you have WebView installed and it\'s supported architecture is arm64.\nError: %s The next generation\nof private messaging diff --git a/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js b/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js index 97d157b762..665bd14a74 100644 --- a/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js +++ b/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js @@ -76,6 +76,8 @@ const processCommand = (function () { iceCandidatePoolSize: 10, encodedInsertableStreams, iceTransportPolicy: relay ? "relay" : "all", + // needed for Android WebView >= 69 && <= 72 where default was "plan-b" which is incompatible with transceivers + sdpSemantics: "unified-plan", }, iceCandidates: { delay: 750, @@ -202,7 +204,12 @@ const processCommand = (function () { localOrPeerMediaSourcesChanged(call); await setupMediaStreams(call); let connectionTimeout = setTimeout(connectionHandler, answerTimeout); - pc.addEventListener("connectionstatechange", connectionStateChange); + if (pc.connectionState) { + pc.addEventListener("connectionstatechange", connectionStateChange); + } + else { + pc.addEventListener("iceconnectionstatechange", connectionStateChange); + } return call; async function connectionStateChange() { // "failed" means the second party did not answer in time (15 sec timeout in Chrome WebView) @@ -211,26 +218,38 @@ const processCommand = (function () { connectionHandler(); } async function connectionHandler() { + var _a; sendMessageToNative({ resp: { type: "connection", state: { - connectionState: pc.connectionState, + connectionState: (_a = pc.connectionState) !== null && _a !== void 0 ? _a : (pc.iceConnectionState != "completed" && pc.iceConnectionState != "checking" + ? pc.iceConnectionState + : pc.iceConnectionState == "completed" + ? "connected" + : "connecting") /* webView 69-70 doesn't have connectionState yet */, iceConnectionState: pc.iceConnectionState, iceGatheringState: pc.iceGatheringState, signalingState: pc.signalingState, }, }, }); - if (pc.connectionState == "disconnected" || pc.connectionState == "failed") { + if (pc.connectionState == "disconnected" || + pc.connectionState == "failed" || + (!pc.connectionState && (pc.iceConnectionState == "disconnected" || pc.iceConnectionState == "failed"))) { clearConnectionTimeout(); - pc.removeEventListener("connectionstatechange", connectionStateChange); + if (pc.connectionState) { + pc.removeEventListener("connectionstatechange", connectionStateChange); + } + else { + pc.removeEventListener("iceconnectionstatechange", connectionStateChange); + } if (activeCall) { setTimeout(() => sendMessageToNative({ resp: { type: "ended" } }), 0); } endCall(); } - else if (pc.connectionState == "connected") { + else if (pc.connectionState == "connected" || (!pc.connectionState && pc.iceConnectionState == "connected")) { clearConnectionTimeout(); const stats = (await pc.getStats()); for (const stat of stats.values()) { @@ -355,7 +374,7 @@ const processCommand = (function () { activeCall = await initializeCall(getCallConfig(!!aesKey, iceServers, relay), media, aesKey); const pc = activeCall.connection; // console.log("offer remoteIceCandidates", JSON.stringify(remoteIceCandidates)) - await pc.setRemoteDescription(new RTCSessionDescription(offer)); + await pc.setRemoteDescription(new RTCSessionDescription(!webView69Or70() ? offer : adaptSdpToOldWebView(offer))); // setting up local stream only after setRemoteDescription in order to have transceivers set await setupLocalStream(false, activeCall); setupEncryptionForLocalStream(activeCall); @@ -397,7 +416,7 @@ const processCommand = (function () { const answer = parse(command.answer); const remoteIceCandidates = parse(command.iceCandidates); // console.log("answer remoteIceCandidates", JSON.stringify(remoteIceCandidates)) - await pc.setRemoteDescription(new RTCSessionDescription(answer)); + await pc.setRemoteDescription(new RTCSessionDescription(!webView69Or70() ? answer : adaptSdpToOldWebView(answer))); adaptToOldVersion(pc.getTransceivers()[2].currentDirection == "sendonly", activeCall); addIceCandidates(pc, remoteIceCandidates); addIceCandidates(pc, afterCallInitializedCandidates); @@ -934,6 +953,7 @@ const processCommand = (function () { }); } if (inboundStatsId) { + // even though MSDN site says `packetsReceived` is available in WebView 80+, in reality it's available even in 69 const packets = (_a = stats.get(inboundStatsId)) === null || _a === void 0 ? void 0 : _a.packetsReceived; if (packets <= lastPacketsReceived) { mutedSeconds++; @@ -1156,6 +1176,22 @@ const processCommand = (function () { } } } + function webView69Or70() { + return !isDesktop && (navigator.userAgent.includes("Chrome/69.") || navigator.userAgent.includes("Chrome/70.")); + } + // Adding `a=extmap-allow-mixed` causes exception on old WebViews + // https://groups.google.com/a/chromium.org/g/blink-dev/c/7z3uvp0-ZAc/m/8Z7qpp71BgAJ + function adaptSdpToOldWebView(desc) { + var _a; + const res = []; + (_a = desc.sdp) === null || _a === void 0 ? void 0 : _a.split("\n").forEach((line) => { + // Chrome has a bug related to SDP parser in old web view versions + if (!line.includes("a=extmap-allow-mixed")) { + res.push(line); + } + }); + return { sdp: res.join("\n"), type: desc.type }; + } return processCommand; })(); function toggleRemoteVideoFitFill() { diff --git a/apps/multiplatform/common/src/commonMain/resources/assets/www/lz-string.min.js b/apps/multiplatform/common/src/commonMain/resources/assets/www/lz-string.min.js index 2d1900a0d3..f7c26ae2b4 100644 --- a/apps/multiplatform/common/src/commonMain/resources/assets/www/lz-string.min.js +++ b/apps/multiplatform/common/src/commonMain/resources/assets/www/lz-string.min.js @@ -1 +1 @@ -var LZString=function(){function o(o,r){if(!t[o]){t[o]={};for(var n=0;ne;e++){var s=r.charCodeAt(e);n[2*e]=s>>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null===o||void 0===o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;t>e;e++)n[e]=256*o[2*e]+o[2*e+1];var s=[];return n.forEach(function(o){s.push(r(o))}),i.decompress(s.join(""))},compressToEncodedURIComponent:function(o){return null==o?"":i._compress(o,6,function(o){return e.charAt(o)})},decompressFromEncodedURIComponent:function(r){return null==r?"":""==r?null:(r=r.replace(/ /g,"+"),i._decompress(r.length,32,function(n){return o(e,r.charAt(n))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(o,r,n){if(null==o)return"";var e,t,i,s={},p={},u="",c="",a="",l=2,f=3,h=2,d=[],m=0,v=0;for(i=0;ie;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++),s[c]=f++,a=String(u)}if(""!==a){if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;for(;;){if(m<<=1,v==r-1){d.push(n(m));break}v++}return d.join("")},decompress:function(o){return null==o?"":""==o?null:i._decompress(o.length,32768,function(r){return o.charCodeAt(r)})},_decompress:function(o,n,e){var t,i,s,p,u,c,a,l,f=[],h=4,d=4,m=3,v="",w=[],A={val:e(0),position:n,index:1};for(i=0;3>i;i+=1)f[i]=i;for(p=0,c=Math.pow(2,2),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(t=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 2:return""}for(f[3]=l,s=l,w.push(l);;){if(A.index>o)return"";for(p=0,c=Math.pow(2,m),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(l=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 2:return w.join("")}if(0==h&&(h=Math.pow(2,m),m++),f[l])v=f[l];else{if(l!==d)return null;v=s+s.charAt(0)}w.push(v),f[d++]=s+v.charAt(0),h--,s=v,0==h&&(h=Math.pow(2,m),m++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module&&(module.exports=LZString); +var LZString=function(){var r=String.fromCharCode,o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$",e={};function t(r,o){if(!e[r]){e[r]={};for(var n=0;n>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null==o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;e>=1}else{for(t=1,e=0;e>=1}0==--l&&(l=Math.pow(2,h),h++),delete u[c]}else for(t=s[c],e=0;e>=1;0==--l&&(l=Math.pow(2,h),h++),s[p]=f++,c=String(a)}if(""!==c){if(Object.prototype.hasOwnProperty.call(u,c)){if(c.charCodeAt(0)<256){for(e=0;e>=1}else{for(t=1,e=0;e>=1}0==--l&&(l=Math.pow(2,h),h++),delete u[c]}else for(t=s[c],e=0;e>=1;0==--l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;e>=1;for(;;){if(m<<=1,v==o-1){d.push(n(m));break}v++}return d.join("")},decompress:function(r){return null==r?"":""==r?null:i._decompress(r.length,32768,function(o){return r.charCodeAt(o)})},_decompress:function(o,n,e){var t,i,s,u,a,p,c,l=[],f=4,h=4,d=3,m="",v=[],g={val:e(0),position:n,index:1};for(t=0;t<3;t+=1)l[t]=t;for(s=0,a=Math.pow(2,2),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;switch(s){case 0:for(s=0,a=Math.pow(2,8),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;c=r(s);break;case 1:for(s=0,a=Math.pow(2,16),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;c=r(s);break;case 2:return""}for(l[3]=c,i=c,v.push(c);;){if(g.index>o)return"";for(s=0,a=Math.pow(2,d),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;switch(c=s){case 0:for(s=0,a=Math.pow(2,8),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;l[h++]=r(s),c=h-1,f--;break;case 1:for(s=0,a=Math.pow(2,16),p=1;p!=a;)u=g.val&g.position,g.position>>=1,0==g.position&&(g.position=n,g.val=e(g.index++)),s|=(u>0?1:0)*p,p<<=1;l[h++]=r(s),c=h-1,f--;break;case 2:return v.join("")}if(0==f&&(f=Math.pow(2,d),d++),l[c])m=l[c];else{if(c!==h)return null;m=i+i.charAt(0)}v.push(m),l[h++]=i+m.charAt(0),i=m,0==--f&&(f=Math.pow(2,d),d++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module?module.exports=LZString:"undefined"!=typeof angular&&null!=angular&&angular.module("LZString",[]).factory("LZString",function(){return LZString}); \ No newline at end of file diff --git a/packages/simplex-chat-webrtc/src/call.ts b/packages/simplex-chat-webrtc/src/call.ts index cf91af07dc..1a83c159c1 100644 --- a/packages/simplex-chat-webrtc/src/call.ts +++ b/packages/simplex-chat-webrtc/src/call.ts @@ -311,8 +311,12 @@ const processCommand = (function () { encodedInsertableStreams: boolean } + type RTCConfigurationWithSdpSemantics = RTCConfiguration & { + sdpSemantics: string + } + interface CallConfig { - peerConnectionConfig: RTCConfigurationWithEncryption + peerConnectionConfig: RTCConfigurationWithEncryption & RTCConfigurationWithSdpSemantics iceCandidates: { delay: number extrasInterval: number @@ -334,6 +338,8 @@ const processCommand = (function () { iceCandidatePoolSize: 10, encodedInsertableStreams, iceTransportPolicy: relay ? "relay" : "all", + // needed for Android WebView >= 69 && <= 72 where default was "plan-b" which is incompatible with transceivers + sdpSemantics: "unified-plan", }, iceCandidates: { delay: 750, @@ -458,7 +464,11 @@ const processCommand = (function () { localOrPeerMediaSourcesChanged(call) await setupMediaStreams(call) let connectionTimeout: number | undefined = setTimeout(connectionHandler, answerTimeout) - pc.addEventListener("connectionstatechange", connectionStateChange) + if (pc.connectionState) { + pc.addEventListener("connectionstatechange", connectionStateChange) + } else { + pc.addEventListener("iceconnectionstatechange", connectionStateChange) + } return call async function connectionStateChange() { @@ -472,21 +482,35 @@ const processCommand = (function () { resp: { type: "connection", state: { - connectionState: pc.connectionState, + connectionState: + pc.connectionState ?? + (pc.iceConnectionState != "completed" && pc.iceConnectionState != "checking" + ? pc.iceConnectionState + : pc.iceConnectionState == "completed" + ? "connected" + : "connecting") /* webView 69-70 doesn't have connectionState yet */, iceConnectionState: pc.iceConnectionState, iceGatheringState: pc.iceGatheringState, signalingState: pc.signalingState, }, }, }) - if (pc.connectionState == "disconnected" || pc.connectionState == "failed") { + if ( + pc.connectionState == "disconnected" || + pc.connectionState == "failed" || + (!pc.connectionState && (pc.iceConnectionState == "disconnected" || pc.iceConnectionState == "failed")) + ) { clearConnectionTimeout() - pc.removeEventListener("connectionstatechange", connectionStateChange) + if (pc.connectionState) { + pc.removeEventListener("connectionstatechange", connectionStateChange) + } else { + pc.removeEventListener("iceconnectionstatechange", connectionStateChange) + } if (activeCall) { setTimeout(() => sendMessageToNative({resp: {type: "ended"}}), 0) } endCall() - } else if (pc.connectionState == "connected") { + } else if (pc.connectionState == "connected" || (!pc.connectionState && pc.iceConnectionState == "connected")) { clearConnectionTimeout() const stats = (await pc.getStats()) as Map for (const stat of stats.values()) { @@ -613,7 +637,7 @@ const processCommand = (function () { activeCall = await initializeCall(getCallConfig(!!aesKey, iceServers, relay), media, aesKey) const pc = activeCall.connection // console.log("offer remoteIceCandidates", JSON.stringify(remoteIceCandidates)) - await pc.setRemoteDescription(new RTCSessionDescription(offer)) + await pc.setRemoteDescription(new RTCSessionDescription(!webView69Or70() ? offer : adaptSdpToOldWebView(offer))) // setting up local stream only after setRemoteDescription in order to have transceivers set await setupLocalStream(false, activeCall) setupEncryptionForLocalStream(activeCall) @@ -654,7 +678,7 @@ const processCommand = (function () { const remoteIceCandidates: RTCIceCandidateInit[] = parse(command.iceCandidates) // console.log("answer remoteIceCandidates", JSON.stringify(remoteIceCandidates)) - await pc.setRemoteDescription(new RTCSessionDescription(answer)) + await pc.setRemoteDescription(new RTCSessionDescription(!webView69Or70() ? answer : adaptSdpToOldWebView(answer))) adaptToOldVersion(pc.getTransceivers()[2].currentDirection == "sendonly", activeCall!) addIceCandidates(pc, remoteIceCandidates) addIceCandidates(pc, afterCallInitializedCandidates) @@ -1219,6 +1243,7 @@ const processCommand = (function () { }) } if (inboundStatsId) { + // even though MSDN site says `packetsReceived` is available in WebView 80+, in reality it's available even in 69 const packets = (stats as any).get(inboundStatsId)?.packetsReceived if (packets <= lastPacketsReceived) { mutedSeconds++ @@ -1447,6 +1472,23 @@ const processCommand = (function () { } } + function webView69Or70(): boolean { + return !isDesktop && (navigator.userAgent.includes("Chrome/69.") || navigator.userAgent.includes("Chrome/70.")) + } + + // Adding `a=extmap-allow-mixed` causes exception on old WebViews + // https://groups.google.com/a/chromium.org/g/blink-dev/c/7z3uvp0-ZAc/m/8Z7qpp71BgAJ + function adaptSdpToOldWebView(desc: RTCSessionDescriptionInit): RTCSessionDescriptionInit { + const res: string[] = [] + desc.sdp?.split("\n").forEach((line) => { + // Chrome has a bug related to SDP parser in old web view versions + if (!line.includes("a=extmap-allow-mixed")) { + res.push(line) + } + }) + return {sdp: res.join("\n"), type: desc.type} + } + return processCommand })() From d9ad755474f1c4c112c694d658819d1e2ddbb361 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Mon, 30 Sep 2024 21:45:13 +0700 Subject: [PATCH 6/9] android, desktop: make audio call default type of call on desktop (#4954) * android, desktop: make audio call default type of call on desktop * change --- .../chat/simplex/common/views/call/WebRTC.kt | 2 +- .../simplex/common/views/chat/ChatView.kt | 49 ++++++------------- .../commonMain/resources/assets/www/call.js | 4 +- packages/simplex-chat-webrtc/src/call.ts | 4 +- 4 files changed, 19 insertions(+), 40 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/WebRTC.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/WebRTC.kt index f723306456..89883e1bf8 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/WebRTC.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/call/WebRTC.kt @@ -17,7 +17,7 @@ data class Call( val callUUID: String?, val callState: CallState, val initialCallType: CallMediaType, - val localMediaSources: CallMediaSources = CallMediaSources(mic = true, camera = initialCallType == CallMediaType.Video && appPlatform.isAndroid), + val localMediaSources: CallMediaSources = CallMediaSources(mic = true, camera = initialCallType == CallMediaType.Video), val localCapabilities: CallCapabilities? = null, val peerMediaSources: CallMediaSources = CallMediaSources(), val sharedKey: String? = null, 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 1cc81a351f..6ffd02dc60 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 @@ -779,30 +779,16 @@ fun ChatInfoToolbar( if (chatInfo is ChatInfo.Direct && chatInfo.contact.mergedPreferences.calls.enabled.forUser) { if (activeCall == null) { barButtons.add { - if (appPlatform.isAndroid) { - IconButton({ - showMenu.value = false - startCall(CallMediaType.Audio) - }, enabled = chatInfo.contact.ready && chatInfo.contact.active - ) { - Icon( - painterResource(MR.images.ic_call_500), - stringResource(MR.strings.icon_descr_audio_call).capitalize(Locale.current), - tint = if (chatInfo.contact.ready && chatInfo.contact.active) MaterialTheme.colors.primary else MaterialTheme.colors.secondary - ) - } - } else { - IconButton({ - showMenu.value = false - startCall(CallMediaType.Video) - }, enabled = chatInfo.contact.ready && chatInfo.contact.active - ) { - Icon( - painterResource(MR.images.ic_videocam), - stringResource(MR.strings.icon_descr_video_call).capitalize(Locale.current), - tint = if (chatInfo.contact.ready && chatInfo.contact.active) MaterialTheme.colors.primary else MaterialTheme.colors.secondary - ) - } + IconButton({ + showMenu.value = false + startCall(CallMediaType.Audio) + }, enabled = chatInfo.contact.ready && chatInfo.contact.active + ) { + Icon( + painterResource(MR.images.ic_call_500), + stringResource(MR.strings.icon_descr_audio_call).capitalize(Locale.current), + tint = if (chatInfo.contact.ready && chatInfo.contact.active) MaterialTheme.colors.primary else MaterialTheme.colors.secondary + ) } } } else if (activeCall?.contact?.id == chatInfo.id && appPlatform.isDesktop) { @@ -836,17 +822,10 @@ fun ChatInfoToolbar( } if (chatInfo.contact.ready && chatInfo.contact.active && activeCall == null) { menuItems.add { - if (appPlatform.isAndroid) { - ItemAction(stringResource(MR.strings.icon_descr_video_call).capitalize(Locale.current), painterResource(MR.images.ic_videocam), onClick = { - showMenu.value = false - startCall(CallMediaType.Video) - }) - } else { - ItemAction(stringResource(MR.strings.icon_descr_audio_call).capitalize(Locale.current), painterResource(MR.images.ic_call_500), onClick = { - showMenu.value = false - startCall(CallMediaType.Audio) - }) - } + ItemAction(stringResource(MR.strings.icon_descr_video_call).capitalize(Locale.current), painterResource(MR.images.ic_videocam), onClick = { + showMenu.value = false + startCall(CallMediaType.Video) + }) } } } else if (chatInfo is ChatInfo.Group && chatInfo.groupInfo.canAddMembers) { diff --git a/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js b/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js index 665bd14a74..f042859270 100644 --- a/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js +++ b/apps/multiplatform/common/src/commonMain/resources/assets/www/call.js @@ -296,7 +296,7 @@ const processCommand = (function () { endCall(); let localStream = null; try { - localStream = await getLocalMediaStream(true, command.media == CallMediaType.Video && !isDesktop, VideoCamera.User); + localStream = await getLocalMediaStream(true, command.media == CallMediaType.Video, VideoCamera.User); const videos = getVideoElements(); if (videos) { videos.local.srcObject = localStream; @@ -325,7 +325,7 @@ const processCommand = (function () { if (activeCall) endCall(); inactiveCallMediaSources.mic = true; - inactiveCallMediaSources.camera = command.media == CallMediaType.Video && !isDesktop; + inactiveCallMediaSources.camera = command.media == CallMediaType.Video; inactiveCallMediaSourcesChanged(inactiveCallMediaSources); const { media, iceServers, relay } = command; const encryption = supportsInsertableStreams(useWorker); diff --git a/packages/simplex-chat-webrtc/src/call.ts b/packages/simplex-chat-webrtc/src/call.ts index 1a83c159c1..f27c87b870 100644 --- a/packages/simplex-chat-webrtc/src/call.ts +++ b/packages/simplex-chat-webrtc/src/call.ts @@ -560,7 +560,7 @@ const processCommand = (function () { let localStream: MediaStream | null = null try { - localStream = await getLocalMediaStream(true, command.media == CallMediaType.Video && !isDesktop, VideoCamera.User) + localStream = await getLocalMediaStream(true, command.media == CallMediaType.Video, VideoCamera.User) const videos = getVideoElements() if (videos) { videos.local.srcObject = localStream @@ -588,7 +588,7 @@ const processCommand = (function () { if (activeCall) endCall() inactiveCallMediaSources.mic = true - inactiveCallMediaSources.camera = command.media == CallMediaType.Video && !isDesktop + inactiveCallMediaSources.camera = command.media == CallMediaType.Video inactiveCallMediaSourcesChanged(inactiveCallMediaSources) const {media, iceServers, relay} = command From 533d0e40accb2b9fc50b6243e70cfeac02f21a99 Mon Sep 17 00:00:00 2001 From: Diogo Date: Mon, 30 Sep 2024 15:45:32 +0100 Subject: [PATCH 7/9] android, desktop: add floating date separator to chatview (#4951) * android, desktop: add floating date separator to chatview * closer near bottom * uncessary code * same pill bg as other btns * space * varname * safe get for lastVisibleItem * move floating date outside of floating buttons * fast cleanup on chat change * reduced recomposes * change delay position * base near bottom offset on viewport size * refactor * Revert "change delay position" This reverts commit 27b19580edd211f216f6b7e7cc2504bbc45027d5. * simplified * exact match on header position * reduce recomposes --------- Co-authored-by: Avently <7953703+avently@users.noreply.github.com> --- .../simplex/common/views/chat/ChatView.kt | 111 +++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) 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 6ffd02dc60..2ba4316b0f 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.material.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.* +import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawWithCache import androidx.compose.ui.graphics.* import androidx.compose.ui.layout.layoutId @@ -1250,6 +1251,12 @@ fun BoxWithConstraintsScope.ChatItemsList( } } FloatingButtons(chatModel.chatItems, unreadCount, remoteHostId, chatInfo, searchValue, markRead, setFloatingButton, listState) + + FloatingDate( + Modifier.padding(top = 10.dp).align(Alignment.TopCenter), + listState, + ) + LaunchedEffect(Unit) { snapshotFlow { listState.isScrollInProgress } .collect { @@ -1476,6 +1483,108 @@ private fun TopEndFloatingButton( } } +@Composable +private fun FloatingDate( + modifier: Modifier, + listState: LazyListState, +) { + var nearBottomIndex by remember { mutableStateOf(-1) } + var isNearBottom by remember { mutableStateOf(true) } + val lastVisibleItemDate = remember { + derivedStateOf { + if (listState.layoutInfo.visibleItemsInfo.lastIndex >= 0 && listState.firstVisibleItemIndex >= 0) { + val lastVisibleChatItemIndex = chatModel.chatItems.value.lastIndex - listState.firstVisibleItemIndex - listState.layoutInfo.visibleItemsInfo.lastIndex + val item = chatModel.chatItems.value.getOrNull(lastVisibleChatItemIndex) + val timeZone = TimeZone.currentSystemDefault() + item?.meta?.itemTs?.toLocalDateTime(timeZone)?.date?.atStartOfDayIn(timeZone) + } else { + null + } + } + } + val showDate = remember { mutableStateOf(false) } + LaunchedEffect(Unit) { + launch { + snapshotFlow { chatModel.chatId.value } + .distinctUntilChanged() + .collect { + showDate.value = false + isNearBottom = true + nearBottomIndex = -1 + } + } + } + + LaunchedEffect(Unit) { + snapshotFlow { listState.layoutInfo.visibleItemsInfo } + .collect { visibleItemsInfo -> + if (visibleItemsInfo.find { it.index == 0 } != null) { + var elapsedOffset = 0 + + for (it in visibleItemsInfo) { + if (elapsedOffset >= listState.layoutInfo.viewportSize.height / 2.5) { + nearBottomIndex = it.index + break; + } + elapsedOffset += it.size + } + } + + isNearBottom = if (nearBottomIndex == -1) true else (visibleItemsInfo.firstOrNull()?.index ?: 0) <= nearBottomIndex + } + } + + fun setDateVisibility(isVisible: Boolean) { + if (isVisible) { + val now = Clock.System.now() + val date = lastVisibleItemDate.value + if (!isNearBottom && !showDate.value && date != null && getTimestampDateText(date) != getTimestampDateText(now)) { + showDate.value = true + } + } else if (showDate.value) { + showDate.value = false + } + } + + LaunchedEffect(Unit) { + var hideDateWhenNotScrolling: Job = Job() + snapshotFlow { listState.firstVisibleItemScrollOffset } + .collect { + setDateVisibility(true) + hideDateWhenNotScrolling.cancel() + hideDateWhenNotScrolling = launch { + delay(1000) + setDateVisibility(false) + } + } + } + + AnimatedVisibility( + modifier = modifier, + visible = showDate.value, + enter = fadeIn(tween(durationMillis = 350)), + exit = fadeOut(tween(durationMillis = 350)) + ) { + val date = lastVisibleItemDate.value + Column { + Text( + text = if (date != null) getTimestampDateText(date) else "", + Modifier + .background( + color = MaterialTheme.colors.secondaryVariant, + RoundedCornerShape(25.dp) + ) + .padding(vertical = 4.dp, horizontal = 8.dp) + .clip(RoundedCornerShape(25.dp)), + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + textAlign = TextAlign.Center, + color = MaterialTheme.colors.secondary + ) + } + } +} + @Composable private fun DownloadFilesButton( forwardConfirmation: ForwardConfirmation.FilesNotAccepted, @@ -1539,7 +1648,7 @@ private fun ButtonRow(horizontalArrangement: Arrangement.Horizontal, content: @C private fun DateSeparator(date: Instant) { Text( text = getTimestampDateText(date), - Modifier.padding(DEFAULT_PADDING).fillMaxWidth(), + Modifier.padding(vertical = DEFAULT_PADDING_HALF + 4.dp, horizontal = DEFAULT_PADDING_HALF).fillMaxWidth(), fontSize = 14.sp, fontWeight = FontWeight.Medium, textAlign = TextAlign.Center, From cc9b4f3bb3cc7c79bb6a2119cc0cb51aaa484963 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Mon, 30 Sep 2024 18:29:20 +0100 Subject: [PATCH 8/9] core: 6.1.0.5 (simplexmq: 6.1.0.3) --- cabal.project | 2 +- package.yaml | 2 +- scripts/nix/sha256map.nix | 2 +- simplex-chat.cabal | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cabal.project b/cabal.project index ca3aaede2d..5a732f84d5 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: a9576935cf1967082f6d7997cce3cd6a634c4ef7 + tag: da79d544cf990fb0638ae5434407d6a30724fb87 source-repository-package type: git diff --git a/package.yaml b/package.yaml index edeb47ce27..edfbd98134 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: simplex-chat -version: 6.1.0.4 +version: 6.1.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 db4e731152..928a9e3c8e 100644 --- a/scripts/nix/sha256map.nix +++ b/scripts/nix/sha256map.nix @@ -1,5 +1,5 @@ { - "https://github.com/simplex-chat/simplexmq.git"."a9576935cf1967082f6d7997cce3cd6a634c4ef7" = "013s1q74k5wp8x7377qqrrqwpxfybjlim90qzv6jzl8smi0613dk"; + "https://github.com/simplex-chat/simplexmq.git"."da79d544cf990fb0638ae5434407d6a30724fb87" = "11rxpcg2g781rbr5d20fw6zpv81q06w3c9bh6qh5cpnza230yvl3"; "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 2386128bb6..5c943df73e 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: 6.1.0.4 +version: 6.1.0.5 category: Web, System, Services, Cryptography homepage: https://github.com/simplex-chat/simplex-chat#readme author: simplex.chat From dc1106afadcc496caaad2dd41623df3ce10c720b Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Mon, 30 Sep 2024 19:56:09 +0100 Subject: [PATCH 9/9] ios: update core library --- apps/ios/SimpleX.xcodeproj/project.pbxproj | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 1fea71f3c2..7a1491f408 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -147,11 +147,6 @@ 6407BA83295DA85D0082BA18 /* CIInvalidJSONView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */; }; 6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */; }; 6419EC582AB97507004A607A /* CIMemberCreatedContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */; }; - 64227CFA2CAAA7C200E910A3 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64227CF52CAAA7C200E910A3 /* libgmpxx.a */; }; - 64227CFB2CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64227CF62CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a */; }; - 64227CFC2CAAA7C200E910A3 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64227CF72CAAA7C200E910A3 /* libgmp.a */; }; - 64227CFD2CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64227CF82CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a */; }; - 64227CFE2CAAA7C200E910A3 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64227CF92CAAA7C200E910A3 /* libffi.a */; }; 6432857C2925443C00FBE5C8 /* GroupPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */; }; 6440CA00288857A10062C672 /* CIEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440C9FF288857A10062C672 /* CIEventView.swift */; }; 6440CA03288AECA70062C672 /* AddGroupMembersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6440CA02288AECA70062C672 /* AddGroupMembersView.swift */; }; @@ -222,6 +217,11 @@ D741547A29AF90B00022400A /* PushKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D741547929AF90B00022400A /* PushKit.framework */; }; D77B92DC2952372200A5A1CC /* SwiftyGif in Frameworks */ = {isa = PBXBuildFile; productRef = D77B92DB2952372200A5A1CC /* SwiftyGif */; }; D7F0E33929964E7E0068AF69 /* LZString in Frameworks */ = {isa = PBXBuildFile; productRef = D7F0E33829964E7E0068AF69 /* LZString */; }; + E51B923B2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */; }; + E51B923C2CAB2B8800C212F2 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92372CAB2B8800C212F2 /* libgmp.a */; }; + E51B923D2CAB2B8800C212F2 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92382CAB2B8800C212F2 /* libffi.a */; }; + E51B923E2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */; }; + E51B923F2CAB2B8800C212F2 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E51B923A2CAB2B8800C212F2 /* libgmpxx.a */; }; E51CC1E62C62085600DB91FE /* OneHandUICard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51CC1E52C62085600DB91FE /* OneHandUICard.swift */; }; E5DCF8DB2C56FAC1007928CC /* SimpleXChat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CE2BA682845308900EC33A6 /* SimpleXChat.framework */; }; E5DCF9712C590272007928CC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E5DCF96F2C590272007928CC /* Localizable.strings */; }; @@ -488,11 +488,6 @@ 6407BA82295DA85D0082BA18 /* CIInvalidJSONView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIInvalidJSONView.swift; sourceTree = ""; }; 6419EC552AB8BC8B004A607A /* ContextInvitingContactMemberView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextInvitingContactMemberView.swift; sourceTree = ""; }; 6419EC572AB97507004A607A /* CIMemberCreatedContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMemberCreatedContactView.swift; sourceTree = ""; }; - 64227CF52CAAA7C200E910A3 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; - 64227CF62CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a"; sourceTree = ""; }; - 64227CF72CAAA7C200E910A3 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; - 64227CF82CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a"; sourceTree = ""; }; - 64227CF92CAAA7C200E910A3 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; 6432857B2925443C00FBE5C8 /* GroupPreferencesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupPreferencesView.swift; sourceTree = ""; }; 6440C9FF288857A10062C672 /* CIEventView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIEventView.swift; sourceTree = ""; }; 6440CA02288AECA70062C672 /* AddGroupMembersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddGroupMembersView.swift; sourceTree = ""; }; @@ -562,6 +557,11 @@ D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; }; D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; }; D7AA2C3429A936B400737B40 /* MediaEncryption.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; name = MediaEncryption.playground; path = Shared/MediaEncryption.playground; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a"; sourceTree = ""; }; + E51B92372CAB2B8800C212F2 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = ""; }; + E51B92382CAB2B8800C212F2 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = ""; }; + E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a"; sourceTree = ""; }; + E51B923A2CAB2B8800C212F2 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = ""; }; E51CC1E52C62085600DB91FE /* OneHandUICard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OneHandUICard.swift; sourceTree = ""; }; E5DCF9702C590272007928CC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; E5DCF9722C590274007928CC /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = ""; }; @@ -653,14 +653,14 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 64227CFA2CAAA7C200E910A3 /* libgmpxx.a in Frameworks */, + E51B923B2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a in Frameworks */, + E51B923D2CAB2B8800C212F2 /* libffi.a in Frameworks */, + E51B923C2CAB2B8800C212F2 /* libgmp.a in Frameworks */, 5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */, - 64227CFD2CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a in Frameworks */, - 64227CFE2CAAA7C200E910A3 /* libffi.a in Frameworks */, + E51B923F2CAB2B8800C212F2 /* libgmpxx.a in Frameworks */, 5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */, - 64227CFB2CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a in Frameworks */, - 64227CFC2CAAA7C200E910A3 /* libgmp.a in Frameworks */, CE38A29C2C3FCD72005ED185 /* SwiftyGif in Frameworks */, + E51B923E2CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -737,11 +737,11 @@ 5C764E5C279C70B7000C6508 /* Libraries */ = { isa = PBXGroup; children = ( - 64227CF92CAAA7C200E910A3 /* libffi.a */, - 64227CF72CAAA7C200E910A3 /* libgmp.a */, - 64227CF52CAAA7C200E910A3 /* libgmpxx.a */, - 64227CF82CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN-ghc9.6.3.a */, - 64227CF62CAAA7C200E910A3 /* libHSsimplex-chat-6.1.0.4-8Sjoh2YTHoMJcEgF7NicnN.a */, + E51B92382CAB2B8800C212F2 /* libffi.a */, + E51B92372CAB2B8800C212F2 /* libgmp.a */, + E51B923A2CAB2B8800C212F2 /* libgmpxx.a */, + E51B92392CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU-ghc9.6.3.a */, + E51B92362CAB2B8800C212F2 /* libHSsimplex-chat-6.1.0.5-HWShuJBYoppEOt1hLB8GPU.a */, ); path = Libraries; sourceTree = "";