mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-06-29 04:39:53 +00:00
mobile: call settings, request camera on iOS on call start (#701)
* mobile: call settings, request camera on iOS on call start * refactor preferences * fix typo
This commit is contained in:
parent
79d9e90ab7
commit
da13e6614b
28 changed files with 686 additions and 513 deletions
5
apps/android/.idea/codeStyles/Project.xml
generated
5
apps/android/.idea/codeStyles/Project.xml
generated
|
@ -1,5 +1,8 @@
|
||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
|
<ComposeCustomCodeStyleSettings>
|
||||||
|
<option name="USE_CUSTOM_FORMATTING_FOR_MODIFIERS" value="false" />
|
||||||
|
</ComposeCustomCodeStyleSettings>
|
||||||
<JetCodeStyleSettings>
|
<JetCodeStyleSettings>
|
||||||
<option name="SPACE_BEFORE_EXTEND_COLON" value="false" />
|
<option name="SPACE_BEFORE_EXTEND_COLON" value="false" />
|
||||||
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="3" />
|
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="3" />
|
||||||
|
@ -123,9 +126,11 @@
|
||||||
<codeStyleSettings language="kotlin">
|
<codeStyleSettings language="kotlin">
|
||||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
<option name="RIGHT_MARGIN" value="140" />
|
<option name="RIGHT_MARGIN" value="140" />
|
||||||
|
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
||||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="1" />
|
||||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="0" />
|
<option name="KEEP_BLANK_LINES_IN_CODE" value="0" />
|
||||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
|
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
|
||||||
|
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||||
<option name="CALL_PARAMETERS_WRAP" value="0" />
|
<option name="CALL_PARAMETERS_WRAP" value="0" />
|
||||||
<option name="METHOD_PARAMETERS_WRAP" value="0" />
|
<option name="METHOD_PARAMETERS_WRAP" value="0" />
|
||||||
<option name="EXTENDS_LIST_WRAP" value="0" />
|
<option name="EXTENDS_LIST_WRAP" value="0" />
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<state>
|
<state>
|
||||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
|
||||||
</state>
|
</state>
|
||||||
</component>
|
</component>
|
|
@ -96,8 +96,7 @@ const processCommand = (function () {
|
||||||
const pc = new RTCPeerConnection(config.peerConnectionConfig);
|
const pc = new RTCPeerConnection(config.peerConnectionConfig);
|
||||||
const remoteStream = new MediaStream();
|
const remoteStream = new MediaStream();
|
||||||
const localCamera = VideoCamera.User;
|
const localCamera = VideoCamera.User;
|
||||||
const constraints = callMediaConstraints(mediaType, localCamera);
|
const localStream = await getLocalMediaStream(mediaType, localCamera);
|
||||||
const localStream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
||||||
const iceCandidates = getIceCandidates(pc, config);
|
const iceCandidates = getIceCandidates(pc, config);
|
||||||
const call = { connection: pc, iceCandidates, localMedia: mediaType, localCamera, localStream, remoteStream, aesKey, useWorker };
|
const call = { connection: pc, iceCandidates, localMedia: mediaType, localCamera, localStream, remoteStream, aesKey, useWorker };
|
||||||
await setupMediaStreams(call);
|
await setupMediaStreams(call);
|
||||||
|
@ -156,11 +155,17 @@ const processCommand = (function () {
|
||||||
try {
|
try {
|
||||||
switch (command.type) {
|
switch (command.type) {
|
||||||
case "capabilities":
|
case "capabilities":
|
||||||
|
console.log("starting outgoing call - capabilities");
|
||||||
|
if (activeCall)
|
||||||
|
endCall();
|
||||||
|
// This request for local media stream is made to prompt for camera/mic permissions on call start
|
||||||
|
if (command.media)
|
||||||
|
await getLocalMediaStream(command.media, VideoCamera.User);
|
||||||
const encryption = supportsInsertableStreams(command.useWorker);
|
const encryption = supportsInsertableStreams(command.useWorker);
|
||||||
resp = { type: "capabilities", capabilities: { encryption } };
|
resp = { type: "capabilities", capabilities: { encryption } };
|
||||||
break;
|
break;
|
||||||
case "start": {
|
case "start": {
|
||||||
console.log("starting call");
|
console.log("starting incoming call - create webrtc session");
|
||||||
if (activeCall)
|
if (activeCall)
|
||||||
endCall();
|
endCall();
|
||||||
const { media, useWorker, iceServers, relay } = command;
|
const { media, useWorker, iceServers, relay } = command;
|
||||||
|
@ -394,8 +399,7 @@ const processCommand = (function () {
|
||||||
for (const t of call.localStream.getTracks())
|
for (const t of call.localStream.getTracks())
|
||||||
t.stop();
|
t.stop();
|
||||||
call.localCamera = camera;
|
call.localCamera = camera;
|
||||||
const constraints = callMediaConstraints(call.localMedia, camera);
|
const localStream = await getLocalMediaStream(call.localMedia, camera);
|
||||||
const localStream = await navigator.mediaDevices.getUserMedia(constraints);
|
|
||||||
replaceTracks(pc, localStream.getVideoTracks());
|
replaceTracks(pc, localStream.getVideoTracks());
|
||||||
replaceTracks(pc, localStream.getAudioTracks());
|
replaceTracks(pc, localStream.getAudioTracks());
|
||||||
call.localStream = localStream;
|
call.localStream = localStream;
|
||||||
|
@ -430,6 +434,10 @@ const processCommand = (function () {
|
||||||
console.log(`no ${operation}`);
|
console.log(`no ${operation}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function getLocalMediaStream(mediaType, facingMode) {
|
||||||
|
const constraints = callMediaConstraints(mediaType, facingMode);
|
||||||
|
return navigator.mediaDevices.getUserMedia(constraints);
|
||||||
|
}
|
||||||
function callMediaConstraints(mediaType, facingMode) {
|
function callMediaConstraints(mediaType, facingMode) {
|
||||||
switch (mediaType) {
|
switch (mediaType) {
|
||||||
case CallMediaType.Audio:
|
case CallMediaType.Audio:
|
||||||
|
|
|
@ -72,7 +72,7 @@ class MainActivity: FragmentActivity(), LifecycleEventObserver {
|
||||||
val m = vm.chatModel
|
val m = vm.chatModel
|
||||||
val lastLAVal = lastLA.value
|
val lastLAVal = lastLA.value
|
||||||
if (
|
if (
|
||||||
m.controller.getPerformLA()
|
m.controller.prefPerformLA.get()
|
||||||
&& (lastLAVal == null || (System.nanoTime() - lastLAVal >= 30 * 1e+9))
|
&& (lastLAVal == null || (System.nanoTime() - lastLAVal >= 30 * 1e+9))
|
||||||
) {
|
) {
|
||||||
userAuthorized.value = false
|
userAuthorized.value = false
|
||||||
|
@ -91,7 +91,7 @@ class MainActivity: FragmentActivity(), LifecycleEventObserver {
|
||||||
LAResult.Unavailable -> {
|
LAResult.Unavailable -> {
|
||||||
userAuthorized.value = true
|
userAuthorized.value = true
|
||||||
m.performLA.value = false
|
m.performLA.value = false
|
||||||
m.controller.setPerformLA(false)
|
m.controller.prefPerformLA.set(false)
|
||||||
laUnavailableTurningOffAlert()
|
laUnavailableTurningOffAlert()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,13 +106,13 @@ class MainActivity: FragmentActivity(), LifecycleEventObserver {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun schedulePeriodicServiceRestartWorker() {
|
private fun schedulePeriodicServiceRestartWorker() {
|
||||||
val workerVersion = chatController.getAutoRestartWorkerVersion()
|
val workerVersion = chatController.prefAutoRestartWorkerVersion.get()
|
||||||
val workPolicy = if (workerVersion == SimplexService.SERVICE_START_WORKER_VERSION) {
|
val workPolicy = if (workerVersion == SimplexService.SERVICE_START_WORKER_VERSION) {
|
||||||
Log.d(TAG, "ServiceStartWorker version matches: choosing KEEP as existing work policy")
|
Log.d(TAG, "ServiceStartWorker version matches: choosing KEEP as existing work policy")
|
||||||
ExistingPeriodicWorkPolicy.KEEP
|
ExistingPeriodicWorkPolicy.KEEP
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "ServiceStartWorker version DOES NOT MATCH: choosing REPLACE as existing work policy")
|
Log.d(TAG, "ServiceStartWorker version DOES NOT MATCH: choosing REPLACE as existing work policy")
|
||||||
chatController.setAutoRestartWorkerVersion(SimplexService.SERVICE_START_WORKER_VERSION)
|
chatController.prefAutoRestartWorkerVersion.set(SimplexService.SERVICE_START_WORKER_VERSION)
|
||||||
ExistingPeriodicWorkPolicy.REPLACE
|
ExistingPeriodicWorkPolicy.REPLACE
|
||||||
}
|
}
|
||||||
val work = PeriodicWorkRequestBuilder<SimplexService.ServiceStartWorker>(SimplexService.SERVICE_START_WORKER_INTERVAL_MINUTES, TimeUnit.MINUTES)
|
val work = PeriodicWorkRequestBuilder<SimplexService.ServiceStartWorker>(SimplexService.SERVICE_START_WORKER_INTERVAL_MINUTES, TimeUnit.MINUTES)
|
||||||
|
@ -126,7 +126,7 @@ class MainActivity: FragmentActivity(), LifecycleEventObserver {
|
||||||
private fun setPerformLA(on: Boolean) {
|
private fun setPerformLA(on: Boolean) {
|
||||||
val m = vm.chatModel
|
val m = vm.chatModel
|
||||||
if (on) {
|
if (on) {
|
||||||
m.controller.setLANoticeShown(true)
|
m.controller.prefLANoticeShown.set(true)
|
||||||
authenticate(
|
authenticate(
|
||||||
generalGetString(R.string.auth_enable),
|
generalGetString(R.string.auth_enable),
|
||||||
generalGetString(R.string.auth_confirm_credential),
|
generalGetString(R.string.auth_confirm_credential),
|
||||||
|
@ -135,24 +135,24 @@ class MainActivity: FragmentActivity(), LifecycleEventObserver {
|
||||||
when (laResult) {
|
when (laResult) {
|
||||||
LAResult.Success -> {
|
LAResult.Success -> {
|
||||||
m.performLA.value = true
|
m.performLA.value = true
|
||||||
m.controller.setPerformLA(true)
|
m.controller.prefPerformLA.set(true)
|
||||||
userAuthorized.value = true
|
userAuthorized.value = true
|
||||||
lastLA.value = System.nanoTime()
|
lastLA.value = System.nanoTime()
|
||||||
laTurnedOnAlert()
|
laTurnedOnAlert()
|
||||||
}
|
}
|
||||||
is LAResult.Error -> {
|
is LAResult.Error -> {
|
||||||
m.performLA.value = false
|
m.performLA.value = false
|
||||||
m.controller.setPerformLA(false)
|
m.controller.prefPerformLA.set(false)
|
||||||
laErrorToast(applicationContext, laResult.errString)
|
laErrorToast(applicationContext, laResult.errString)
|
||||||
}
|
}
|
||||||
LAResult.Failed -> {
|
LAResult.Failed -> {
|
||||||
m.performLA.value = false
|
m.performLA.value = false
|
||||||
m.controller.setPerformLA(false)
|
m.controller.prefPerformLA.set(false)
|
||||||
laFailedToast(applicationContext)
|
laFailedToast(applicationContext)
|
||||||
}
|
}
|
||||||
LAResult.Unavailable -> {
|
LAResult.Unavailable -> {
|
||||||
m.performLA.value = false
|
m.performLA.value = false
|
||||||
m.controller.setPerformLA(false)
|
m.controller.prefPerformLA.set(false)
|
||||||
laUnavailableInstructionAlert()
|
laUnavailableInstructionAlert()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,21 +167,21 @@ class MainActivity: FragmentActivity(), LifecycleEventObserver {
|
||||||
when (laResult) {
|
when (laResult) {
|
||||||
LAResult.Success -> {
|
LAResult.Success -> {
|
||||||
m.performLA.value = false
|
m.performLA.value = false
|
||||||
m.controller.setPerformLA(false)
|
m.controller.prefPerformLA.set(false)
|
||||||
}
|
}
|
||||||
is LAResult.Error -> {
|
is LAResult.Error -> {
|
||||||
m.performLA.value = true
|
m.performLA.value = true
|
||||||
m.controller.setPerformLA(true)
|
m.controller.prefPerformLA.set(true)
|
||||||
laErrorToast(applicationContext, laResult.errString)
|
laErrorToast(applicationContext, laResult.errString)
|
||||||
}
|
}
|
||||||
LAResult.Failed -> {
|
LAResult.Failed -> {
|
||||||
m.performLA.value = true
|
m.performLA.value = true
|
||||||
m.controller.setPerformLA(true)
|
m.controller.prefPerformLA.set(true)
|
||||||
laFailedToast(applicationContext)
|
laFailedToast(applicationContext)
|
||||||
}
|
}
|
||||||
LAResult.Unavailable -> {
|
LAResult.Unavailable -> {
|
||||||
m.performLA.value = false
|
m.performLA.value = false
|
||||||
m.controller.setPerformLA(false)
|
m.controller.prefPerformLA.set(false)
|
||||||
laUnavailableTurningOffAlert()
|
laUnavailableTurningOffAlert()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ fun MainPage(
|
||||||
var showAdvertiseLAAlert by remember { mutableStateOf(false) }
|
var showAdvertiseLAAlert by remember { mutableStateOf(false) }
|
||||||
LaunchedEffect(showAdvertiseLAAlert) {
|
LaunchedEffect(showAdvertiseLAAlert) {
|
||||||
if (
|
if (
|
||||||
!chatModel.controller.getLANoticeShown()
|
!chatModel.controller.prefLANoticeShown.get()
|
||||||
&& showAdvertiseLAAlert
|
&& showAdvertiseLAAlert
|
||||||
&& chatModel.onboardingStage.value == OnboardingStage.OnboardingComplete
|
&& chatModel.onboardingStage.value == OnboardingStage.OnboardingComplete
|
||||||
&& chatModel.chats.isNotEmpty()
|
&& chatModel.chats.isNotEmpty()
|
||||||
|
|
|
@ -61,7 +61,7 @@ class SimplexApp: Application(), LifecycleEventObserver {
|
||||||
withApi {
|
withApi {
|
||||||
when (event) {
|
when (event) {
|
||||||
Lifecycle.Event.ON_STOP ->
|
Lifecycle.Event.ON_STOP ->
|
||||||
if (!chatController.getRunServiceInBackground()) SimplexService.stop(applicationContext)
|
if (!chatController.prefRunServiceInBackground.get()) SimplexService.stop(applicationContext)
|
||||||
Lifecycle.Event.ON_START ->
|
Lifecycle.Event.ON_START ->
|
||||||
SimplexService.start(applicationContext)
|
SimplexService.start(applicationContext)
|
||||||
Lifecycle.Event.ON_RESUME ->
|
Lifecycle.Event.ON_RESUME ->
|
||||||
|
|
|
@ -50,9 +50,18 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager
|
||||||
var chatModel = ChatModel(this)
|
var chatModel = ChatModel(this)
|
||||||
private val sharedPreferences: SharedPreferences = appContext.getSharedPreferences(SHARED_PREFS_ID, Context.MODE_PRIVATE)
|
private val sharedPreferences: SharedPreferences = appContext.getSharedPreferences(SHARED_PREFS_ID, Context.MODE_PRIVATE)
|
||||||
|
|
||||||
|
val prefRunServiceInBackground = mkBoolPreference(SHARED_PREFS_RUN_SERVICE_IN_BACKGROUND, true)
|
||||||
|
val prefBackgroundServiceNoticeShown = mkBoolPreference(SHARED_PREFS_SERVICE_NOTICE_SHOWN, false)
|
||||||
|
private val prefBackgroundServiceBatteryNoticeShown = mkBoolPreference(SHARED_PREFS_SERVICE_BATTERY_NOTICE_SHOWN, false)
|
||||||
|
val prefAutoRestartWorkerVersion = mkIntPreference(SHARED_PREFS_AUTO_RESTART_WORKER_VERSION, 0)
|
||||||
|
val prefWebrtcPolicyRelay = mkBoolPreference(SHARED_PREFS_WEBRTC_POLICY_RELAY, true)
|
||||||
|
val prefAcceptCallsFromLockScreen = mkBoolPreference(SHARED_PREFS_WEBRTC_ACCEPT_CALLS_FROM_LOCK_SCREEN, false)
|
||||||
|
val prefPerformLA = mkBoolPreference(SHARED_PREFS_PERFORM_LA, false)
|
||||||
|
val prefLANoticeShown = mkBoolPreference(SHARED_PREFS_LA_NOTICE_SHOWN, false)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
chatModel.runServiceInBackground.value = getRunServiceInBackground()
|
chatModel.runServiceInBackground.value = prefRunServiceInBackground.get()
|
||||||
chatModel.performLA.value = getPerformLA()
|
chatModel.performLA.value = prefPerformLA.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun startChat(user: User) {
|
suspend fun startChat(user: User) {
|
||||||
|
@ -529,7 +538,7 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager
|
||||||
if (invitation != null) {
|
if (invitation != null) {
|
||||||
chatModel.callManager.reportCallRemoteEnded(invitation = invitation)
|
chatModel.callManager.reportCallRemoteEnded(invitation = invitation)
|
||||||
}
|
}
|
||||||
withCall(r, r.contact) { call ->
|
withCall(r, r.contact) { _ ->
|
||||||
chatModel.callCommand.value = WCallCommand.End
|
chatModel.callCommand.value = WCallCommand.End
|
||||||
withApi {
|
withApi {
|
||||||
chatModel.activeCall.value = null
|
chatModel.activeCall.value = null
|
||||||
|
@ -583,7 +592,7 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager
|
||||||
|
|
||||||
fun showBackgroundServiceNoticeIfNeeded() {
|
fun showBackgroundServiceNoticeIfNeeded() {
|
||||||
Log.d(TAG, "showBackgroundServiceNoticeIfNeeded")
|
Log.d(TAG, "showBackgroundServiceNoticeIfNeeded")
|
||||||
if (!getBackgroundServiceNoticeShown()) {
|
if (!prefBackgroundServiceNoticeShown.get()) {
|
||||||
// the branch for the new users who has never seen service notice
|
// the branch for the new users who has never seen service notice
|
||||||
if (isIgnoringBatteryOptimizations(appContext)) {
|
if (isIgnoringBatteryOptimizations(appContext)) {
|
||||||
showBGServiceNotice()
|
showBGServiceNotice()
|
||||||
|
@ -591,20 +600,20 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager
|
||||||
showBGServiceNoticeIgnoreOptimization()
|
showBGServiceNoticeIgnoreOptimization()
|
||||||
}
|
}
|
||||||
// set both flags, so that if the user doesn't allow ignoring optimizations, the service will be disabled without additional notice
|
// set both flags, so that if the user doesn't allow ignoring optimizations, the service will be disabled without additional notice
|
||||||
setBackgroundServiceNoticeShown(true)
|
prefBackgroundServiceNoticeShown.set(true)
|
||||||
setBackgroundServiceBatteryNoticeShown(true)
|
prefBackgroundServiceBatteryNoticeShown.set(true)
|
||||||
} else if (!isIgnoringBatteryOptimizations(appContext) && getRunServiceInBackground()) {
|
} else if (!isIgnoringBatteryOptimizations(appContext) && prefRunServiceInBackground.get()) {
|
||||||
// the branch for users who have app installed, and have seen the service notice,
|
// the branch for users who have app installed, and have seen the service notice,
|
||||||
// but the battery optimization for the app is on (Android 12) AND the service is running
|
// but the battery optimization for the app is on (Android 12) AND the service is running
|
||||||
if (getBackgroundServiceBatteryNoticeShown()) {
|
if (prefBackgroundServiceBatteryNoticeShown.get()) {
|
||||||
// users have been presented with battery notice before - they did not allow ignoring optimizitions -> disable service
|
// users have been presented with battery notice before - they did not allow ignoring optimizitions -> disable service
|
||||||
showDisablingServiceNotice()
|
showDisablingServiceNotice()
|
||||||
setRunServiceInBackground(false)
|
prefRunServiceInBackground.set(false)
|
||||||
chatModel.runServiceInBackground.value = false
|
chatModel.runServiceInBackground.value = false
|
||||||
} else {
|
} else {
|
||||||
// show battery optimization notice
|
// show battery optimization notice
|
||||||
showBGServiceNoticeIgnoreOptimization()
|
showBGServiceNoticeIgnoreOptimization()
|
||||||
setBackgroundServiceBatteryNoticeShown(true)
|
prefBackgroundServiceBatteryNoticeShown.set(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -695,8 +704,8 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager
|
||||||
|
|
||||||
fun showLANotice(activity: FragmentActivity) {
|
fun showLANotice(activity: FragmentActivity) {
|
||||||
Log.d(TAG, "showLANotice")
|
Log.d(TAG, "showLANotice")
|
||||||
if (!getLANoticeShown()) {
|
if (!prefLANoticeShown.get()) {
|
||||||
setLANoticeShown(true)
|
prefLANoticeShown.set(true)
|
||||||
AlertManager.shared.showAlertDialog(
|
AlertManager.shared.showAlertDialog(
|
||||||
title = generalGetString(R.string.la_notice_title),
|
title = generalGetString(R.string.la_notice_title),
|
||||||
text = generalGetString(R.string.la_notice_text),
|
text = generalGetString(R.string.la_notice_text),
|
||||||
|
@ -710,22 +719,22 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager
|
||||||
when (laResult) {
|
when (laResult) {
|
||||||
LAResult.Success -> {
|
LAResult.Success -> {
|
||||||
chatModel.performLA.value = true
|
chatModel.performLA.value = true
|
||||||
setPerformLA(true)
|
prefPerformLA.set(true)
|
||||||
laTurnedOnAlert()
|
laTurnedOnAlert()
|
||||||
}
|
}
|
||||||
is LAResult.Error -> {
|
is LAResult.Error -> {
|
||||||
chatModel.performLA.value = false
|
chatModel.performLA.value = false
|
||||||
setPerformLA(false)
|
prefPerformLA.set(false)
|
||||||
laErrorToast(appContext, laResult.errString)
|
laErrorToast(appContext, laResult.errString)
|
||||||
}
|
}
|
||||||
LAResult.Failed -> {
|
LAResult.Failed -> {
|
||||||
chatModel.performLA.value = false
|
chatModel.performLA.value = false
|
||||||
setPerformLA(false)
|
prefPerformLA.set(false)
|
||||||
laFailedToast(appContext)
|
laFailedToast(appContext)
|
||||||
}
|
}
|
||||||
LAResult.Unavailable -> {
|
LAResult.Unavailable -> {
|
||||||
chatModel.performLA.value = false
|
chatModel.performLA.value = false
|
||||||
setPerformLA(false)
|
prefPerformLA.set(false)
|
||||||
chatModel.showAdvertiseLAUnavailableAlert.value = true
|
chatModel.showAdvertiseLAUnavailableAlert.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -736,34 +745,6 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAutoRestartWorkerVersion(): Int = sharedPreferences.getInt(SHARED_PREFS_AUTO_RESTART_WORKER_VERSION, 0)
|
|
||||||
|
|
||||||
fun setAutoRestartWorkerVersion(version: Int) =
|
|
||||||
sharedPreferences.edit()
|
|
||||||
.putInt(SHARED_PREFS_AUTO_RESTART_WORKER_VERSION, version)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
fun getRunServiceInBackground(): Boolean = sharedPreferences.getBoolean(SHARED_PREFS_RUN_SERVICE_IN_BACKGROUND, true)
|
|
||||||
|
|
||||||
fun setRunServiceInBackground(runService: Boolean) =
|
|
||||||
sharedPreferences.edit()
|
|
||||||
.putBoolean(SHARED_PREFS_RUN_SERVICE_IN_BACKGROUND, runService)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
private fun getBackgroundServiceNoticeShown(): Boolean = sharedPreferences.getBoolean(SHARED_PREFS_SERVICE_NOTICE_SHOWN, false)
|
|
||||||
|
|
||||||
fun setBackgroundServiceNoticeShown(shown: Boolean) =
|
|
||||||
sharedPreferences.edit()
|
|
||||||
.putBoolean(SHARED_PREFS_SERVICE_NOTICE_SHOWN, shown)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
private fun getBackgroundServiceBatteryNoticeShown(): Boolean = sharedPreferences.getBoolean(SHARED_PREFS_SERVICE_BATTERY_NOTICE_SHOWN, false)
|
|
||||||
|
|
||||||
fun setBackgroundServiceBatteryNoticeShown(shown: Boolean) =
|
|
||||||
sharedPreferences.edit()
|
|
||||||
.putBoolean(SHARED_PREFS_SERVICE_BATTERY_NOTICE_SHOWN, shown)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
fun isIgnoringBatteryOptimizations(context: Context): Boolean {
|
fun isIgnoringBatteryOptimizations(context: Context): Boolean {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return true
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) return true
|
||||||
val powerManager = context.getSystemService(Application.POWER_SERVICE) as PowerManager
|
val powerManager = context.getSystemService(Application.POWER_SERVICE) as PowerManager
|
||||||
|
@ -783,19 +764,17 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPerformLA(): Boolean = sharedPreferences.getBoolean(SHARED_PREFS_PERFORM_LA, false)
|
private fun mkIntPreference(prefName: String, default: Int) =
|
||||||
|
Preference(
|
||||||
|
get = fun() = sharedPreferences.getInt(prefName, default),
|
||||||
|
set = fun(value) = sharedPreferences.edit().putInt(prefName, value).apply()
|
||||||
|
)
|
||||||
|
|
||||||
fun setPerformLA(performLA: Boolean) =
|
private fun mkBoolPreference(prefName: String, default: Boolean) =
|
||||||
sharedPreferences.edit()
|
Preference(
|
||||||
.putBoolean(SHARED_PREFS_PERFORM_LA, performLA)
|
get = fun() = sharedPreferences.getBoolean(prefName, default),
|
||||||
.apply()
|
set = fun(value) = sharedPreferences.edit().putBoolean(prefName, value).apply()
|
||||||
|
)
|
||||||
fun getLANoticeShown(): Boolean = sharedPreferences.getBoolean(SHARED_PREFS_LA_NOTICE_SHOWN, false)
|
|
||||||
|
|
||||||
fun setLANoticeShown(shown: Boolean) =
|
|
||||||
sharedPreferences.edit()
|
|
||||||
.putBoolean(SHARED_PREFS_LA_NOTICE_SHOWN, shown)
|
|
||||||
.apply()
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val SHARED_PREFS_ID = "chat.simplex.app.SIMPLEX_APP_PREFS"
|
private const val SHARED_PREFS_ID = "chat.simplex.app.SIMPLEX_APP_PREFS"
|
||||||
|
@ -803,11 +782,15 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager
|
||||||
private const val SHARED_PREFS_RUN_SERVICE_IN_BACKGROUND = "RunServiceInBackground"
|
private const val SHARED_PREFS_RUN_SERVICE_IN_BACKGROUND = "RunServiceInBackground"
|
||||||
private const val SHARED_PREFS_SERVICE_NOTICE_SHOWN = "BackgroundServiceNoticeShown"
|
private const val SHARED_PREFS_SERVICE_NOTICE_SHOWN = "BackgroundServiceNoticeShown"
|
||||||
private const val SHARED_PREFS_SERVICE_BATTERY_NOTICE_SHOWN = "BackgroundServiceBatteryNoticeShown"
|
private const val SHARED_PREFS_SERVICE_BATTERY_NOTICE_SHOWN = "BackgroundServiceBatteryNoticeShown"
|
||||||
|
private const val SHARED_PREFS_WEBRTC_POLICY_RELAY = "WebrtcPolicyRelay"
|
||||||
|
private const val SHARED_PREFS_WEBRTC_ACCEPT_CALLS_FROM_LOCK_SCREEN = "AcceptCallsFromLockScreen"
|
||||||
private const val SHARED_PREFS_PERFORM_LA = "PerformLA"
|
private const val SHARED_PREFS_PERFORM_LA = "PerformLA"
|
||||||
private const val SHARED_PREFS_LA_NOTICE_SHOWN = "LANoticeShown"
|
private const val SHARED_PREFS_LA_NOTICE_SHOWN = "LANoticeShown"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Preference<T>(val get: () -> T, val set: (T) -> Unit)
|
||||||
|
|
||||||
// ChatCommand
|
// ChatCommand
|
||||||
sealed class CC {
|
sealed class CC {
|
||||||
class Console(val cmd: String): CC()
|
class Console(val cmd: String): CC()
|
||||||
|
|
|
@ -156,7 +156,7 @@ private fun ActiveCallOverlayLayout(
|
||||||
ControlButton(call, Icons.Filled.FlipCameraAndroid, R.string.icon_descr_flip_camera, flipCamera)
|
ControlButton(call, Icons.Filled.FlipCameraAndroid, R.string.icon_descr_flip_camera, flipCamera)
|
||||||
ControlButton(call, Icons.Filled.Videocam, R.string.icon_descr_video_off, toggleVideo)
|
ControlButton(call, Icons.Filled.Videocam, R.string.icon_descr_video_off, toggleVideo)
|
||||||
} else {
|
} else {
|
||||||
Spacer(Modifier.size(40.dp))
|
Spacer(Modifier.size(48.dp))
|
||||||
ControlButton(call, Icons.Outlined.VideocamOff, R.string.icon_descr_video_on, toggleVideo)
|
ControlButton(call, Icons.Outlined.VideocamOff, R.string.icon_descr_video_on, toggleVideo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
|
@ -25,14 +24,15 @@ import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
import chat.simplex.app.*
|
import chat.simplex.app.*
|
||||||
import chat.simplex.app.R
|
import chat.simplex.app.R
|
||||||
import chat.simplex.app.model.ChatModel
|
import chat.simplex.app.model.ChatModel
|
||||||
import chat.simplex.app.model.Contact
|
import chat.simplex.app.model.Contact
|
||||||
|
import chat.simplex.app.model.NtfManager.Companion.OpenChatAction
|
||||||
import chat.simplex.app.ui.theme.*
|
import chat.simplex.app.ui.theme.*
|
||||||
import chat.simplex.app.views.helpers.ProfileImage
|
import chat.simplex.app.views.helpers.ProfileImage
|
||||||
import chat.simplex.app.views.onboarding.SimpleXLogo
|
import chat.simplex.app.views.onboarding.SimpleXLogo
|
||||||
|
@ -93,7 +93,7 @@ fun IncomingCallActivityView(m: ChatModel, activity: IncomingCallActivity) {
|
||||||
activity.finish()
|
activity.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SimpleXTheme(darkTheme = true) {
|
SimpleXTheme {
|
||||||
Surface(
|
Surface(
|
||||||
Modifier
|
Modifier
|
||||||
.background(MaterialTheme.colors.background)
|
.background(MaterialTheme.colors.background)
|
||||||
|
@ -104,33 +104,48 @@ fun IncomingCallActivityView(m: ChatModel, activity: IncomingCallActivity) {
|
||||||
if (invitation != null) IncomingCallAlertView(invitation, m)
|
if (invitation != null) IncomingCallAlertView(invitation, m)
|
||||||
}
|
}
|
||||||
} else if (invitation != null) {
|
} else if (invitation != null) {
|
||||||
IncomingCallLockScreenAlert(invitation, m)
|
IncomingCallLockScreenAlert(invitation, m, activity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun IncomingCallLockScreenAlert(invitation: CallInvitation, chatModel: ChatModel) {
|
fun IncomingCallLockScreenAlert(invitation: CallInvitation, chatModel: ChatModel, activity: IncomingCallActivity) {
|
||||||
val cm = chatModel.callManager
|
val cm = chatModel.callManager
|
||||||
val cxt = LocalContext.current
|
val cxt = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
var acceptCallsFromLockScreen by remember { mutableStateOf(chatModel.controller.prefAcceptCallsFromLockScreen.get()) }
|
||||||
LaunchedEffect(true) { SoundPlayer.shared.start(cxt, scope, sound = true) }
|
LaunchedEffect(true) { SoundPlayer.shared.start(cxt, scope, sound = true) }
|
||||||
DisposableEffect(true) { onDispose { SoundPlayer.shared.stop() } }
|
DisposableEffect(true) { onDispose { SoundPlayer.shared.stop() } }
|
||||||
IncomingCallLockScreenAlertLayout(
|
IncomingCallLockScreenAlertLayout(
|
||||||
invitation,
|
invitation,
|
||||||
|
acceptCallsFromLockScreen,
|
||||||
rejectCall = { cm.endCall(invitation = invitation) },
|
rejectCall = { cm.endCall(invitation = invitation) },
|
||||||
ignoreCall = { chatModel.activeCallInvitation.value = null },
|
ignoreCall = { chatModel.activeCallInvitation.value = null },
|
||||||
acceptCall = { cm.acceptIncomingCall(invitation = invitation) }
|
acceptCall = { cm.acceptIncomingCall(invitation = invitation) },
|
||||||
|
openApp = {
|
||||||
|
SoundPlayer.shared.stop()
|
||||||
|
var intent = Intent(activity, MainActivity::class.java)
|
||||||
|
.setAction(OpenChatAction)
|
||||||
|
.putExtra("chatId", invitation.contact.id)
|
||||||
|
activity.startActivity(intent)
|
||||||
|
activity.finish()
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
getKeyguardManager(activity).requestDismissKeyguard(activity, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun IncomingCallLockScreenAlertLayout(
|
fun IncomingCallLockScreenAlertLayout(
|
||||||
invitation: CallInvitation,
|
invitation: CallInvitation,
|
||||||
|
acceptCallsFromLockScreen: Boolean,
|
||||||
rejectCall: () -> Unit,
|
rejectCall: () -> Unit,
|
||||||
ignoreCall: () -> Unit,
|
ignoreCall: () -> Unit,
|
||||||
acceptCall: () -> Unit
|
acceptCall: () -> Unit,
|
||||||
|
openApp: () -> Unit
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
|
@ -139,22 +154,24 @@ fun IncomingCallLockScreenAlertLayout(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
IncomingCallInfo(invitation)
|
IncomingCallInfo(invitation)
|
||||||
Spacer(
|
Spacer(Modifier.fillMaxHeight().weight(1f))
|
||||||
Modifier
|
if (acceptCallsFromLockScreen) {
|
||||||
.fillMaxHeight()
|
ProfileImage(size = 192.dp, image = invitation.contact.profile.image)
|
||||||
.weight(1f))
|
Text(invitation.contact.chatViewName, style = MaterialTheme.typography.h2)
|
||||||
ProfileImage(size = 192.dp, image = invitation.contact.profile.image)
|
Spacer(Modifier.fillMaxHeight().weight(1f))
|
||||||
Text(invitation.contact.chatViewName, style = MaterialTheme.typography.h2)
|
Row {
|
||||||
Spacer(
|
LockScreenCallButton(stringResource(R.string.reject), Icons.Filled.CallEnd, Color.Red, rejectCall)
|
||||||
Modifier
|
Spacer(Modifier.size(48.dp))
|
||||||
.fillMaxHeight()
|
LockScreenCallButton(stringResource(R.string.ignore), Icons.Filled.Close, MaterialTheme.colors.primary, ignoreCall)
|
||||||
.weight(1f))
|
Spacer(Modifier.size(48.dp))
|
||||||
Row {
|
LockScreenCallButton(stringResource(R.string.accept), Icons.Filled.Check, SimplexGreen, acceptCall)
|
||||||
LockScreenCallButton(stringResource(R.string.reject), Icons.Filled.CallEnd, Color.Red, rejectCall)
|
}
|
||||||
Spacer(Modifier.size(48.dp))
|
} else {
|
||||||
LockScreenCallButton(stringResource(R.string.ignore), Icons.Filled.Close, MaterialTheme.colors.primary, ignoreCall)
|
SimpleXLogo()
|
||||||
Spacer(Modifier.size(48.dp))
|
Text(stringResource(R.string.open_simplex_chat_to_accept_call), textAlign = TextAlign.Center, lineHeight = 22.sp)
|
||||||
LockScreenCallButton(stringResource(R.string.accept), Icons.Filled.Check, SimplexGreen, acceptCall)
|
Text(stringResource(R.string.allow_accepting_calls_from_lock_screen), textAlign = TextAlign.Center, style = MaterialTheme.typography.body2, lineHeight = 22.sp)
|
||||||
|
Spacer(Modifier.fillMaxHeight().weight(1f))
|
||||||
|
SimpleButton(text = stringResource(R.string.open_verb), icon = Icons.Filled.Check, click = openApp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,7 +183,9 @@ private fun LockScreenCallButton(text: String, icon: ImageVector, color: Color,
|
||||||
color = Color.Transparent
|
color = Color.Transparent
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
Modifier.defaultMinSize(minWidth = 50.dp).padding(4.dp),
|
Modifier
|
||||||
|
.defaultMinSize(minWidth = 50.dp)
|
||||||
|
.padding(4.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
IconButton(action) {
|
IconButton(action) {
|
||||||
|
@ -185,16 +204,21 @@ private fun LockScreenCallButton(text: String, icon: ImageVector, color: Color,
|
||||||
@Composable
|
@Composable
|
||||||
fun PreviewIncomingCallLockScreenAlert() {
|
fun PreviewIncomingCallLockScreenAlert() {
|
||||||
SimpleXTheme(true) {
|
SimpleXTheme(true) {
|
||||||
Surface(Modifier.background(MaterialTheme.colors.background).fillMaxSize()) {
|
Surface(
|
||||||
|
Modifier
|
||||||
|
.background(MaterialTheme.colors.background)
|
||||||
|
.fillMaxSize()) {
|
||||||
IncomingCallLockScreenAlertLayout(
|
IncomingCallLockScreenAlertLayout(
|
||||||
invitation = CallInvitation(
|
invitation = CallInvitation(
|
||||||
contact = Contact.sampleData,
|
contact = Contact.sampleData,
|
||||||
peerMedia = CallMediaType.Audio,
|
peerMedia = CallMediaType.Audio,
|
||||||
sharedKey = null
|
sharedKey = null
|
||||||
),
|
),
|
||||||
|
acceptCallsFromLockScreen = false,
|
||||||
rejectCall = {},
|
rejectCall = {},
|
||||||
ignoreCall = {},
|
ignoreCall = {},
|
||||||
acceptCall = {}
|
acceptCall = {},
|
||||||
|
openApp = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package chat.simplex.app.views.usersettings
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import chat.simplex.app.R
|
||||||
|
import chat.simplex.app.model.*
|
||||||
|
import chat.simplex.app.ui.theme.HighOrLowlight
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CallSettingsView(m: ChatModel) {
|
||||||
|
CallSettingsLayout(
|
||||||
|
webrtcPolicyRelay = m.controller.prefWebrtcPolicyRelay,
|
||||||
|
acceptCallsFromLockScreen = m.controller.prefAcceptCallsFromLockScreen
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CallSettingsLayout(
|
||||||
|
webrtcPolicyRelay: Preference<Boolean>,
|
||||||
|
acceptCallsFromLockScreen: Preference<Boolean>,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
Modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.Start,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.call_settings),
|
||||||
|
Modifier.padding(bottom = 24.dp),
|
||||||
|
style = MaterialTheme.typography.h1
|
||||||
|
)
|
||||||
|
SharedPreferenceToggle(stringResource(R.string.connect_calls_via_relay), webrtcPolicyRelay)
|
||||||
|
SharedPreferenceToggle(stringResource(R.string.accept_calls_from_lock_screen), acceptCallsFromLockScreen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SharedPreferenceToggle(
|
||||||
|
text: String,
|
||||||
|
preference: Preference<Boolean>
|
||||||
|
) {
|
||||||
|
var preferenceState by remember { mutableStateOf(preference.get()) }
|
||||||
|
Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Text(text, Modifier.padding(end = 24.dp))
|
||||||
|
Spacer(Modifier.fillMaxWidth().weight(1f))
|
||||||
|
Switch(
|
||||||
|
checked = preferenceState,
|
||||||
|
onCheckedChange = {
|
||||||
|
preference.set(it)
|
||||||
|
preferenceState = it
|
||||||
|
},
|
||||||
|
colors = SwitchDefaults.colors(
|
||||||
|
checkedThumbColor = MaterialTheme.colors.primary,
|
||||||
|
uncheckedThumbColor = HighOrLowlight
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
package chat.simplex.app.views.usersettings
|
package chat.simplex.app.views.usersettings
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.gestures.Orientation
|
||||||
|
import androidx.compose.foundation.gestures.scrollable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
@ -12,6 +13,7 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalUriHandler
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
|
import androidx.compose.ui.platform.UriHandler
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
@ -32,9 +34,9 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) {
|
||||||
val user = chatModel.currentUser.value
|
val user = chatModel.currentUser.value
|
||||||
|
|
||||||
fun setRunServiceInBackground(on: Boolean) {
|
fun setRunServiceInBackground(on: Boolean) {
|
||||||
chatModel.controller.setRunServiceInBackground(on)
|
chatModel.controller.prefRunServiceInBackground.set(on)
|
||||||
if (on && !chatModel.controller.isIgnoringBatteryOptimizations(chatModel.controller.appContext)) {
|
if (on && !chatModel.controller.isIgnoringBatteryOptimizations(chatModel.controller.appContext)) {
|
||||||
chatModel.controller.setBackgroundServiceNoticeShown(false)
|
chatModel.controller.prefBackgroundServiceNoticeShown.set(false)
|
||||||
}
|
}
|
||||||
chatModel.controller.showBackgroundServiceNoticeIfNeeded()
|
chatModel.controller.showBackgroundServiceNoticeIfNeeded()
|
||||||
chatModel.runServiceInBackground.value = on
|
chatModel.runServiceInBackground.value = on
|
||||||
|
@ -75,6 +77,7 @@ fun SettingsLayout(
|
||||||
Modifier
|
Modifier
|
||||||
.background(MaterialTheme.colors.background)
|
.background(MaterialTheme.colors.background)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
|
@ -83,6 +86,7 @@ fun SettingsLayout(
|
||||||
.padding(8.dp)
|
.padding(8.dp)
|
||||||
.padding(top = 16.dp)
|
.padding(top = 16.dp)
|
||||||
) {
|
) {
|
||||||
|
@Composable fun divider() = Divider(Modifier.padding(horizontal = 8.dp))
|
||||||
Text(
|
Text(
|
||||||
stringResource(R.string.your_settings),
|
stringResource(R.string.your_settings),
|
||||||
style = MaterialTheme.typography.h1,
|
style = MaterialTheme.typography.h1,
|
||||||
|
@ -93,150 +97,219 @@ fun SettingsLayout(
|
||||||
SettingsSectionView(showCustomModal { chatModel, close -> UserProfileView(chatModel, close) }, 80.dp) {
|
SettingsSectionView(showCustomModal { chatModel, close -> UserProfileView(chatModel, close) }, 80.dp) {
|
||||||
ProfilePreview(profile)
|
ProfilePreview(profile)
|
||||||
}
|
}
|
||||||
Divider(Modifier.padding(horizontal = 8.dp))
|
divider()
|
||||||
SettingsSectionView(showModal { UserAddressView(it) }) {
|
UserAddressSection(showModal)
|
||||||
Icon(
|
|
||||||
Icons.Outlined.QrCode,
|
|
||||||
contentDescription = stringResource(R.string.icon_descr_address),
|
|
||||||
)
|
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
|
||||||
Text(stringResource(R.string.your_simplex_contact_address))
|
|
||||||
}
|
|
||||||
Spacer(Modifier.height(24.dp))
|
Spacer(Modifier.height(24.dp))
|
||||||
|
|
||||||
SettingsSectionView(showModal { HelpView(it) }) {
|
CallSettingsSection(showModal)
|
||||||
Icon(
|
divider()
|
||||||
Icons.Outlined.HelpOutline,
|
ChatLockSection(performLA, setPerformLA)
|
||||||
contentDescription = stringResource(R.string.icon_descr_help),
|
divider()
|
||||||
)
|
PrivateNotificationsSection(runServiceInBackground, setRunServiceInBackground)
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
divider()
|
||||||
Text(stringResource(R.string.how_to_use_simplex_chat))
|
SMPServersSection(showModal)
|
||||||
}
|
|
||||||
Divider(Modifier.padding(horizontal = 8.dp))
|
|
||||||
SettingsSectionView(showModal { SimpleXInfo(it, onboarding = false) }) {
|
|
||||||
Icon(
|
|
||||||
Icons.Outlined.Info,
|
|
||||||
contentDescription = stringResource(R.string.icon_descr_help),
|
|
||||||
)
|
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
|
||||||
Text(stringResource(R.string.about_simplex_chat))
|
|
||||||
}
|
|
||||||
Divider(Modifier.padding(horizontal = 8.dp))
|
|
||||||
SettingsSectionView(showModal { MarkdownHelpView() }) {
|
|
||||||
Icon(
|
|
||||||
Icons.Outlined.TextFormat,
|
|
||||||
contentDescription = stringResource(R.string.markdown_help),
|
|
||||||
)
|
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
|
||||||
Text(stringResource(R.string.markdown_in_messages))
|
|
||||||
}
|
|
||||||
Divider(Modifier.padding(horizontal = 8.dp))
|
|
||||||
SettingsSectionView({ uriHandler.openUri(simplexTeamUri) }) {
|
|
||||||
Icon(
|
|
||||||
Icons.Outlined.Tag,
|
|
||||||
contentDescription = stringResource(R.string.icon_descr_simplex_team),
|
|
||||||
)
|
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.chat_with_the_founder),
|
|
||||||
color = MaterialTheme.colors.primary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Divider(Modifier.padding(horizontal = 8.dp))
|
|
||||||
SettingsSectionView({ uriHandler.openUri("mailto:chat@simplex.chat") }) {
|
|
||||||
Icon(
|
|
||||||
Icons.Outlined.Email,
|
|
||||||
contentDescription = stringResource(R.string.icon_descr_email),
|
|
||||||
)
|
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.send_us_an_email),
|
|
||||||
color = MaterialTheme.colors.primary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Spacer(Modifier.height(24.dp))
|
Spacer(Modifier.height(24.dp))
|
||||||
|
|
||||||
SettingsSectionView(showModal { SMPServersView(it) }) {
|
HelpViewSection(showModal)
|
||||||
Icon(
|
divider()
|
||||||
Icons.Outlined.Dns,
|
SimpleXInfoSection(showModal)
|
||||||
contentDescription = stringResource(R.string.smp_servers),
|
divider()
|
||||||
)
|
MarkdownHelpSection(showModal)
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
divider()
|
||||||
Text(stringResource(R.string.smp_servers))
|
ConnectToDevelopersSection(uriHandler)
|
||||||
}
|
divider()
|
||||||
Divider(Modifier.padding(horizontal = 8.dp))
|
SendEmailSection(uriHandler)
|
||||||
SettingsSectionView() {
|
Spacer(Modifier.height(24.dp))
|
||||||
Icon(
|
|
||||||
Icons.Outlined.Bolt,
|
ChatConsoleSection(showTerminal)
|
||||||
contentDescription = stringResource(R.string.private_notifications),
|
divider()
|
||||||
)
|
InstallTerminalAppSection(uriHandler)
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
divider()
|
||||||
Text(
|
AppVersionSection()
|
||||||
stringResource(R.string.private_notifications), Modifier
|
|
||||||
.padding(end = 24.dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.weight(1F)
|
|
||||||
)
|
|
||||||
Switch(
|
|
||||||
checked = runServiceInBackground.value,
|
|
||||||
onCheckedChange = { setRunServiceInBackground(it) },
|
|
||||||
colors = SwitchDefaults.colors(
|
|
||||||
checkedThumbColor = MaterialTheme.colors.primary,
|
|
||||||
uncheckedThumbColor = HighOrLowlight
|
|
||||||
),
|
|
||||||
modifier = Modifier.padding(end = 8.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Divider(Modifier.padding(horizontal = 8.dp))
|
|
||||||
SettingsSectionView() {
|
|
||||||
Icon(
|
|
||||||
Icons.Outlined.Lock,
|
|
||||||
contentDescription = stringResource(R.string.chat_lock),
|
|
||||||
)
|
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
|
||||||
Text(
|
|
||||||
stringResource(R.string.chat_lock), Modifier
|
|
||||||
.padding(end = 24.dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.weight(1F)
|
|
||||||
)
|
|
||||||
Switch(
|
|
||||||
checked = performLA.value,
|
|
||||||
onCheckedChange = { setPerformLA(it) },
|
|
||||||
colors = SwitchDefaults.colors(
|
|
||||||
checkedThumbColor = MaterialTheme.colors.primary,
|
|
||||||
uncheckedThumbColor = HighOrLowlight
|
|
||||||
),
|
|
||||||
modifier = Modifier.padding(end = 8.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Divider(Modifier.padding(horizontal = 8.dp))
|
|
||||||
SettingsSectionView(showTerminal) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.ic_outline_terminal),
|
|
||||||
contentDescription = stringResource(R.string.chat_console),
|
|
||||||
)
|
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
|
||||||
Text(stringResource(R.string.chat_console))
|
|
||||||
}
|
|
||||||
Divider(Modifier.padding(horizontal = 8.dp))
|
|
||||||
SettingsSectionView({ uriHandler.openUri("https://github.com/simplex-chat/simplex-chat") }) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.ic_github),
|
|
||||||
contentDescription = "GitHub",
|
|
||||||
)
|
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
|
||||||
Text(annotatedStringResource(R.string.install_simplex_chat_for_terminal))
|
|
||||||
}
|
|
||||||
Divider(Modifier.padding(horizontal = 8.dp))
|
|
||||||
// SettingsSectionView(showVideoChatPrototype) {
|
|
||||||
SettingsSectionView() {
|
|
||||||
Text("v${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable private fun UserAddressSection(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) {
|
||||||
|
SettingsSectionView(showModal { UserAddressView(it) }) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.QrCode,
|
||||||
|
contentDescription = stringResource(R.string.icon_descr_address),
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(stringResource(R.string.your_simplex_contact_address))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun CallSettingsSection(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) {
|
||||||
|
SettingsSectionView(showModal { CallSettingsView(it) }) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Videocam,
|
||||||
|
contentDescription = stringResource(R.string.call_settings),
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(stringResource(R.string.call_settings))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun HelpViewSection(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) {
|
||||||
|
SettingsSectionView(showModal { HelpView(it) }) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.HelpOutline,
|
||||||
|
contentDescription = stringResource(R.string.icon_descr_help),
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(stringResource(R.string.how_to_use_simplex_chat))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun SimpleXInfoSection(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) {
|
||||||
|
SettingsSectionView(showModal { SimpleXInfo(it, onboarding = false) }) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Info,
|
||||||
|
contentDescription = stringResource(R.string.icon_descr_help),
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(stringResource(R.string.about_simplex_chat))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun MarkdownHelpSection(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) {
|
||||||
|
SettingsSectionView(showModal { MarkdownHelpView() }) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.TextFormat,
|
||||||
|
contentDescription = stringResource(R.string.markdown_help),
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(stringResource(R.string.markdown_in_messages))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun ConnectToDevelopersSection(uriHandler: UriHandler) {
|
||||||
|
SettingsSectionView({ uriHandler.openUri(simplexTeamUri) }) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Tag,
|
||||||
|
contentDescription = stringResource(R.string.icon_descr_simplex_team),
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.chat_with_the_founder),
|
||||||
|
color = MaterialTheme.colors.primary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun SendEmailSection(uriHandler: UriHandler) {
|
||||||
|
SettingsSectionView({ uriHandler.openUri("mailto:chat@simplex.chat") }) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Email,
|
||||||
|
contentDescription = stringResource(R.string.icon_descr_email),
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.send_us_an_email),
|
||||||
|
color = MaterialTheme.colors.primary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun SMPServersSection(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) {
|
||||||
|
SettingsSectionView(showModal { SMPServersView(it) }) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Dns,
|
||||||
|
contentDescription = stringResource(R.string.smp_servers),
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(stringResource(R.string.smp_servers))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun PrivateNotificationsSection(
|
||||||
|
runServiceInBackground: MutableState<Boolean>,
|
||||||
|
setRunServiceInBackground: (Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
SettingsSectionView() {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Bolt,
|
||||||
|
contentDescription = stringResource(R.string.private_notifications),
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.private_notifications),
|
||||||
|
Modifier
|
||||||
|
.padding(end = 24.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f)
|
||||||
|
)
|
||||||
|
Switch(
|
||||||
|
checked = runServiceInBackground.value,
|
||||||
|
onCheckedChange = { setRunServiceInBackground(it) },
|
||||||
|
colors = SwitchDefaults.colors(
|
||||||
|
checkedThumbColor = MaterialTheme.colors.primary,
|
||||||
|
uncheckedThumbColor = HighOrLowlight
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(end = 8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun ChatLockSection(performLA: MutableState<Boolean>, setPerformLA: (Boolean) -> Unit) {
|
||||||
|
SettingsSectionView() {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Icon(
|
||||||
|
Icons.Outlined.Lock,
|
||||||
|
contentDescription = stringResource(R.string.chat_lock),
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(
|
||||||
|
stringResource(R.string.chat_lock), Modifier
|
||||||
|
.padding(end = 24.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1F)
|
||||||
|
)
|
||||||
|
Switch(
|
||||||
|
checked = performLA.value,
|
||||||
|
onCheckedChange = { setPerformLA(it) },
|
||||||
|
colors = SwitchDefaults.colors(
|
||||||
|
checkedThumbColor = MaterialTheme.colors.primary,
|
||||||
|
uncheckedThumbColor = HighOrLowlight
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(end = 8.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun ChatConsoleSection(showTerminal: () -> Unit) {
|
||||||
|
SettingsSectionView(showTerminal) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_outline_terminal),
|
||||||
|
contentDescription = stringResource(R.string.chat_console),
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(stringResource(R.string.chat_console))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun InstallTerminalAppSection(uriHandler: UriHandler) {
|
||||||
|
SettingsSectionView({ uriHandler.openUri("https://github.com/simplex-chat/simplex-chat") }) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_github),
|
||||||
|
contentDescription = "GitHub",
|
||||||
|
)
|
||||||
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
Text(annotatedStringResource(R.string.install_simplex_chat_for_terminal))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable private fun AppVersionSection() {
|
||||||
|
SettingsSectionView() {
|
||||||
|
Text("v${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable fun ProfilePreview(profileOf: NamedChat, size: Dp = 60.dp, color: Color = MaterialTheme.colors.secondary) {
|
@Composable fun ProfilePreview(profileOf: NamedChat, size: Dp = 60.dp, color: Color = MaterialTheme.colors.secondary) {
|
||||||
ProfileImage(size = size, image = profileOf.image, color = color)
|
ProfileImage(size = size, image = profileOf.image, color = color)
|
||||||
Spacer(Modifier.padding(horizontal = 4.dp))
|
Spacer(Modifier.padding(horizontal = 4.dp))
|
||||||
|
|
|
@ -377,6 +377,16 @@
|
||||||
<string name="icon_descr_video_call">видеозвонок</string>
|
<string name="icon_descr_video_call">видеозвонок</string>
|
||||||
<string name="icon_descr_audio_call">аудиозвонок</string>
|
<string name="icon_descr_audio_call">аудиозвонок</string>
|
||||||
|
|
||||||
|
<!-- Call settings -->
|
||||||
|
<string name="call_settings">Настройки звонков</string>
|
||||||
|
<string name="connect_calls_via_relay">Соединяться через сервер (relay)</string>
|
||||||
|
<string name="accept_calls_from_lock_screen">Принимать с экрана блокировки</string>
|
||||||
|
|
||||||
|
<!-- Call Lock Screen -->
|
||||||
|
<string name="open_simplex_chat_to_accept_call">Open <xliff:g id="appNameFull">SimpleX Chat</xliff:g>\nto accept call</string>
|
||||||
|
<string name="allow_accepting_calls_from_lock_screen">You can allow accepting calls from lock screen via Settings.</string>
|
||||||
|
<string name="open_verb">Open</string>
|
||||||
|
|
||||||
<!-- Call overlay -->
|
<!-- Call overlay -->
|
||||||
<string name="status_e2e_encrypted">e2e зашифровано</string>
|
<string name="status_e2e_encrypted">e2e зашифровано</string>
|
||||||
<string name="status_no_e2e_encryption">нет e2e шифрования</string>
|
<string name="status_no_e2e_encryption">нет e2e шифрования</string>
|
||||||
|
|
|
@ -379,6 +379,16 @@
|
||||||
<string name="icon_descr_video_call">video call</string>
|
<string name="icon_descr_video_call">video call</string>
|
||||||
<string name="icon_descr_audio_call">audio call</string>
|
<string name="icon_descr_audio_call">audio call</string>
|
||||||
|
|
||||||
|
<!-- Call settings -->
|
||||||
|
<string name="call_settings">Call settings</string>
|
||||||
|
<string name="connect_calls_via_relay">Connect via relay</string>
|
||||||
|
<string name="accept_calls_from_lock_screen">Accept calls from lock screen</string>
|
||||||
|
|
||||||
|
<!-- Call Lock Screen -->
|
||||||
|
<string name="open_simplex_chat_to_accept_call">Open <xliff:g id="appNameFull">SimpleX Chat</xliff:g> to accept call</string>
|
||||||
|
<string name="allow_accepting_calls_from_lock_screen">Enable calls from lock screen via Settings.</string>
|
||||||
|
<string name="open_verb">Open</string>
|
||||||
|
|
||||||
<!-- Call overlay -->
|
<!-- Call overlay -->
|
||||||
<string name="status_e2e_encrypted">e2e encrypted</string>
|
<string name="status_e2e_encrypted">e2e encrypted</string>
|
||||||
<string name="status_no_e2e_encryption">no e2e encryption</string>
|
<string name="status_no_e2e_encryption">no e2e encryption</string>
|
||||||
|
|
|
@ -660,7 +660,9 @@ func processReceivedMsg(_ res: ChatResponse) {
|
||||||
call.callState = .offerReceived
|
call.callState = .offerReceived
|
||||||
call.peerMedia = callType.media
|
call.peerMedia = callType.media
|
||||||
call.sharedKey = sharedKey
|
call.sharedKey = sharedKey
|
||||||
m.callCommand = .offer(offer: offer.rtcSession, iceCandidates: offer.rtcIceCandidates, media: callType.media, aesKey: sharedKey, useWorker: true)
|
let useRelay = UserDefaults.standard.bool(forKey: DEFAULT_WEBRTC_POLICY_RELAY)
|
||||||
|
logger.debug(".callOffer useRelay \(useRelay)")
|
||||||
|
m.callCommand = .offer(offer: offer.rtcSession, iceCandidates: offer.rtcIceCandidates, media: callType.media, aesKey: sharedKey, useWorker: true, relay: useRelay)
|
||||||
}
|
}
|
||||||
case let .callAnswer(contact, answer):
|
case let .callAnswer(contact, answer):
|
||||||
withCall(contact) { call in
|
withCall(contact) { call in
|
||||||
|
|
|
@ -21,6 +21,7 @@ struct SimpleXApp: App {
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
hs_init(0, nil)
|
hs_init(0, nil)
|
||||||
|
UserDefaults.standard.register(defaults: appDefaults)
|
||||||
BGManager.shared.register()
|
BGManager.shared.register()
|
||||||
NtfManager.shared.registerCategories()
|
NtfManager.shared.registerCategories()
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ class CallManager {
|
||||||
let m = ChatModel.shared
|
let m = ChatModel.shared
|
||||||
if let call = m.activeCall, call.callkitUUID == callUUID {
|
if let call = m.activeCall, call.callkitUUID == callUUID {
|
||||||
m.showCallView = true
|
m.showCallView = true
|
||||||
m.callCommand = .capabilities(useWorker: true)
|
m.callCommand = .capabilities(media: call.localMedia, useWorker: true)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -45,7 +45,9 @@ class CallManager {
|
||||||
sharedKey: invitation.sharedKey
|
sharedKey: invitation.sharedKey
|
||||||
)
|
)
|
||||||
m.showCallView = true
|
m.showCallView = true
|
||||||
m.callCommand = .start(media: invitation.peerMedia, aesKey: invitation.sharedKey, useWorker: true)
|
let useRelay = UserDefaults.standard.bool(forKey: DEFAULT_WEBRTC_POLICY_RELAY)
|
||||||
|
logger.debug("answerIncomingCall useRelay \(useRelay)")
|
||||||
|
m.callCommand = .start(media: invitation.peerMedia, aesKey: invitation.sharedKey, useWorker: true, relay: useRelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
func endCall(callUUID: UUID, completed: @escaping (Bool) -> Void) {
|
func endCall(callUUID: UUID, completed: @escaping (Bool) -> Void) {
|
||||||
|
|
|
@ -102,7 +102,7 @@ struct WVAPIMessage: Equatable, Decodable, Encodable {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum WCallCommand: Equatable, Encodable, Decodable {
|
enum WCallCommand: Equatable, Encodable, Decodable {
|
||||||
case capabilities(useWorker: Bool? = nil)
|
case capabilities(media: CallMediaType, useWorker: Bool? = nil)
|
||||||
case start(media: CallMediaType, aesKey: String? = nil, useWorker: Bool? = nil, iceServers: [RTCIceServer]? = nil, relay: Bool? = nil)
|
case start(media: CallMediaType, aesKey: String? = nil, useWorker: Bool? = nil, iceServers: [RTCIceServer]? = nil, relay: Bool? = nil)
|
||||||
case offer(offer: String, iceCandidates: String, media: CallMediaType, aesKey: String? = nil, useWorker: Bool? = nil, iceServers: [RTCIceServer]? = nil, relay: Bool? = nil)
|
case offer(offer: String, iceCandidates: String, media: CallMediaType, aesKey: String? = nil, useWorker: Bool? = nil, iceServers: [RTCIceServer]? = nil, relay: Bool? = nil)
|
||||||
case answer(answer: String, iceCandidates: String)
|
case answer(answer: String, iceCandidates: String)
|
||||||
|
@ -143,8 +143,9 @@ enum WCallCommand: Equatable, Encodable, Decodable {
|
||||||
func encode(to encoder: Encoder) throws {
|
func encode(to encoder: Encoder) throws {
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
switch self {
|
switch self {
|
||||||
case let .capabilities(useWorker):
|
case let .capabilities(media, useWorker):
|
||||||
try container.encode("capabilities", forKey: .type)
|
try container.encode("capabilities", forKey: .type)
|
||||||
|
try container.encode(media, forKey: .media)
|
||||||
try container.encode(useWorker, forKey: .useWorker)
|
try container.encode(useWorker, forKey: .useWorker)
|
||||||
case let .start(media, aesKey, useWorker, iceServers, relay):
|
case let .start(media, aesKey, useWorker, iceServers, relay):
|
||||||
try container.encode("start", forKey: .type)
|
try container.encode("start", forKey: .type)
|
||||||
|
@ -186,8 +187,9 @@ enum WCallCommand: Equatable, Encodable, Decodable {
|
||||||
let type = try container.decode(String.self, forKey: CodingKeys.type)
|
let type = try container.decode(String.self, forKey: CodingKeys.type)
|
||||||
switch type {
|
switch type {
|
||||||
case "capabilities":
|
case "capabilities":
|
||||||
|
let media = try container.decode(CallMediaType.self, forKey: CodingKeys.media)
|
||||||
let useWorker = try container.decode((Bool?).self, forKey: CodingKeys.useWorker)
|
let useWorker = try container.decode((Bool?).self, forKey: CodingKeys.useWorker)
|
||||||
self = .capabilities(useWorker: useWorker)
|
self = .capabilities(media: media, useWorker: useWorker)
|
||||||
case "start":
|
case "start":
|
||||||
let media = try container.decode(CallMediaType.self, forKey: CodingKeys.media)
|
let media = try container.decode(CallMediaType.self, forKey: CodingKeys.media)
|
||||||
let aesKey = try? container.decode(String.self, forKey: CodingKeys.aesKey)
|
let aesKey = try? container.decode(String.self, forKey: CodingKeys.aesKey)
|
||||||
|
|
25
apps/ios/Shared/Views/UserSettings/CallSettings.swift
Normal file
25
apps/ios/Shared/Views/UserSettings/CallSettings.swift
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
//
|
||||||
|
// CallSettings.swift
|
||||||
|
// SimpleX (iOS)
|
||||||
|
//
|
||||||
|
// Created by Evgeny on 27/05/2022.
|
||||||
|
// Copyright © 2022 SimpleX Chat. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct CallSettings: View {
|
||||||
|
@AppStorage(DEFAULT_WEBRTC_POLICY_RELAY) private var webrtcPolicyRelay = true
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
List {
|
||||||
|
Toggle("Connect via relay", isOn: $webrtcPolicyRelay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CallSettings_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
CallSettings()
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,13 @@ let appBuild = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as?
|
||||||
|
|
||||||
let DEFAULT_USE_NOTIFICATIONS = "useNotifications"
|
let DEFAULT_USE_NOTIFICATIONS = "useNotifications"
|
||||||
let DEFAULT_PENDING_CONNECTIONS = "pendingConnections"
|
let DEFAULT_PENDING_CONNECTIONS = "pendingConnections"
|
||||||
|
let DEFAULT_WEBRTC_POLICY_RELAY = "webrtcPolicyRelay"
|
||||||
|
|
||||||
|
let appDefaults: [String:Any] = [
|
||||||
|
DEFAULT_USE_NOTIFICATIONS: false,
|
||||||
|
DEFAULT_PENDING_CONNECTIONS: true,
|
||||||
|
DEFAULT_WEBRTC_POLICY_RELAY: true
|
||||||
|
]
|
||||||
|
|
||||||
private var indent: CGFloat = 36
|
private var indent: CGFloat = 36
|
||||||
|
|
||||||
|
@ -59,6 +66,12 @@ struct SettingsView: View {
|
||||||
} label: {
|
} label: {
|
||||||
settingsRow("server.rack") { Text("SMP servers") }
|
settingsRow("server.rack") { Text("SMP servers") }
|
||||||
}
|
}
|
||||||
|
NavigationLink {
|
||||||
|
CallSettings()
|
||||||
|
.navigationTitle("Call settings")
|
||||||
|
} label: {
|
||||||
|
settingsRow("video") { Text("Call settings") }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("Help") {
|
Section("Help") {
|
||||||
|
|
|
@ -20,11 +20,6 @@
|
||||||
<target> (can be copied)</target>
|
<target> (can be copied)</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id=" wants to connect with you via " xml:space="preserve">
|
|
||||||
<source> wants to connect with you via </source>
|
|
||||||
<target> wants to connect with you via </target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="!1 colored!" xml:space="preserve">
|
<trans-unit id="!1 colored!" xml:space="preserve">
|
||||||
<source>!1 colored!</source>
|
<source>!1 colored!</source>
|
||||||
<target>!1 colored!</target>
|
<target>!1 colored!</target>
|
||||||
|
@ -133,7 +128,8 @@
|
||||||
<trans-unit id="Accept" xml:space="preserve">
|
<trans-unit id="Accept" xml:space="preserve">
|
||||||
<source>Accept</source>
|
<source>Accept</source>
|
||||||
<target>Accept</target>
|
<target>Accept</target>
|
||||||
<note>accept contact request via notification</note>
|
<note>accept contact request via notification
|
||||||
|
accept incoming call via notification</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Accept contact" xml:space="preserve">
|
<trans-unit id="Accept contact" xml:space="preserve">
|
||||||
<source>Accept contact</source>
|
<source>Accept contact</source>
|
||||||
|
@ -165,11 +161,6 @@
|
||||||
<target>Already connected?</target>
|
<target>Already connected?</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Answer" xml:space="preserve">
|
|
||||||
<source>Answer</source>
|
|
||||||
<target>Answer</target>
|
|
||||||
<note>accept incoming call via notification</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="Answer call" xml:space="preserve">
|
<trans-unit id="Answer call" xml:space="preserve">
|
||||||
<source>Answer call</source>
|
<source>Answer call</source>
|
||||||
<target>Answer call</target>
|
<target>Answer call</target>
|
||||||
|
@ -185,16 +176,16 @@
|
||||||
<target>Call already ended!</target>
|
<target>Call already ended!</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="Call settings" xml:space="preserve">
|
||||||
|
<source>Call settings</source>
|
||||||
|
<target>Call settings</target>
|
||||||
|
<note>No comment provided by engineer.</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="Cancel" xml:space="preserve">
|
<trans-unit id="Cancel" xml:space="preserve">
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<target>Cancel</target>
|
<target>Cancel</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Capabilities" xml:space="preserve">
|
|
||||||
<source>Capabilities</source>
|
|
||||||
<target>Capabilities</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="Chat console" xml:space="preserve">
|
<trans-unit id="Chat console" xml:space="preserve">
|
||||||
<source>Chat console</source>
|
<source>Chat console</source>
|
||||||
<target>Chat console</target>
|
<target>Chat console</target>
|
||||||
|
@ -275,6 +266,11 @@
|
||||||
<target>Connect via one-time link?</target>
|
<target>Connect via one-time link?</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="Connect via relay" xml:space="preserve">
|
||||||
|
<source>Connect via relay</source>
|
||||||
|
<target>Connect via relay</target>
|
||||||
|
<note>No comment provided by engineer.</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="Connect with the developers" xml:space="preserve">
|
<trans-unit id="Connect with the developers" xml:space="preserve">
|
||||||
<source>Connect with the developers</source>
|
<source>Connect with the developers</source>
|
||||||
<target>Connect with the developers</target>
|
<target>Connect with the developers</target>
|
||||||
|
@ -460,11 +456,6 @@
|
||||||
<target>Enable notifications? (BETA)</target>
|
<target>Enable notifications? (BETA)</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="End" xml:space="preserve">
|
|
||||||
<source>End</source>
|
|
||||||
<target>End</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="Enter one SMP server per line:" xml:space="preserve">
|
<trans-unit id="Enter one SMP server per line:" xml:space="preserve">
|
||||||
<source>Enter one SMP server per line:</source>
|
<source>Enter one SMP server per line:</source>
|
||||||
<target>Enter one SMP server per line:</target>
|
<target>Enter one SMP server per line:</target>
|
||||||
|
@ -540,11 +531,6 @@
|
||||||
<target>How to use markdown</target>
|
<target>How to use markdown</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICE" xml:space="preserve">
|
|
||||||
<source>ICE</source>
|
|
||||||
<target>ICE</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="If you can't meet in person, **show QR code in the video call**, or share the link." xml:space="preserve">
|
<trans-unit id="If you can't meet in person, **show QR code in the video call**, or share the link." xml:space="preserve">
|
||||||
<source>If you can't meet in person, **show QR code in the video call**, or share the link.</source>
|
<source>If you can't meet in person, **show QR code in the video call**, or share the link.</source>
|
||||||
<target>If you can't meet in person, **show QR code in the video call**, or share the link.</target>
|
<target>If you can't meet in person, **show QR code in the video call**, or share the link.</target>
|
||||||
|
@ -558,7 +544,7 @@
|
||||||
<trans-unit id="Ignore" xml:space="preserve">
|
<trans-unit id="Ignore" xml:space="preserve">
|
||||||
<source>Ignore</source>
|
<source>Ignore</source>
|
||||||
<target>Ignore</target>
|
<target>Ignore</target>
|
||||||
<note>ignore incoming call via notification</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Image will be received when your contact is online, please wait or check later!" xml:space="preserve">
|
<trans-unit id="Image will be received when your contact is online, please wait or check later!" xml:space="preserve">
|
||||||
<source>Image will be received when your contact is online, please wait or check later!</source>
|
<source>Image will be received when your contact is online, please wait or check later!</source>
|
||||||
|
@ -748,7 +734,7 @@
|
||||||
<trans-unit id="Reject" xml:space="preserve">
|
<trans-unit id="Reject" xml:space="preserve">
|
||||||
<source>Reject</source>
|
<source>Reject</source>
|
||||||
<target>Reject</target>
|
<target>Reject</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>reject incoming call via notification</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Reject contact (sender NOT notified)" xml:space="preserve">
|
<trans-unit id="Reject contact (sender NOT notified)" xml:space="preserve">
|
||||||
<source>Reject contact (sender NOT notified)</source>
|
<source>Reject contact (sender NOT notified)</source>
|
||||||
|
@ -795,11 +781,6 @@
|
||||||
<target>Scan contact's QR code</target>
|
<target>Scan contact's QR code</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Send" xml:space="preserve">
|
|
||||||
<source>Send</source>
|
|
||||||
<target>Send</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="Server connected" xml:space="preserve">
|
<trans-unit id="Server connected" xml:space="preserve">
|
||||||
<source>Server connected</source>
|
<source>Server connected</source>
|
||||||
<target>Server connected</target>
|
<target>Server connected</target>
|
||||||
|
@ -830,11 +811,6 @@
|
||||||
<target>Show pending connections</target>
|
<target>Show pending connections</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Start" xml:space="preserve">
|
|
||||||
<source>Start</source>
|
|
||||||
<target>Start</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="Take picture" xml:space="preserve">
|
<trans-unit id="Take picture" xml:space="preserve">
|
||||||
<source>Take picture</source>
|
<source>Take picture</source>
|
||||||
<target>Take picture</target>
|
<target>Take picture</target>
|
||||||
|
@ -1113,9 +1089,9 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>above, then choose:</target>
|
<target>above, then choose:</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="accepted" xml:space="preserve">
|
<trans-unit id="accepted call" xml:space="preserve">
|
||||||
<source>accepted</source>
|
<source>accepted call</source>
|
||||||
<target>accepted</target>
|
<target>accepted call</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
|
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
|
||||||
|
@ -1128,6 +1104,16 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>bold</target>
|
<target>bold</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="call error" xml:space="preserve">
|
||||||
|
<source>call error</source>
|
||||||
|
<target>call error</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="call in progress" xml:space="preserve">
|
||||||
|
<source>call in progress</source>
|
||||||
|
<target>call in progress</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="calling…" xml:space="preserve">
|
<trans-unit id="calling…" xml:space="preserve">
|
||||||
<source>calling…</source>
|
<source>calling…</source>
|
||||||
<target>calling…</target>
|
<target>calling…</target>
|
||||||
|
@ -1148,11 +1134,15 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>connected</target>
|
<target>connected</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="connecting call…" xml:space="preserve">
|
||||||
|
<source>connecting call…</source>
|
||||||
|
<target>connecting call…</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="connecting…" xml:space="preserve">
|
<trans-unit id="connecting…" xml:space="preserve">
|
||||||
<source>connecting…</source>
|
<source>connecting…</source>
|
||||||
<target>connecting…</target>
|
<target>connecting…</target>
|
||||||
<note>call status
|
<note>chat list item title</note>
|
||||||
chat list item title</note>
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="connection established" xml:space="preserve">
|
<trans-unit id="connection established" xml:space="preserve">
|
||||||
<source>connection established</source>
|
<source>connection established</source>
|
||||||
|
@ -1184,19 +1174,14 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>e2e encrypted</target>
|
<target>e2e encrypted</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ended %@" xml:space="preserve">
|
<trans-unit id="ended" xml:space="preserve">
|
||||||
<source>ended %@</source>
|
<source>ended</source>
|
||||||
<target>ended %@</target>
|
<target>ended</target>
|
||||||
<note>call status</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="error" xml:space="preserve">
|
<trans-unit id="ended call %@" xml:space="preserve">
|
||||||
<source>error</source>
|
<source>ended call %@</source>
|
||||||
<target>error</target>
|
<target>ended call %@</target>
|
||||||
<note>call status</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="in progress" xml:space="preserve">
|
|
||||||
<source>in progress</source>
|
|
||||||
<target>in progress</target>
|
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="invited to connect" xml:space="preserve">
|
<trans-unit id="invited to connect" xml:space="preserve">
|
||||||
|
@ -1209,9 +1194,9 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>italic</target>
|
<target>italic</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="missed" xml:space="preserve">
|
<trans-unit id="missed call" xml:space="preserve">
|
||||||
<source>missed</source>
|
<source>missed call</source>
|
||||||
<target>missed</target>
|
<target>missed call</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="no e2e encryption" xml:space="preserve">
|
<trans-unit id="no e2e encryption" xml:space="preserve">
|
||||||
|
@ -1234,9 +1219,14 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>received answer…</target>
|
<target>received answer…</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="rejected" xml:space="preserve">
|
<trans-unit id="received confirmation…" xml:space="preserve">
|
||||||
<source>rejected</source>
|
<source>received confirmation…</source>
|
||||||
<target>rejected</target>
|
<target>received confirmation…</target>
|
||||||
|
<note>No comment provided by engineer.</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="rejected call" xml:space="preserve">
|
||||||
|
<source>rejected call</source>
|
||||||
|
<target>rejected call</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="secret" xml:space="preserve">
|
<trans-unit id="secret" xml:space="preserve">
|
||||||
|
@ -1299,11 +1289,6 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>wants to connect to you!</target>
|
<target>wants to connect to you!</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="with e2e encryption" xml:space="preserve">
|
|
||||||
<source>with e2e encryption</source>
|
|
||||||
<target>with e2e encryption</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="you shared one-time link" xml:space="preserve">
|
<trans-unit id="you shared one-time link" xml:space="preserve">
|
||||||
<source>you shared one-time link</source>
|
<source>you shared one-time link</source>
|
||||||
<target>you shared one-time link</target>
|
<target>you shared one-time link</target>
|
||||||
|
@ -1410,9 +1395,9 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>You can now send messages to %@</target>
|
<target>You can now send messages to %@</target>
|
||||||
<note>notification body</note>
|
<note>notification body</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="accepted" xml:space="preserve">
|
<trans-unit id="accepted call" xml:space="preserve">
|
||||||
<source>accepted</source>
|
<source>accepted call</source>
|
||||||
<target>accepted</target>
|
<target>accepted call</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
|
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
|
||||||
|
@ -1420,16 +1405,30 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>audio call (not e2e encrypted)</target>
|
<target>audio call (not e2e encrypted)</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="call error" xml:space="preserve">
|
||||||
|
<source>call error</source>
|
||||||
|
<target>call error</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="call in progress" xml:space="preserve">
|
||||||
|
<source>call in progress</source>
|
||||||
|
<target>call in progress</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="calling…" xml:space="preserve">
|
<trans-unit id="calling…" xml:space="preserve">
|
||||||
<source>calling…</source>
|
<source>calling…</source>
|
||||||
<target>calling…</target>
|
<target>calling…</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="connecting call…" xml:space="preserve">
|
||||||
|
<source>connecting call…</source>
|
||||||
|
<target>connecting call…</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="connecting…" xml:space="preserve">
|
<trans-unit id="connecting…" xml:space="preserve">
|
||||||
<source>connecting…</source>
|
<source>connecting…</source>
|
||||||
<target>connecting…</target>
|
<target>connecting…</target>
|
||||||
<note>call status
|
<note>chat list item title</note>
|
||||||
chat list item title</note>
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="connection established" xml:space="preserve">
|
<trans-unit id="connection established" xml:space="preserve">
|
||||||
<source>connection established</source>
|
<source>connection established</source>
|
||||||
|
@ -1446,19 +1445,9 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>deleted</target>
|
<target>deleted</target>
|
||||||
<note>deleted chat item</note>
|
<note>deleted chat item</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ended %@" xml:space="preserve">
|
<trans-unit id="ended call %@" xml:space="preserve">
|
||||||
<source>ended %@</source>
|
<source>ended call %@</source>
|
||||||
<target>ended %@</target>
|
<target>ended call %@</target>
|
||||||
<note>call status</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="error" xml:space="preserve">
|
|
||||||
<source>error</source>
|
|
||||||
<target>error</target>
|
|
||||||
<note>call status</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="in progress" xml:space="preserve">
|
|
||||||
<source>in progress</source>
|
|
||||||
<target>in progress</target>
|
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="invited to connect" xml:space="preserve">
|
<trans-unit id="invited to connect" xml:space="preserve">
|
||||||
|
@ -1466,19 +1455,14 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>invited to connect</target>
|
<target>invited to connect</target>
|
||||||
<note>chat list item title</note>
|
<note>chat list item title</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="missed" xml:space="preserve">
|
<trans-unit id="missed call" xml:space="preserve">
|
||||||
<source>missed</source>
|
<source>missed call</source>
|
||||||
<target>missed</target>
|
<target>missed call</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="no e2e encryption" xml:space="preserve">
|
<trans-unit id="rejected call" xml:space="preserve">
|
||||||
<source>no e2e encryption</source>
|
<source>rejected call</source>
|
||||||
<target>no e2e encryption</target>
|
<target>rejected call</target>
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="rejected" xml:space="preserve">
|
|
||||||
<source>rejected</source>
|
|
||||||
<target>rejected</target>
|
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="via contact address link" xml:space="preserve">
|
<trans-unit id="via contact address link" xml:space="preserve">
|
||||||
|
@ -1496,11 +1480,6 @@ SimpleX servers cannot see your profile.</target>
|
||||||
<target>video call (not e2e encrypted)</target>
|
<target>video call (not e2e encrypted)</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="with e2e encryption" xml:space="preserve">
|
|
||||||
<source>with e2e encryption</source>
|
|
||||||
<target>with e2e encryption</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="you shared one-time link" xml:space="preserve">
|
<trans-unit id="you shared one-time link" xml:space="preserve">
|
||||||
<source>you shared one-time link</source>
|
<source>you shared one-time link</source>
|
||||||
<target>you shared one-time link</target>
|
<target>you shared one-time link</target>
|
||||||
|
|
Binary file not shown.
|
@ -20,11 +20,6 @@
|
||||||
<target> (можно скопировать)</target>
|
<target> (можно скопировать)</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id=" wants to connect with you via " xml:space="preserve">
|
|
||||||
<source> wants to connect with you via </source>
|
|
||||||
<target> хочет связаться с вами через </target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="!1 colored!" xml:space="preserve">
|
<trans-unit id="!1 colored!" xml:space="preserve">
|
||||||
<source>!1 colored!</source>
|
<source>!1 colored!</source>
|
||||||
<target>!1 цвет!</target>
|
<target>!1 цвет!</target>
|
||||||
|
@ -133,7 +128,8 @@
|
||||||
<trans-unit id="Accept" xml:space="preserve">
|
<trans-unit id="Accept" xml:space="preserve">
|
||||||
<source>Accept</source>
|
<source>Accept</source>
|
||||||
<target>Принять</target>
|
<target>Принять</target>
|
||||||
<note>accept contact request via notification</note>
|
<note>accept contact request via notification
|
||||||
|
accept incoming call via notification</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Accept contact" xml:space="preserve">
|
<trans-unit id="Accept contact" xml:space="preserve">
|
||||||
<source>Accept contact</source>
|
<source>Accept contact</source>
|
||||||
|
@ -165,11 +161,6 @@
|
||||||
<target>Соединение уже установлено?</target>
|
<target>Соединение уже установлено?</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Answer" xml:space="preserve">
|
|
||||||
<source>Answer</source>
|
|
||||||
<target>Ответить</target>
|
|
||||||
<note>accept incoming call via notification</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="Answer call" xml:space="preserve">
|
<trans-unit id="Answer call" xml:space="preserve">
|
||||||
<source>Answer call</source>
|
<source>Answer call</source>
|
||||||
<target>Принять звонок</target>
|
<target>Принять звонок</target>
|
||||||
|
@ -185,16 +176,16 @@
|
||||||
<target>Звонок уже завершен!</target>
|
<target>Звонок уже завершен!</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="Call settings" xml:space="preserve">
|
||||||
|
<source>Call settings</source>
|
||||||
|
<target>Настройки звонков</target>
|
||||||
|
<note>No comment provided by engineer.</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="Cancel" xml:space="preserve">
|
<trans-unit id="Cancel" xml:space="preserve">
|
||||||
<source>Cancel</source>
|
<source>Cancel</source>
|
||||||
<target>Отменить</target>
|
<target>Отменить</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Capabilities" xml:space="preserve">
|
|
||||||
<source>Capabilities</source>
|
|
||||||
<target>Возможности</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="Chat console" xml:space="preserve">
|
<trans-unit id="Chat console" xml:space="preserve">
|
||||||
<source>Chat console</source>
|
<source>Chat console</source>
|
||||||
<target>Консоль</target>
|
<target>Консоль</target>
|
||||||
|
@ -275,6 +266,11 @@
|
||||||
<target>Соединиться через одноразовую ссылку?</target>
|
<target>Соединиться через одноразовую ссылку?</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="Connect via relay" xml:space="preserve">
|
||||||
|
<source>Connect via relay</source>
|
||||||
|
<target>Соединяться через сервер (relay)</target>
|
||||||
|
<note>No comment provided by engineer.</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="Connect with the developers" xml:space="preserve">
|
<trans-unit id="Connect with the developers" xml:space="preserve">
|
||||||
<source>Connect with the developers</source>
|
<source>Connect with the developers</source>
|
||||||
<target>Соединиться с разработчиками</target>
|
<target>Соединиться с разработчиками</target>
|
||||||
|
@ -460,11 +456,6 @@
|
||||||
<target>Включить уведомления? (БЕТА)</target>
|
<target>Включить уведомления? (БЕТА)</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="End" xml:space="preserve">
|
|
||||||
<source>End</source>
|
|
||||||
<target>Завершить</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="Enter one SMP server per line:" xml:space="preserve">
|
<trans-unit id="Enter one SMP server per line:" xml:space="preserve">
|
||||||
<source>Enter one SMP server per line:</source>
|
<source>Enter one SMP server per line:</source>
|
||||||
<target>Введите SMP серверы, каждый на отдельной строке:</target>
|
<target>Введите SMP серверы, каждый на отдельной строке:</target>
|
||||||
|
@ -540,11 +531,6 @@
|
||||||
<target>Как форматировать</target>
|
<target>Как форматировать</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICE" xml:space="preserve">
|
|
||||||
<source>ICE</source>
|
|
||||||
<target>ICE</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="If you can't meet in person, **show QR code in the video call**, or share the link." xml:space="preserve">
|
<trans-unit id="If you can't meet in person, **show QR code in the video call**, or share the link." xml:space="preserve">
|
||||||
<source>If you can't meet in person, **show QR code in the video call**, or share the link.</source>
|
<source>If you can't meet in person, **show QR code in the video call**, or share the link.</source>
|
||||||
<target>Если вы не можете встретиться лично, вы можете **показать QR код во время видеозвонка**, или поделиться ссылкой.</target>
|
<target>Если вы не можете встретиться лично, вы можете **показать QR код во время видеозвонка**, или поделиться ссылкой.</target>
|
||||||
|
@ -558,7 +544,7 @@
|
||||||
<trans-unit id="Ignore" xml:space="preserve">
|
<trans-unit id="Ignore" xml:space="preserve">
|
||||||
<source>Ignore</source>
|
<source>Ignore</source>
|
||||||
<target>Не отвечать</target>
|
<target>Не отвечать</target>
|
||||||
<note>ignore incoming call via notification</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Image will be received when your contact is online, please wait or check later!" xml:space="preserve">
|
<trans-unit id="Image will be received when your contact is online, please wait or check later!" xml:space="preserve">
|
||||||
<source>Image will be received when your contact is online, please wait or check later!</source>
|
<source>Image will be received when your contact is online, please wait or check later!</source>
|
||||||
|
@ -748,7 +734,7 @@
|
||||||
<trans-unit id="Reject" xml:space="preserve">
|
<trans-unit id="Reject" xml:space="preserve">
|
||||||
<source>Reject</source>
|
<source>Reject</source>
|
||||||
<target>Отклонить</target>
|
<target>Отклонить</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>reject incoming call via notification</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Reject contact (sender NOT notified)" xml:space="preserve">
|
<trans-unit id="Reject contact (sender NOT notified)" xml:space="preserve">
|
||||||
<source>Reject contact (sender NOT notified)</source>
|
<source>Reject contact (sender NOT notified)</source>
|
||||||
|
@ -795,11 +781,6 @@
|
||||||
<target>Сосканировать QR код контакта</target>
|
<target>Сосканировать QR код контакта</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Send" xml:space="preserve">
|
|
||||||
<source>Send</source>
|
|
||||||
<target>Отправить</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="Server connected" xml:space="preserve">
|
<trans-unit id="Server connected" xml:space="preserve">
|
||||||
<source>Server connected</source>
|
<source>Server connected</source>
|
||||||
<target>Установлено соединение с сервером</target>
|
<target>Установлено соединение с сервером</target>
|
||||||
|
@ -830,11 +811,6 @@
|
||||||
<target>Показать ожидаемые соединения</target>
|
<target>Показать ожидаемые соединения</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="Start" xml:space="preserve">
|
|
||||||
<source>Start</source>
|
|
||||||
<target>Начать</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="Take picture" xml:space="preserve">
|
<trans-unit id="Take picture" xml:space="preserve">
|
||||||
<source>Take picture</source>
|
<source>Take picture</source>
|
||||||
<target>Сделать фото</target>
|
<target>Сделать фото</target>
|
||||||
|
@ -1113,9 +1089,9 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>наверху, затем выберите:</target>
|
<target>наверху, затем выберите:</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="accepted" xml:space="preserve">
|
<trans-unit id="accepted call" xml:space="preserve">
|
||||||
<source>accepted</source>
|
<source>accepted call</source>
|
||||||
<target>принятый звонок</target>
|
<target> принятый звонок</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
|
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
|
||||||
|
@ -1128,6 +1104,16 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>жирный</target>
|
<target>жирный</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="call error" xml:space="preserve">
|
||||||
|
<source>call error</source>
|
||||||
|
<target>ошибка звонка</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="call in progress" xml:space="preserve">
|
||||||
|
<source>call in progress</source>
|
||||||
|
<target>активный звонок</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="calling…" xml:space="preserve">
|
<trans-unit id="calling…" xml:space="preserve">
|
||||||
<source>calling…</source>
|
<source>calling…</source>
|
||||||
<target>входящий звонок…</target>
|
<target>входящий звонок…</target>
|
||||||
|
@ -1148,11 +1134,15 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>соединение установлено</target>
|
<target>соединение установлено</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="connecting call…" xml:space="preserve">
|
||||||
|
<source>connecting call…</source>
|
||||||
|
<target>звонок соединяется…</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="connecting…" xml:space="preserve">
|
<trans-unit id="connecting…" xml:space="preserve">
|
||||||
<source>connecting…</source>
|
<source>connecting…</source>
|
||||||
<target>соединяется…</target>
|
<target>соединяется…</target>
|
||||||
<note>call status
|
<note>chat list item title</note>
|
||||||
chat list item title</note>
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="connection established" xml:space="preserve">
|
<trans-unit id="connection established" xml:space="preserve">
|
||||||
<source>connection established</source>
|
<source>connection established</source>
|
||||||
|
@ -1184,19 +1174,14 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>e2e зашифровано</target>
|
<target>e2e зашифровано</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ended %@" xml:space="preserve">
|
<trans-unit id="ended" xml:space="preserve">
|
||||||
<source>ended %@</source>
|
<source>ended</source>
|
||||||
<target>завершен %@</target>
|
<target>завершён</target>
|
||||||
<note>call status</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="error" xml:space="preserve">
|
<trans-unit id="ended call %@" xml:space="preserve">
|
||||||
<source>error</source>
|
<source>ended call %@</source>
|
||||||
<target>ошибка соединения</target>
|
<target>завершённый звонок %@</target>
|
||||||
<note>call status</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="in progress" xml:space="preserve">
|
|
||||||
<source>in progress</source>
|
|
||||||
<target>активный звонок</target>
|
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="invited to connect" xml:space="preserve">
|
<trans-unit id="invited to connect" xml:space="preserve">
|
||||||
|
@ -1209,8 +1194,8 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>курсив</target>
|
<target>курсив</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="missed" xml:space="preserve">
|
<trans-unit id="missed call" xml:space="preserve">
|
||||||
<source>missed</source>
|
<source>missed call</source>
|
||||||
<target>пропущенный звонок</target>
|
<target>пропущенный звонок</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
@ -1234,9 +1219,14 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>получен ответ…</target>
|
<target>получен ответ…</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="rejected" xml:space="preserve">
|
<trans-unit id="received confirmation…" xml:space="preserve">
|
||||||
<source>rejected</source>
|
<source>received confirmation…</source>
|
||||||
<target>отклоненный звонок</target>
|
<target>получено подтверждение…</target>
|
||||||
|
<note>No comment provided by engineer.</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="rejected call" xml:space="preserve">
|
||||||
|
<source>rejected call</source>
|
||||||
|
<target>отклонённый звонок</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="secret" xml:space="preserve">
|
<trans-unit id="secret" xml:space="preserve">
|
||||||
|
@ -1299,11 +1289,6 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>хочет соединиться с вами!</target>
|
<target>хочет соединиться с вами!</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="with e2e encryption" xml:space="preserve">
|
|
||||||
<source>with e2e encryption</source>
|
|
||||||
<target>e2e зашифровано</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="you shared one-time link" xml:space="preserve">
|
<trans-unit id="you shared one-time link" xml:space="preserve">
|
||||||
<source>you shared one-time link</source>
|
<source>you shared one-time link</source>
|
||||||
<target>вы создали ссылку</target>
|
<target>вы создали ссылку</target>
|
||||||
|
@ -1410,9 +1395,9 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>Вы можете отправлять сообщения %@</target>
|
<target>Вы можете отправлять сообщения %@</target>
|
||||||
<note>notification body</note>
|
<note>notification body</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="accepted" xml:space="preserve">
|
<trans-unit id="accepted call" xml:space="preserve">
|
||||||
<source>accepted</source>
|
<source>accepted call</source>
|
||||||
<target>принятый звонок</target>
|
<target>принятный звонок</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
|
<trans-unit id="audio call (not e2e encrypted)" xml:space="preserve">
|
||||||
|
@ -1420,16 +1405,30 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>аудиозвонок (не e2e зашифрованный)</target>
|
<target>аудиозвонок (не e2e зашифрованный)</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="call error" xml:space="preserve">
|
||||||
|
<source>call error</source>
|
||||||
|
<target>ошибка звонка</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="call in progress" xml:space="preserve">
|
||||||
|
<source>call in progress</source>
|
||||||
|
<target>активный звонок</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="calling…" xml:space="preserve">
|
<trans-unit id="calling…" xml:space="preserve">
|
||||||
<source>calling…</source>
|
<source>calling…</source>
|
||||||
<target>входящий звонок…</target>
|
<target>входящий звонок…</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="connecting call…" xml:space="preserve">
|
||||||
|
<source>connecting call…</source>
|
||||||
|
<target>звонок соединяется…</target>
|
||||||
|
<note>call status</note>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="connecting…" xml:space="preserve">
|
<trans-unit id="connecting…" xml:space="preserve">
|
||||||
<source>connecting…</source>
|
<source>connecting…</source>
|
||||||
<target>соединяется…</target>
|
<target>соединяется…</target>
|
||||||
<note>call status
|
<note>chat list item title</note>
|
||||||
chat list item title</note>
|
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="connection established" xml:space="preserve">
|
<trans-unit id="connection established" xml:space="preserve">
|
||||||
<source>connection established</source>
|
<source>connection established</source>
|
||||||
|
@ -1446,19 +1445,9 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>удалено</target>
|
<target>удалено</target>
|
||||||
<note>deleted chat item</note>
|
<note>deleted chat item</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ended %@" xml:space="preserve">
|
<trans-unit id="ended call %@" xml:space="preserve">
|
||||||
<source>ended %@</source>
|
<source>ended call %@</source>
|
||||||
<target>завершен %@</target>
|
<target>завершённый звонок %@</target>
|
||||||
<note>call status</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="error" xml:space="preserve">
|
|
||||||
<source>error</source>
|
|
||||||
<target>ошибка соединения</target>
|
|
||||||
<note>call status</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="in progress" xml:space="preserve">
|
|
||||||
<source>in progress</source>
|
|
||||||
<target>активный звонок</target>
|
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="invited to connect" xml:space="preserve">
|
<trans-unit id="invited to connect" xml:space="preserve">
|
||||||
|
@ -1466,19 +1455,14 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>приглашение соединиться</target>
|
<target>приглашение соединиться</target>
|
||||||
<note>chat list item title</note>
|
<note>chat list item title</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="missed" xml:space="preserve">
|
<trans-unit id="missed call" xml:space="preserve">
|
||||||
<source>missed</source>
|
<source>missed call</source>
|
||||||
<target>пропущенный звонок</target>
|
<target>пропущенный звонок</target>
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="no e2e encryption" xml:space="preserve">
|
<trans-unit id="rejected call" xml:space="preserve">
|
||||||
<source>no e2e encryption</source>
|
<source>rejected call</source>
|
||||||
<target>нет e2e шифрования</target>
|
<target>отклонённый звонок</target>
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="rejected" xml:space="preserve">
|
|
||||||
<source>rejected</source>
|
|
||||||
<target>отклоненный звонок</target>
|
|
||||||
<note>call status</note>
|
<note>call status</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="via contact address link" xml:space="preserve">
|
<trans-unit id="via contact address link" xml:space="preserve">
|
||||||
|
@ -1496,11 +1480,6 @@ SimpleX серверы не могут получить доступ к ваше
|
||||||
<target>видеозвонок (не e2e зашифрованный)</target>
|
<target>видеозвонок (не e2e зашифрованный)</target>
|
||||||
<note>No comment provided by engineer.</note>
|
<note>No comment provided by engineer.</note>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="with e2e encryption" xml:space="preserve">
|
|
||||||
<source>with e2e encryption</source>
|
|
||||||
<target>e2e зашифровано</target>
|
|
||||||
<note>No comment provided by engineer.</note>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="you shared one-time link" xml:space="preserve">
|
<trans-unit id="you shared one-time link" xml:space="preserve">
|
||||||
<source>you shared one-time link</source>
|
<source>you shared one-time link</source>
|
||||||
<target>вы создали одноразовую ссылку</target>
|
<target>вы создали одноразовую ссылку</target>
|
||||||
|
|
Binary file not shown.
|
@ -14,16 +14,24 @@
|
||||||
"Accept contact request from %@?" = "Принять запрос на соединение от %@?";
|
"Accept contact request from %@?" = "Принять запрос на соединение от %@?";
|
||||||
|
|
||||||
/* call status */
|
/* call status */
|
||||||
"accepted" = "принятый звонок";
|
"accepted call" = "принятный звонок";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"audio call (not e2e encrypted)" = "аудиозвонок (не e2e зашифрованный)";
|
"audio call (not e2e encrypted)" = "аудиозвонок (не e2e зашифрованный)";
|
||||||
|
|
||||||
|
/* call status */
|
||||||
|
"call error" = "ошибка звонка";
|
||||||
|
|
||||||
|
/* call status */
|
||||||
|
"call in progress" = "активный звонок";
|
||||||
|
|
||||||
/* call status */
|
/* call status */
|
||||||
"calling…" = "входящий звонок…";
|
"calling…" = "входящий звонок…";
|
||||||
|
|
||||||
/* call status
|
/* call status */
|
||||||
chat list item title */
|
"connecting call…" = "звонок соединяется…";
|
||||||
|
|
||||||
|
/* chat list item title */
|
||||||
"connecting…" = "соединяется…";
|
"connecting…" = "соединяется…";
|
||||||
|
|
||||||
/* chat list item title (it should not be shown */
|
/* chat list item title (it should not be shown */
|
||||||
|
@ -36,13 +44,7 @@
|
||||||
"deleted" = "удалено";
|
"deleted" = "удалено";
|
||||||
|
|
||||||
/* call status */
|
/* call status */
|
||||||
"ended %@" = "завершен %@";
|
"ended call %@" = "завершённый звонок %@";
|
||||||
|
|
||||||
/* call status */
|
|
||||||
"error" = "ошибка соединения";
|
|
||||||
|
|
||||||
/* call status */
|
|
||||||
"in progress" = "активный звонок";
|
|
||||||
|
|
||||||
/* notification */
|
/* notification */
|
||||||
"Incoming audio call" = "Входящий аудиозвонок";
|
"Incoming audio call" = "Входящий аудиозвонок";
|
||||||
|
@ -54,13 +56,10 @@
|
||||||
"invited to connect" = "приглашение соединиться";
|
"invited to connect" = "приглашение соединиться";
|
||||||
|
|
||||||
/* call status */
|
/* call status */
|
||||||
"missed" = "пропущенный звонок";
|
"missed call" = "пропущенный звонок";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"no e2e encryption" = "нет e2e шифрования";
|
|
||||||
|
|
||||||
/* call status */
|
/* call status */
|
||||||
"rejected" = "отклоненный звонок";
|
"rejected call" = "отклонённый звонок";
|
||||||
|
|
||||||
/* chat list item description */
|
/* chat list item description */
|
||||||
"via contact address link" = "через ссылку-контакт";
|
"via contact address link" = "через ссылку-контакт";
|
||||||
|
@ -71,9 +70,6 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"video call (not e2e encrypted)" = "видеозвонок (не e2e зашифрованный)";
|
"video call (not e2e encrypted)" = "видеозвонок (не e2e зашифрованный)";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"with e2e encryption" = "e2e зашифровано";
|
|
||||||
|
|
||||||
/* notification body */
|
/* notification body */
|
||||||
"You can now send messages to %@" = "Вы можете отправлять сообщения %@";
|
"You can now send messages to %@" = "Вы можете отправлять сообщения %@";
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,8 @@
|
||||||
<false/>
|
<false/>
|
||||||
<key>UIBackgroundModes</key>
|
<key>UIBackgroundModes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>audio</string>
|
|
||||||
<string>fetch</string>
|
<string>fetch</string>
|
||||||
<string>remote-notification</string>
|
<string>remote-notification</string>
|
||||||
<string>voip</string>
|
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
3CDBCF4827FF621E00354CDD /* CILinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CDBCF4727FF621E00354CDD /* CILinkView.swift */; };
|
3CDBCF4827FF621E00354CDD /* CILinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CDBCF4727FF621E00354CDD /* CILinkView.swift */; };
|
||||||
5C029EA82837DBB3004A9677 /* CICallItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA72837DBB3004A9677 /* CICallItemView.swift */; };
|
5C029EA82837DBB3004A9677 /* CICallItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA72837DBB3004A9677 /* CICallItemView.swift */; };
|
||||||
5C029EAA283942EA004A9677 /* CallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA9283942EA004A9677 /* CallController.swift */; };
|
5C029EAA283942EA004A9677 /* CallController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C029EA9283942EA004A9677 /* CallController.swift */; };
|
||||||
|
5C05DF532840AA1D00C683F9 /* CallSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C05DF522840AA1D00C683F9 /* CallSettings.swift */; };
|
||||||
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; };
|
5C063D2727A4564100AEC577 /* ChatPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C063D2627A4564100AEC577 /* ChatPreviewView.swift */; };
|
||||||
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
|
5C116CDC27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
|
||||||
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; };
|
5C13730B28156D2700F43030 /* ContactConnectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C13730A28156D2700F43030 /* ContactConnectionView.swift */; };
|
||||||
|
@ -138,6 +139,7 @@
|
||||||
3CDBCF4727FF621E00354CDD /* CILinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CILinkView.swift; sourceTree = "<group>"; };
|
3CDBCF4727FF621E00354CDD /* CILinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CILinkView.swift; sourceTree = "<group>"; };
|
||||||
5C029EA72837DBB3004A9677 /* CICallItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CICallItemView.swift; sourceTree = "<group>"; };
|
5C029EA72837DBB3004A9677 /* CICallItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CICallItemView.swift; sourceTree = "<group>"; };
|
||||||
5C029EA9283942EA004A9677 /* CallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallController.swift; sourceTree = "<group>"; };
|
5C029EA9283942EA004A9677 /* CallController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallController.swift; sourceTree = "<group>"; };
|
||||||
|
5C05DF522840AA1D00C683F9 /* CallSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallSettings.swift; sourceTree = "<group>"; };
|
||||||
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatPreviewView.swift; sourceTree = "<group>"; };
|
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatPreviewView.swift; sourceTree = "<group>"; };
|
||||||
5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestView.swift; sourceTree = "<group>"; };
|
5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestView.swift; sourceTree = "<group>"; };
|
||||||
5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = "<group>"; };
|
5C13730A28156D2700F43030 /* ContactConnectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactConnectionView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -463,6 +465,7 @@
|
||||||
children = (
|
children = (
|
||||||
5CB924D327A853F100ACCCDD /* SettingsButton.swift */,
|
5CB924D327A853F100ACCCDD /* SettingsButton.swift */,
|
||||||
5CB924D627A8563F00ACCCDD /* SettingsView.swift */,
|
5CB924D627A8563F00ACCCDD /* SettingsView.swift */,
|
||||||
|
5C05DF522840AA1D00C683F9 /* CallSettings.swift */,
|
||||||
5CB924E327A8683A00ACCCDD /* UserAddress.swift */,
|
5CB924E327A8683A00ACCCDD /* UserAddress.swift */,
|
||||||
5CB924E027A867BA00ACCCDD /* UserProfile.swift */,
|
5CB924E027A867BA00ACCCDD /* UserProfile.swift */,
|
||||||
5C577F7C27C83AA10006112D /* MarkdownHelp.swift */,
|
5C577F7C27C83AA10006112D /* MarkdownHelp.swift */,
|
||||||
|
@ -624,7 +627,6 @@
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
en,
|
en,
|
||||||
Base,
|
|
||||||
ru,
|
ru,
|
||||||
);
|
);
|
||||||
mainGroup = 5CA059BD279559F40002BEB4;
|
mainGroup = 5CA059BD279559F40002BEB4;
|
||||||
|
@ -717,6 +719,7 @@
|
||||||
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */,
|
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */,
|
||||||
5CA059ED279559F40002BEB4 /* ContentView.swift in Sources */,
|
5CA059ED279559F40002BEB4 /* ContentView.swift in Sources */,
|
||||||
5CCD403427A5F6DF00368C90 /* AddContactView.swift in Sources */,
|
5CCD403427A5F6DF00368C90 /* AddContactView.swift in Sources */,
|
||||||
|
5C05DF532840AA1D00C683F9 /* CallSettings.swift in Sources */,
|
||||||
5CFE0921282EEAF60002594B /* ZoomableScrollView.swift in Sources */,
|
5CFE0921282EEAF60002594B /* ZoomableScrollView.swift in Sources */,
|
||||||
5C3A88CE27DF50170060F1C2 /* DetermineWidth.swift in Sources */,
|
5C3A88CE27DF50170060F1C2 /* DetermineWidth.swift in Sources */,
|
||||||
5CB0BA962827143500B3292C /* MakeConnection.swift in Sources */,
|
5CB0BA962827143500B3292C /* MakeConnection.swift in Sources */,
|
||||||
|
|
|
@ -49,8 +49,7 @@
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
debugDocumentVersioning = "YES"
|
debugDocumentVersioning = "YES"
|
||||||
debugServiceExtension = "internal"
|
debugServiceExtension = "internal"
|
||||||
allowLocationSimulation = "YES"
|
allowLocationSimulation = "YES">
|
||||||
showNonLocalizedStrings = "YES">
|
|
||||||
<BuildableProductRunnable
|
<BuildableProductRunnable
|
||||||
runnableDebuggingMode = "0">
|
runnableDebuggingMode = "0">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
|
|
|
@ -7,9 +7,6 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
" (can be copied)" = " (можно скопировать)";
|
" (can be copied)" = " (можно скопировать)";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
" wants to connect with you via " = " хочет связаться с вами через ";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"_italic_" = "\\_курсив_";
|
"_italic_" = "\\_курсив_";
|
||||||
|
|
||||||
|
@ -88,7 +85,8 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"above, then choose:" = "наверху, затем выберите:";
|
"above, then choose:" = "наверху, затем выберите:";
|
||||||
|
|
||||||
/* accept contact request via notification */
|
/* accept contact request via notification
|
||||||
|
accept incoming call via notification */
|
||||||
"Accept" = "Принять";
|
"Accept" = "Принять";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
|
@ -98,7 +96,7 @@
|
||||||
"Accept contact request from %@?" = "Принять запрос на соединение от %@?";
|
"Accept contact request from %@?" = "Принять запрос на соединение от %@?";
|
||||||
|
|
||||||
/* call status */
|
/* call status */
|
||||||
"accepted" = "принятый звонок";
|
"accepted call" = " принятый звонок";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Add contact to start a new chat" = "Добавьте контакт, чтобы начать разговор";
|
"Add contact to start a new chat" = "Добавьте контакт, чтобы начать разговор";
|
||||||
|
@ -112,9 +110,6 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Already connected?" = "Соединение уже установлено?";
|
"Already connected?" = "Соединение уже установлено?";
|
||||||
|
|
||||||
/* accept incoming call via notification */
|
|
||||||
"Answer" = "Ответить";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Answer call" = "Принять звонок";
|
"Answer call" = "Принять звонок";
|
||||||
|
|
||||||
|
@ -130,15 +125,21 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Call already ended!" = "Звонок уже завершен!";
|
"Call already ended!" = "Звонок уже завершен!";
|
||||||
|
|
||||||
|
/* call status */
|
||||||
|
"call error" = "ошибка звонка";
|
||||||
|
|
||||||
|
/* call status */
|
||||||
|
"call in progress" = "активный звонок";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"Call settings" = "Настройки звонков";
|
||||||
|
|
||||||
/* call status */
|
/* call status */
|
||||||
"calling…" = "входящий звонок…";
|
"calling…" = "входящий звонок…";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Cancel" = "Отменить";
|
"Cancel" = "Отменить";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Capabilities" = "Возможности";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Chat console" = "Консоль";
|
"Chat console" = "Консоль";
|
||||||
|
|
||||||
|
@ -193,20 +194,25 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Connect via one-time link?" = "Соединиться через одноразовую ссылку?";
|
"Connect via one-time link?" = "Соединиться через одноразовую ссылку?";
|
||||||
|
|
||||||
|
/* No comment provided by engineer. */
|
||||||
|
"Connect via relay" = "Соединяться через сервер (relay)";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Connect with the developers" = "Соединиться с разработчиками";
|
"Connect with the developers" = "Соединиться с разработчиками";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"connected" = "соединение установлено";
|
"connected" = "соединение установлено";
|
||||||
|
|
||||||
|
/* call status */
|
||||||
|
"connecting call…" = "звонок соединяется…";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Connecting server…" = "Устанавливается соединение с сервером…";
|
"Connecting server…" = "Устанавливается соединение с сервером…";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Connecting server… (error: %@)" = "Устанавливается соединение с сервером… (ошибка: %@)";
|
"Connecting server… (error: %@)" = "Устанавливается соединение с сервером… (ошибка: %@)";
|
||||||
|
|
||||||
/* call status
|
/* chat list item title */
|
||||||
chat list item title */
|
|
||||||
"connecting…" = "соединяется…";
|
"connecting…" = "соединяется…";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
|
@ -330,17 +336,14 @@
|
||||||
"Enable notifications? (BETA)" = "Включить уведомления? (БЕТА)";
|
"Enable notifications? (BETA)" = "Включить уведомления? (БЕТА)";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"End" = "Завершить";
|
"ended" = "завершён";
|
||||||
|
|
||||||
/* call status */
|
/* call status */
|
||||||
"ended %@" = "завершен %@";
|
"ended call %@" = "завершённый звонок %@";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Enter one SMP server per line:" = "Введите SMP серверы, каждый на отдельной строке:";
|
"Enter one SMP server per line:" = "Введите SMP серверы, каждый на отдельной строке:";
|
||||||
|
|
||||||
/* call status */
|
|
||||||
"error" = "ошибка соединения";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Error deleting token" = "Ошибка удаления токена";
|
"Error deleting token" = "Ошибка удаления токена";
|
||||||
|
|
||||||
|
@ -383,16 +386,13 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"How to use markdown" = "Как форматировать";
|
"How to use markdown" = "Как форматировать";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"ICE" = "ICE";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"If you can't meet in person, **show QR code in the video call**, or share the link." = "Если вы не можете встретиться лично, вы можете **показать QR код во время видеозвонка**, или поделиться ссылкой.";
|
"If you can't meet in person, **show QR code in the video call**, or share the link." = "Если вы не можете встретиться лично, вы можете **показать QR код во время видеозвонка**, или поделиться ссылкой.";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link." = "Если вы не можете встретиться лично, вы можете **сосканировать QR код во время видеозвонка**, или ваш контакт может отправить вам ссылку.";
|
"If you cannot meet in person, you can **scan QR code in the video call**, or your contact can share an invitation link." = "Если вы не можете встретиться лично, вы можете **сосканировать QR код во время видеозвонка**, или ваш контакт может отправить вам ссылку.";
|
||||||
|
|
||||||
/* ignore incoming call via notification */
|
/* No comment provided by engineer. */
|
||||||
"Ignore" = "Не отвечать";
|
"Ignore" = "Не отвечать";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
|
@ -404,9 +404,6 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"In person or via a video call – the most secure way to connect." = "При встрече или в видеозвонке – самый безопасный способ установить соединение";
|
"In person or via a video call – the most secure way to connect." = "При встрече или в видеозвонке – самый безопасный способ установить соединение";
|
||||||
|
|
||||||
/* call status */
|
|
||||||
"in progress" = "активный звонок";
|
|
||||||
|
|
||||||
/* notification */
|
/* notification */
|
||||||
"Incoming audio call" = "Входящий аудиозвонок";
|
"Incoming audio call" = "Входящий аудиозвонок";
|
||||||
|
|
||||||
|
@ -453,7 +450,7 @@
|
||||||
"Message delivery error" = "Ошибка доставки сообщения";
|
"Message delivery error" = "Ошибка доставки сообщения";
|
||||||
|
|
||||||
/* call status */
|
/* call status */
|
||||||
"missed" = "пропущенный звонок";
|
"missed call" = "пропущенный звонок";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Most likely this contact has deleted the connection with you." = "Скорее всего, этот контакт удалил соединение с вами.";
|
"Most likely this contact has deleted the connection with you." = "Скорее всего, этот контакт удалил соединение с вами.";
|
||||||
|
@ -531,6 +528,9 @@
|
||||||
"received answer…" = "получен ответ…";
|
"received answer…" = "получен ответ…";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
|
"received confirmation…" = "получено подтверждение…";
|
||||||
|
|
||||||
|
/* reject incoming call via notification */
|
||||||
"Reject" = "Отклонить";
|
"Reject" = "Отклонить";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
|
@ -540,7 +540,7 @@
|
||||||
"Reject contact request" = "Отклонить запрос";
|
"Reject contact request" = "Отклонить запрос";
|
||||||
|
|
||||||
/* call status */
|
/* call status */
|
||||||
"rejected" = "отклоненный звонок";
|
"rejected call" = "отклонённый звонок";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Reply" = "Ответить";
|
"Reply" = "Ответить";
|
||||||
|
@ -563,9 +563,6 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"secret" = "секрет";
|
"secret" = "секрет";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Send" = "Отправить";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Server connected" = "Установлено соединение с сервером";
|
"Server connected" = "Установлено соединение с сервером";
|
||||||
|
|
||||||
|
@ -587,9 +584,6 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"SMP servers" = "SMP серверы";
|
"SMP servers" = "SMP серверы";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Start" = "Начать";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"starting…" = "инициализация…";
|
"starting…" = "инициализация…";
|
||||||
|
|
||||||
|
@ -698,9 +692,6 @@
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"Welcome %@!" = "Здравствуйте %@!";
|
"Welcome %@!" = "Здравствуйте %@!";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"with e2e encryption" = "e2e зашифровано";
|
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"You" = "Вы";
|
"You" = "Вы";
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ interface IWCallResponse {
|
||||||
|
|
||||||
interface WCCapabilities extends IWCallCommand {
|
interface WCCapabilities extends IWCallCommand {
|
||||||
type: "capabilities"
|
type: "capabilities"
|
||||||
|
media?: CallMediaType
|
||||||
useWorker?: boolean
|
useWorker?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,8 +290,7 @@ const processCommand = (function () {
|
||||||
const pc = new RTCPeerConnection(config.peerConnectionConfig)
|
const pc = new RTCPeerConnection(config.peerConnectionConfig)
|
||||||
const remoteStream = new MediaStream()
|
const remoteStream = new MediaStream()
|
||||||
const localCamera = VideoCamera.User
|
const localCamera = VideoCamera.User
|
||||||
const constraints = callMediaConstraints(mediaType, localCamera)
|
const localStream = await getLocalMediaStream(mediaType, localCamera)
|
||||||
const localStream = await navigator.mediaDevices.getUserMedia(constraints)
|
|
||||||
const iceCandidates = getIceCandidates(pc, config)
|
const iceCandidates = getIceCandidates(pc, config)
|
||||||
const call = {connection: pc, iceCandidates, localMedia: mediaType, localCamera, localStream, remoteStream, aesKey, useWorker}
|
const call = {connection: pc, iceCandidates, localMedia: mediaType, localCamera, localStream, remoteStream, aesKey, useWorker}
|
||||||
await setupMediaStreams(call)
|
await setupMediaStreams(call)
|
||||||
|
@ -352,11 +352,15 @@ const processCommand = (function () {
|
||||||
try {
|
try {
|
||||||
switch (command.type) {
|
switch (command.type) {
|
||||||
case "capabilities":
|
case "capabilities":
|
||||||
|
console.log("starting outgoing call - capabilities")
|
||||||
|
if (activeCall) endCall()
|
||||||
|
// This request for local media stream is made to prompt for camera/mic permissions on call start
|
||||||
|
if (command.media) await getLocalMediaStream(command.media, VideoCamera.User)
|
||||||
const encryption = supportsInsertableStreams(command.useWorker)
|
const encryption = supportsInsertableStreams(command.useWorker)
|
||||||
resp = {type: "capabilities", capabilities: {encryption}}
|
resp = {type: "capabilities", capabilities: {encryption}}
|
||||||
break
|
break
|
||||||
case "start": {
|
case "start": {
|
||||||
console.log("starting call")
|
console.log("starting incoming call - create webrtc session")
|
||||||
if (activeCall) endCall()
|
if (activeCall) endCall()
|
||||||
const {media, useWorker, iceServers, relay} = command
|
const {media, useWorker, iceServers, relay} = command
|
||||||
const encryption = supportsInsertableStreams(useWorker)
|
const encryption = supportsInsertableStreams(useWorker)
|
||||||
|
@ -582,8 +586,7 @@ const processCommand = (function () {
|
||||||
const pc = call.connection
|
const pc = call.connection
|
||||||
for (const t of call.localStream.getTracks()) t.stop()
|
for (const t of call.localStream.getTracks()) t.stop()
|
||||||
call.localCamera = camera
|
call.localCamera = camera
|
||||||
const constraints = callMediaConstraints(call.localMedia, camera)
|
const localStream = await getLocalMediaStream(call.localMedia, camera)
|
||||||
const localStream = await navigator.mediaDevices.getUserMedia(constraints)
|
|
||||||
replaceTracks(pc, localStream.getVideoTracks())
|
replaceTracks(pc, localStream.getVideoTracks())
|
||||||
replaceTracks(pc, localStream.getAudioTracks())
|
replaceTracks(pc, localStream.getAudioTracks())
|
||||||
call.localStream = localStream
|
call.localStream = localStream
|
||||||
|
@ -621,6 +624,11 @@ const processCommand = (function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLocalMediaStream(mediaType: CallMediaType, facingMode: VideoCamera): Promise<MediaStream> {
|
||||||
|
const constraints = callMediaConstraints(mediaType, facingMode)
|
||||||
|
return navigator.mediaDevices.getUserMedia(constraints)
|
||||||
|
}
|
||||||
|
|
||||||
function callMediaConstraints(mediaType: CallMediaType, facingMode: VideoCamera): MediaStreamConstraints {
|
function callMediaConstraints(mediaType: CallMediaType, facingMode: VideoCamera): MediaStreamConstraints {
|
||||||
switch (mediaType) {
|
switch (mediaType) {
|
||||||
case CallMediaType.Audio:
|
case CallMediaType.Audio:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue