mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-28 23:00:09 +00:00
Merge branch 'master' into master-android
This commit is contained in:
+4
-1
@@ -67,10 +67,13 @@ actual fun getKeyboardState(): State<KeyboardState> {
|
||||
return keyboardState
|
||||
}
|
||||
|
||||
actual fun hideKeyboard(view: Any?) {
|
||||
actual fun hideKeyboard(view: Any?, clearFocus: Boolean) {
|
||||
// LALAL
|
||||
// LocalSoftwareKeyboardController.current?.hide()
|
||||
if (view is View) {
|
||||
if (clearFocus) {
|
||||
view.clearFocus()
|
||||
}
|
||||
(androidAppContext.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(view.windowToken, 0)
|
||||
}
|
||||
}
|
||||
|
||||
+24
-22
@@ -64,6 +64,7 @@ class PostSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
|
||||
}
|
||||
|
||||
override fun start() {
|
||||
am.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||
am.registerAudioDeviceCallback(audioCallback, null)
|
||||
am.addOnCommunicationDeviceChangedListener(Executors.newSingleThreadExecutor(), listener)
|
||||
}
|
||||
@@ -75,7 +76,6 @@ class PostSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
|
||||
|
||||
override fun selectLastExternalDeviceOrDefault(speaker: Boolean, keepAnyNonEarpiece: Boolean) {
|
||||
Log.d(TAG, "selectLastExternalDeviceOrDefault: set audio mode, speaker enabled: $speaker")
|
||||
am.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||
val commDevice = am.communicationDevice
|
||||
if (keepAnyNonEarpiece && commDevice != null && commDevice.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) {
|
||||
// some external device or speaker selected already, no need to change it
|
||||
@@ -98,7 +98,6 @@ class PostSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
|
||||
}
|
||||
|
||||
override fun selectDevice(id: Int) {
|
||||
am.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||
val device = devices.value.lastOrNull { it.id == id }
|
||||
if (device != null && am.communicationDevice?.id != id ) {
|
||||
am.setCommunicationDevice(device)
|
||||
@@ -115,40 +114,32 @@ class PreSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
|
||||
override fun onAudioDevicesAdded(addedDevices: Array<out AudioDeviceInfo>) {
|
||||
Log.d(TAG, "Added audio devices: ${addedDevices.map { it.type }}")
|
||||
super.onAudioDevicesAdded(addedDevices)
|
||||
val wasSize = devices.value.size
|
||||
devices.value += addedDevices.filter { it.hasSupportedType() }
|
||||
val addedCount = devices.value.size - wasSize
|
||||
//if (addedCount > 0 && chatModel.activeCall.value?.callState == CallState.Connected) {
|
||||
// Setting params in Connected state makes sure that Bluetooth will NOT be broken on Android < 12
|
||||
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.supportsVideo() == true, false)
|
||||
//}
|
||||
devices.value = am.getDevices(AudioManager.GET_DEVICES_OUTPUTS).filter { it.hasSupportedType() }.excludeSameType().excludeEarpieceIfWired()
|
||||
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.supportsVideo() == true, false)
|
||||
}
|
||||
|
||||
override fun onAudioDevicesRemoved(removedDevices: Array<out AudioDeviceInfo>) {
|
||||
Log.d(TAG, "Removed audio devices: ${removedDevices.map { it.type }}")
|
||||
super.onAudioDevicesRemoved(removedDevices)
|
||||
val wasSize = devices.value.size
|
||||
devices.value = devices.value.filterNot { removedDevices.any { rm -> rm.id == it.id } }
|
||||
//val removedCount = wasSize - devices.value.size
|
||||
//if (devices.value.count { it.hasSupportedType() } == 2 && chatModel.activeCall.value?.callState == CallState.Connected) {
|
||||
// Setting params in Connected state makes sure that Bluetooth will NOT be broken on Android < 12
|
||||
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.supportsVideo() == true, true)
|
||||
//}
|
||||
devices.value = am.getDevices(AudioManager.GET_DEVICES_OUTPUTS).filter { it.hasSupportedType() }.excludeSameType().excludeEarpieceIfWired()
|
||||
selectLastExternalDeviceOrDefault(chatModel.activeCall.value?.supportsVideo() == true, true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun start() {
|
||||
am.mode = AudioManager.MODE_IN_COMMUNICATION
|
||||
am.registerAudioDeviceCallback(audioCallback, null)
|
||||
}
|
||||
|
||||
override fun stop() {
|
||||
am.unregisterAudioDeviceCallback(audioCallback)
|
||||
am.stopBluetoothSco()
|
||||
}
|
||||
|
||||
override fun selectLastExternalDeviceOrDefault(speaker: Boolean, keepAnyNonEarpiece: Boolean) {
|
||||
Log.d(TAG, "selectLastExternalDeviceOrDefault: set audio mode, speaker enabled: $speaker")
|
||||
val preferredSecondaryDevice = if (speaker) AudioDeviceInfo.TYPE_BUILTIN_SPEAKER else AudioDeviceInfo.TYPE_BUILTIN_EARPIECE
|
||||
val externalDevice = devices.value.lastOrNull { it.hasSupportedType() && it.isSource && it.isSink && it.type != AudioDeviceInfo.TYPE_BUILTIN_SPEAKER && it.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE }
|
||||
val externalDevice = devices.value.lastOrNull { it.type != AudioDeviceInfo.TYPE_BUILTIN_SPEAKER && it.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE }
|
||||
if (externalDevice != null) {
|
||||
selectDevice(externalDevice.id)
|
||||
} else {
|
||||
@@ -166,7 +157,7 @@ class PreSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
|
||||
val isExternalDevice = device != null && device.type != AudioDeviceInfo.TYPE_BUILTIN_SPEAKER && device.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE
|
||||
if (isExternalDevice) {
|
||||
am.isSpeakerphoneOn = false
|
||||
if (device?.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES) {
|
||||
if (device?.type == AudioDeviceInfo.TYPE_WIRED_HEADSET || device?.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES) {
|
||||
am.isWiredHeadsetOn = true
|
||||
am.stopBluetoothSco()
|
||||
am.isBluetoothScoOn = false
|
||||
@@ -194,11 +185,18 @@ class PreSCallAudioDeviceManager: CallAudioDeviceManagerInterface {
|
||||
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> true
|
||||
|
||||
AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> true
|
||||
AudioDeviceInfo.TYPE_BLE_HEADSET -> true
|
||||
AudioDeviceInfo.TYPE_BLE_SPEAKER -> true
|
||||
AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun List<AudioDeviceInfo>.excludeSameType(): List<AudioDeviceInfo> =
|
||||
groupBy { it.type }.flatMap { devices -> listOf(devices.value.minByOrNull { it.id }!!) }
|
||||
|
||||
// Earpiece will not work if there is a wired connection
|
||||
private fun List<AudioDeviceInfo>.excludeEarpieceIfWired(): List<AudioDeviceInfo> =
|
||||
if (any { it.type == AudioDeviceInfo.TYPE_WIRED_HEADSET || it.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES })
|
||||
filter { it.type != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE }
|
||||
else this
|
||||
}
|
||||
|
||||
val AudioDeviceInfo.icon: ImageResource
|
||||
@@ -225,11 +223,15 @@ val AudioDeviceInfo.name: StringResource?
|
||||
AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
|
||||
AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
|
||||
AudioDeviceInfo.TYPE_BLE_HEADSET,
|
||||
AudioDeviceInfo.TYPE_BLE_SPEAKER -> null // Use product name instead
|
||||
AudioDeviceInfo.TYPE_BLE_SPEAKER -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
// Use product name instead
|
||||
null
|
||||
} else {
|
||||
MR.strings.audio_device_bluetooth
|
||||
}
|
||||
|
||||
AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> MR.strings.audio_device_wired_headphones
|
||||
|
||||
AudioDeviceInfo.TYPE_USB_HEADSET, AudioDeviceInfo.TYPE_USB_DEVICE -> null // Use product name instead
|
||||
else -> null // Use product name instead
|
||||
}
|
||||
|
||||
|
||||
+15
-6
@@ -87,7 +87,9 @@ actual fun ActiveCallView() {
|
||||
}
|
||||
val callAudioDeviceManager = remember { CallAudioDeviceManagerInterface.new() }
|
||||
DisposableEffect(Unit) {
|
||||
callAudioDeviceManager.start()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
callAudioDeviceManager.start()
|
||||
}
|
||||
onDispose {
|
||||
CallSoundsPlayer.stop()
|
||||
if (wasConnected.value) {
|
||||
@@ -120,13 +122,24 @@ actual fun ActiveCallView() {
|
||||
val callType = CallType(call.localMedia, r.capabilities)
|
||||
chatModel.controller.apiSendCallInvitation(callRh, call.contact, callType)
|
||||
updateActiveCall(call) { it.copy(callState = CallState.InvitationSent, localCapabilities = r.capabilities) }
|
||||
callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||
// Starting is delayed to make Android <= 11 working good with Bluetooth
|
||||
callAudioDeviceManager.start()
|
||||
} else {
|
||||
callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
|
||||
}
|
||||
CallSoundsPlayer.startConnectingCallSound(scope)
|
||||
activeCallWaitDeliveryReceipt(scope)
|
||||
}
|
||||
is WCallResponse.Offer -> withBGApi {
|
||||
chatModel.controller.apiSendCallOffer(callRh, call.contact, r.offer, r.iceCandidates, call.localMedia, r.capabilities)
|
||||
updateActiveCall(call) { it.copy(callState = CallState.OfferSent, localCapabilities = r.capabilities) }
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||
// Starting is delayed to make Android <= 11 working good with Bluetooth
|
||||
callAudioDeviceManager.start()
|
||||
} else {
|
||||
callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
|
||||
}
|
||||
}
|
||||
is WCallResponse.Answer -> withBGApi {
|
||||
chatModel.controller.apiSendCallAnswer(callRh, call.contact, r.answer, r.iceCandidates)
|
||||
@@ -141,7 +154,6 @@ actual fun ActiveCallView() {
|
||||
val callStatus = json.decodeFromString<WebRTCCallStatus>("\"${r.state.connectionState}\"")
|
||||
if (callStatus == WebRTCCallStatus.Connected) {
|
||||
updateActiveCall(call) { it.copy(callState = CallState.Connected, connectedAt = Clock.System.now()) }
|
||||
callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
|
||||
}
|
||||
withBGApi { chatModel.controller.apiCallStatus(callRh, call.contact, callStatus) }
|
||||
} catch (e: Throwable) {
|
||||
@@ -149,9 +161,6 @@ actual fun ActiveCallView() {
|
||||
}
|
||||
is WCallResponse.Connected -> {
|
||||
updateActiveCall(call) { it.copy(callState = CallState.Connected, connectionInfo = r.connectionInfo) }
|
||||
scope.launch {
|
||||
callAudioDeviceManager.selectLastExternalDeviceOrDefault(call.soundSpeaker, true)
|
||||
}
|
||||
}
|
||||
is WCallResponse.End -> {
|
||||
withBGApi { chatModel.callManager.endCall(call) }
|
||||
|
||||
@@ -13,7 +13,7 @@ expect fun LocalMultiplatformView(): Any?
|
||||
|
||||
@Composable
|
||||
expect fun getKeyboardState(): State<KeyboardState>
|
||||
expect fun hideKeyboard(view: Any?)
|
||||
expect fun hideKeyboard(view: Any?, clearFocus: Boolean = false)
|
||||
|
||||
expect fun androidIsFinishingMainActivity(): Boolean
|
||||
|
||||
|
||||
+2
@@ -135,7 +135,9 @@ fun PasscodeView(
|
||||
if (!buttonsEnabled.value) {
|
||||
ProgressIndicator()
|
||||
}
|
||||
val view = LocalMultiplatformView()
|
||||
LaunchedEffect(Unit) {
|
||||
hideKeyboard(view, true)
|
||||
focusRequester.requestFocus()
|
||||
// Disallow to steal a focus by clicking on buttons or using Tab
|
||||
focusRequester.captureFocus()
|
||||
|
||||
+31
@@ -521,6 +521,37 @@ private val versionDescriptions: List<VersionDescription> = listOf(
|
||||
)
|
||||
)
|
||||
),
|
||||
VersionDescription(
|
||||
version = "v5.7",
|
||||
features = listOf(
|
||||
FeatureDescription(
|
||||
icon = MR.images.ic_vpn_key_filled,
|
||||
titleId = MR.strings.v5_6_quantum_resistant_encryption,
|
||||
descrId = MR.strings.v5_7_quantum_resistant_encryption_descr
|
||||
),
|
||||
FeatureDescription(
|
||||
icon = MR.images.ic_forward,
|
||||
titleId = MR.strings.v5_7_forward,
|
||||
descrId = MR.strings.v5_7_forward_descr
|
||||
),
|
||||
FeatureDescription(
|
||||
icon = MR.images.ic_music_note,
|
||||
titleId = MR.strings.v5_7_call_sounds,
|
||||
descrId = MR.strings.v5_7_call_sounds_descr
|
||||
),
|
||||
FeatureDescription(
|
||||
icon = MR.images.ic_wifi_tethering,
|
||||
titleId = MR.strings.v5_7_network,
|
||||
descrId = MR.strings.v5_7_network_descr
|
||||
),
|
||||
FeatureDescription(
|
||||
icon = MR.images.ic_translate,
|
||||
titleId = MR.strings.v5_7_new_interface_languages,
|
||||
descrId = MR.strings.whats_new_thanks_to_users_contribute_weblate,
|
||||
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
private val lastVersion = versionDescriptions.last().version
|
||||
|
||||
+1
-1
@@ -212,7 +212,7 @@ object AppearanceScope {
|
||||
"it" to "Italiano",
|
||||
"iw" to "עִברִית",
|
||||
"ja" to "日本語",
|
||||
"lt" to "Lietuvių kalba",
|
||||
"lt" to "Lietuvių",
|
||||
"nl" to "Nederlands",
|
||||
"pl" to "Polski",
|
||||
"pt-BR" to "Português, Brasil",
|
||||
|
||||
@@ -839,6 +839,7 @@
|
||||
<string name="audio_device_earpiece">Earpiece</string>
|
||||
<string name="audio_device_speaker">Speaker</string>
|
||||
<string name="audio_device_wired_headphones">Headphones</string>
|
||||
<string name="audio_device_bluetooth">Bluetooth</string>
|
||||
|
||||
<!-- SimpleXInfo -->
|
||||
<string name="next_generation_of_private_messaging">The next generation of private messaging</string>
|
||||
@@ -1764,6 +1765,14 @@
|
||||
<string name="v5_6_picture_in_picture_calls_descr">Use the app while in the call.</string>
|
||||
<string name="v5_6_safer_groups">Safer groups</string>
|
||||
<string name="v5_6_safer_groups_descr">Admins can block a member for all.</string>
|
||||
<string name="v5_7_quantum_resistant_encryption_descr">Will be enabled in direct chats!</string>
|
||||
<string name="v5_7_forward">Forward and save messages</string>
|
||||
<string name="v5_7_forward_descr">Message source remains private.</string>
|
||||
<string name="v5_7_call_sounds">In-call sounds</string>
|
||||
<string name="v5_7_call_sounds_descr">When connecting audio and video calls.</string>
|
||||
<string name="v5_7_network">Network management</string>
|
||||
<string name="v5_7_network_descr">More reliable network connection.</string>
|
||||
<string name="v5_7_new_interface_languages">Lithuanian UI</string>
|
||||
|
||||
<!-- CustomTimePicker -->
|
||||
<string name="custom_time_unit_seconds">seconds</string>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M393.814-125q-62.314 0-104.564-42.381Q247-209.762 247-272q0-62.237 42.25-104.619Q331.5-419 394-419q27.5 0 50.25 8t39.25 22.5v-418q0-11.925 8-20.213Q499.5-835 512-835h172.5q12.5 0 20.75 8.24 8.25 8.239 8.25 20.093V-733q0 12.5-8.25 20.75T684.5-704H541v432q0 62.238-42.436 104.619T393.814-125Z"/></svg>
|
||||
|
After Width: | Height: | Size: 396 B |
+1
-1
@@ -16,7 +16,7 @@ actual fun LocalMultiplatformView(): Any? = null
|
||||
|
||||
@Composable
|
||||
actual fun getKeyboardState(): State<KeyboardState> = remember { mutableStateOf(KeyboardState.Opened) }
|
||||
actual fun hideKeyboard(view: Any?) {}
|
||||
actual fun hideKeyboard(view: Any?, clearFocus: Boolean) {}
|
||||
|
||||
actual fun androidIsFinishingMainActivity(): Boolean = false
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
|
||||
source-repository-package
|
||||
type: git
|
||||
location: https://github.com/simplex-chat/simplexmq.git
|
||||
tag: fe28e02be779fb0357a7f650bd327a75f4aaab95
|
||||
tag: daa866f3331cf882f1030ae636f9e27a2498ca8b
|
||||
|
||||
source-repository-package
|
||||
type: git
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
name: simplex-chat
|
||||
version: 5.7.0.2
|
||||
version: 5.7.0.3
|
||||
#synopsis:
|
||||
#description:
|
||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"https://github.com/simplex-chat/simplexmq.git"."fe28e02be779fb0357a7f650bd327a75f4aaab95" = "1hwh0kx6ljskjx7svxpwmga79dfa2vz9qq0mwbqr6kkb9kf6qdd3";
|
||||
"https://github.com/simplex-chat/simplexmq.git"."daa866f3331cf882f1030ae636f9e27a2498ca8b" = "1bfzw8q8jgblpqh0vjvhs3ddyvgxrdpv18gy84yr6kmvssmdgs76";
|
||||
"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";
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ cabal-version: 1.12
|
||||
-- see: https://github.com/sol/hpack
|
||||
|
||||
name: simplex-chat
|
||||
version: 5.7.0.2
|
||||
version: 5.7.0.3
|
||||
category: Web, System, Services, Cryptography
|
||||
homepage: https://github.com/simplex-chat/simplex-chat#readme
|
||||
author: simplex.chat
|
||||
|
||||
Reference in New Issue
Block a user