Add advanced settings view

This commit is contained in:
Benoit Martins 2025-01-15 17:23:15 +01:00
parent eb68b50a43
commit 9b31eb3d99
7 changed files with 764 additions and 20 deletions

View file

@ -129,6 +129,7 @@
D78290BB2ADD40B2004AA85C /* ContactViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78290BA2ADD40B2004AA85C /* ContactViewModel.swift */; };
D783C77C2B1089B200622CC2 /* assistant_linphone_default_values in Resources */ = {isa = PBXBuildFile; fileRef = D783C77A2B1089B200622CC2 /* assistant_linphone_default_values */; };
D783C77D2B1089B200622CC2 /* assistant_third_party_default_values in Resources */ = {isa = PBXBuildFile; fileRef = D783C77B2B1089B200622CC2 /* assistant_third_party_default_values */; };
D78607712D36CB8A009E6A7E /* SettingsAdvancedFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78607702D36CB87009E6A7E /* SettingsAdvancedFragment.swift */; };
D78E06282BE3811D00CE3783 /* CallStatsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78E06272BE3811D00CE3783 /* CallStatsModel.swift */; };
D78E062A2BEA698E00CE3783 /* MediaEncryptedSheetBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78E06292BEA698E00CE3783 /* MediaEncryptedSheetBottomSheet.swift */; };
D78E062C2BEA69BC00CE3783 /* CallStatisticsSheetBottomSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D78E062B2BEA69BC00CE3783 /* CallStatisticsSheetBottomSheet.swift */; };
@ -329,6 +330,7 @@
D78290BA2ADD40B2004AA85C /* ContactViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactViewModel.swift; sourceTree = "<group>"; };
D783C77A2B1089B200622CC2 /* assistant_linphone_default_values */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = assistant_linphone_default_values; sourceTree = "<group>"; };
D783C77B2B1089B200622CC2 /* assistant_third_party_default_values */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = assistant_third_party_default_values; sourceTree = "<group>"; };
D78607702D36CB87009E6A7E /* SettingsAdvancedFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAdvancedFragment.swift; sourceTree = "<group>"; };
D78E06272BE3811D00CE3783 /* CallStatsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallStatsModel.swift; sourceTree = "<group>"; };
D78E06292BEA698E00CE3783 /* MediaEncryptedSheetBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaEncryptedSheetBottomSheet.swift; sourceTree = "<group>"; };
D78E062B2BEA69BC00CE3783 /* CallStatisticsSheetBottomSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallStatisticsSheetBottomSheet.swift; sourceTree = "<group>"; };
@ -939,6 +941,7 @@
D7DC096B2CFA192F00A6D47C /* Fragments */ = {
isa = PBXGroup;
children = (
D78607702D36CB87009E6A7E /* SettingsAdvancedFragment.swift */,
D732C38B2D311D2100F78100 /* SettingsFragment.swift */,
D7C5003F2D27F16900DD53EC /* AccountSettingsFragment.swift */,
D7DC096E2CFA1D7400A6D47C /* AccountProfileFragment.swift */,
@ -1199,6 +1202,7 @@
D796F2002B0BB61A0041115F /* ToastViewModel.swift in Sources */,
D7C3650A2AF001C300FE6142 /* EditContactFragment.swift in Sources */,
D7A03FBD2ACC2DB60081A588 /* ContactsView.swift in Sources */,
D78607712D36CB8A009E6A7E /* SettingsAdvancedFragment.swift in Sources */,
66E50A492BD12B2300AD61CA /* MeetingsView.swift in Sources */,
D719ABCF2ABC779A00B41C10 /* AccountLoginViewModel.swift in Sources */,
D717630D2BD7BD0E00464097 /* ParticipantsListFragment.swift in Sources */,

View file

@ -224,6 +224,24 @@ class CorePreferences {
}
}
static var acceptEarlyMedia: Bool {
get {
return Config.get().getBool(section: "sip", key: "incoming_calls_early_media", defaultValue: false)
}
set {
Config.get().setBool(section: "sip", key: "incoming_calls_early_media", value: newValue)
}
}
static var allowOutgoingEarlyMedia: Bool {
get {
return Config.get().getBool(section: "sip", key: "real_early_media", defaultValue: false)
}
set {
Config.get().setBool(section: "sip", key: "real_early_media", value: newValue)
}
}
private func copy(from: String, to: String, overrideIfExists: Bool = false) {
let fileManager = FileManager.default
if fileManager.fileExists(atPath: to), !overrideIfExists {

View file

@ -3825,6 +3825,9 @@
}
}
}
},
"DTLS" : {
},
"Error" : {
"localizations" : {
@ -5469,6 +5472,9 @@
}
}
}
},
"None" : {
},
"notification_chat_message_reaction_received" : {
"localizations" : {
@ -5651,6 +5657,193 @@
}
}
},
"settings_advanced_accept_early_media_title" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Accept early media"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Accepter l'early media"
}
}
}
},
"settings_advanced_allow_outgoing_early_media_title" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Allow outgoing early media"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Autoriser l'early media pour les appels sortants"
}
}
}
},
"settings_advanced_audio_codecs_title" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Audio codecs"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Codecs audio"
}
}
}
},
"settings_advanced_audio_devices_title" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Audio devices"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Périphériques audio"
}
}
}
},
"settings_advanced_device_id" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Device ID"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Nom de l'appareil"
}
}
}
},
"settings_advanced_device_id_hint" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Alpha-numerical characters only"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Caractères alpha-numériques uniquement"
}
}
}
},
"settings_advanced_download_apply_remote_provisioning" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Download & apply"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Télécharger & appliquer"
}
}
}
},
"settings_advanced_input_audio_device_title" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Default input audio device"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Périphérique de capture par défaut"
}
}
}
},
"settings_advanced_media_encryption_mandatory_title" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Media encryption mandatory"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Rendre le chiffrement du média obligatoire"
}
}
}
},
"settings_advanced_output_audio_device_title" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Default output audio device"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Périphérique d'écoute par défaut"
}
}
}
},
"settings_advanced_remote_provisioning_url" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Remote provisioning URL"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "URL de configuration distante"
}
}
}
},
"settings_advanced_title" : {
"extractionState" : "manual",
"localizations" : {
@ -5668,6 +5861,40 @@
}
}
},
"settings_advanced_upload_server_url" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "File sharing server URL"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "URL du serveur de partage de fichier"
}
}
}
},
"settings_advanced_video_codecs_title" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Video codecs"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Codecs vidéo"
}
}
}
},
"settings_calls_adaptive_rate_control_title" : {
"extractionState" : "manual",
"localizations" : {
@ -6630,6 +6857,9 @@
},
"sip.linphone.org" : {
"shouldTranslate" : false
},
"SRTP" : {
},
"start" : {
"localizations" : {
@ -6909,6 +7139,9 @@
},
"You will change this mode later" : {
},
"ZRTP" : {
}
},
"version" : "1.0"

View file

@ -130,6 +130,7 @@ struct SideMenu: View {
iconName: "gear",
title: "settings_title"
).onTapGesture {
self.menuClose()
withAnimation {
isShowSettingsFragment = true
}

View file

@ -0,0 +1,388 @@
/*
* Copyright (c) 2010-2023 Belledonne Communications SARL.
*
* This file is part of linphone-iphone
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import SwiftUI
import UniformTypeIdentifiers
struct SettingsAdvancedFragment: View {
@ObservedObject var settingsViewModel: SettingsViewModel
@Environment(\.dismiss) var dismiss
@State var audioDevicesIsOpen: Bool = false
@State var audioCodecsIsOpen: Bool = false
@State var videoCodecsIsOpen: Bool = false
@FocusState var isDeviceIdFocused: Bool
@FocusState var isUploadServerUrlFocused: Bool
@FocusState var isRemoteProvisioningUrlFocused: Bool
var body: some View {
ZStack {
VStack(spacing: 1) {
Rectangle()
.foregroundColor(Color.orangeMain500)
.edgesIgnoringSafeArea(.top)
.frame(height: 0)
HStack {
Image("caret-left")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.orangeMain500)
.frame(width: 25, height: 25, alignment: .leading)
.padding(.all, 10)
.padding(.top, 4)
.padding(.leading, -10)
.onTapGesture {
dismiss()
}
Text("settings_title")
.default_text_style_orange_800(styleSize: 16)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.top, 4)
.lineLimit(1)
Spacer()
}
.frame(maxWidth: .infinity)
.frame(height: 50)
.padding(.horizontal)
.padding(.bottom, 4)
.background(.white)
ScrollView {
VStack(spacing: 0) {
VStack(spacing: 30) {
Toggle("settings_calls_enable_fec_title", isOn: $settingsViewModel.enableFec)
.default_text_style_700(styleSize: 15)
VStack(alignment: .leading) {
Text("call_stats_media_encryption_title")
.default_text_style_700(styleSize: 15)
.padding(.bottom, -5)
Menu {
Button("None") { settingsViewModel.mediaEncryption = "None"}
Button("SRTP") { settingsViewModel.mediaEncryption = "SRTP"}
Button("ZRTP") { settingsViewModel.mediaEncryption = "ZRTP"}
Button("DTLS") { settingsViewModel.mediaEncryption = "DTLS"}
} label: {
Text(settingsViewModel.mediaEncryption)
.default_text_style(styleSize: 15)
.frame(maxWidth: .infinity, alignment: .leading)
Image("caret-down")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c500)
.frame(width: 20, height: 20)
}
.frame(height: 25)
.padding(.horizontal, 20)
.padding(.vertical, 15)
.cornerRadius(60)
.overlay(
RoundedRectangle(cornerRadius: 60)
.inset(by: 0.5)
.stroke(Color.gray200, lineWidth: 1)
)
}
Toggle("settings_advanced_media_encryption_mandatory_title", isOn: $settingsViewModel.mediaEncryptionMandatory)
.default_text_style_700(styleSize: 15)
Toggle("settings_advanced_accept_early_media_title", isOn: $settingsViewModel.acceptEarlyMedia)
.default_text_style_700(styleSize: 15)
Toggle("settings_advanced_allow_outgoing_early_media_title", isOn: $settingsViewModel.allowOutgoingEarlyMedia)
.default_text_style_700(styleSize: 15)
VStack(alignment: .leading) {
Text("settings_advanced_device_id")
.default_text_style_700(styleSize: 15)
.padding(.bottom, -5)
TextField("settings_advanced_device_id_hint", text: $settingsViewModel.deviceId)
.default_text_style(styleSize: 15)
.frame(height: 25)
.padding(.horizontal, 20)
.padding(.vertical, 15)
.cornerRadius(60)
.overlay(
RoundedRectangle(cornerRadius: 60)
.inset(by: 0.5)
.stroke(isDeviceIdFocused ? Color.orangeMain500 : Color.gray200, lineWidth: 1)
)
.focused($isDeviceIdFocused)
}
VStack(alignment: .leading) {
Text("settings_advanced_upload_server_url")
.default_text_style_700(styleSize: 15)
.padding(.bottom, -5)
TextField("settings_advanced_upload_server_url", text: $settingsViewModel.uploadServerUrl)
.default_text_style(styleSize: 15)
.frame(height: 25)
.padding(.horizontal, 20)
.padding(.vertical, 15)
.cornerRadius(60)
.overlay(
RoundedRectangle(cornerRadius: 60)
.inset(by: 0.5)
.stroke(isUploadServerUrlFocused ? Color.orangeMain500 : Color.gray200, lineWidth: 1)
)
.focused($isUploadServerUrlFocused)
}
VStack(alignment: .leading) {
Text("settings_advanced_remote_provisioning_url")
.default_text_style_700(styleSize: 15)
.padding(.bottom, -5)
TextField("settings_advanced_remote_provisioning_url", text: $settingsViewModel.remoteProvisioningUrl)
.default_text_style(styleSize: 15)
.frame(height: 25)
.padding(.horizontal, 20)
.padding(.vertical, 15)
.cornerRadius(60)
.overlay(
RoundedRectangle(cornerRadius: 60)
.inset(by: 0.5)
.stroke(isRemoteProvisioningUrlFocused ? Color.orangeMain500 : Color.gray200, lineWidth: 1)
)
.focused($isRemoteProvisioningUrlFocused)
}
HStack {
Spacer()
Button(
action: {
settingsViewModel.downloadAndApplyRemoteProvisioning()
}, label: {
Text("settings_advanced_download_apply_remote_provisioning")
.default_text_style_white_600(styleSize: 15)
}
)
.padding(.horizontal, 20)
.padding(.vertical, 10)
.background(settingsViewModel.remoteProvisioningUrl.isEmpty ? Color.orangeMain100 : Color.orangeMain500)
.cornerRadius(60)
.disabled(settingsViewModel.remoteProvisioningUrl.isEmpty)
}
}
.padding(.vertical, 30)
.padding(.horizontal, 20)
.background(Color.gray100)
/*
HStack(alignment: .center) {
Text("settings_advanced_audio_devices_title")
.default_text_style_800(styleSize: 18)
.frame(maxWidth: .infinity, alignment: .leading)
Spacer()
Image(audioDevicesIsOpen ? "caret-up" : "caret-down")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c600)
.frame(width: 25, height: 25, alignment: .leading)
.padding(.all, 10)
}
.padding(.vertical, 10)
.padding(.horizontal, 20)
.background(Color.gray100)
.onTapGesture {
withAnimation {
audioDevicesIsOpen.toggle()
}
}
if audioDevicesIsOpen {
VStack(spacing: 0) {
VStack(spacing: 30) {
VStack(alignment: .leading) {
Text("call_stats_media_encryption_title")
.default_text_style_700(styleSize: 15)
.padding(.bottom, -5)
Menu {
Button("None") { } // settingsViewModel.defaultLayout = ""}
Button("SRTP") { } // settingsViewModel.defaultLayout = ""}
Button("ZRTP") { } // settingsViewModel.defaultLayout = ""}
Button("DTLS") { } // settingsViewModel.defaultLayout = ""}
} label: {
Text("ZRTP")
.default_text_style(styleSize: 15)
.frame(maxWidth: .infinity, alignment: .leading)
Image("caret-down")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c500)
.frame(width: 20, height: 20)
}
.frame(height: 25)
.padding(.horizontal, 20)
.padding(.vertical, 15)
.cornerRadius(60)
.overlay(
RoundedRectangle(cornerRadius: 60)
.inset(by: 0.5)
.stroke(Color.gray200, lineWidth: 1)
)
}
VStack(alignment: .leading) {
Text("call_stats_media_encryption_title")
.default_text_style_700(styleSize: 15)
.padding(.bottom, -5)
Menu {
Button("None") { } // settingsViewModel.defaultLayout = ""}
Button("SRTP") { } // settingsViewModel.defaultLayout = ""}
Button("ZRTP") { } // settingsViewModel.defaultLayout = ""}
Button("DTLS") { } // settingsViewModel.defaultLayout = ""}
} label: {
Text("ZRTP")
.default_text_style(styleSize: 15)
.frame(maxWidth: .infinity, alignment: .leading)
Image("caret-down")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c500)
.frame(width: 20, height: 20)
}
.frame(height: 25)
.padding(.horizontal, 20)
.padding(.vertical, 15)
.cornerRadius(60)
.overlay(
RoundedRectangle(cornerRadius: 60)
.inset(by: 0.5)
.stroke(Color.gray200, lineWidth: 1)
)
}
}
.padding(.vertical, 30)
.padding(.horizontal, 20)
}
.background(.white)
.cornerRadius(15)
.padding(.horizontal)
.zIndex(-1)
.transition(.move(edge: .top))
}
HStack(alignment: .center) {
Text("settings_advanced_audio_codecs_title")
.default_text_style_800(styleSize: 18)
.frame(maxWidth: .infinity, alignment: .leading)
Spacer()
Image(audioCodecsIsOpen ? "caret-up" : "caret-down")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c600)
.frame(width: 25, height: 25, alignment: .leading)
.padding(.all, 10)
}
.padding(.vertical, 10)
.padding(.horizontal, 20)
.background(Color.gray100)
.onTapGesture {
withAnimation {
audioCodecsIsOpen.toggle()
}
}
if audioCodecsIsOpen {
VStack(spacing: 0) {
VStack(spacing: 30) {
Toggle("settings_calls_adaptive_rate_control_title", isOn: $settingsViewModel.adaptiveRateControl)
.default_text_style_700(styleSize: 15)
Toggle("settings_calls_enable_video_title", isOn: $settingsViewModel.enableVideo)
.default_text_style_700(styleSize: 15)
Toggle("settings_calls_auto_record_title", isOn: $settingsViewModel.autoRecord)
.default_text_style_700(styleSize: 15)
}
.padding(.vertical, 30)
.padding(.horizontal, 20)
}
.background(.white)
.cornerRadius(15)
.padding(.horizontal)
.zIndex(-2)
.transition(.move(edge: .top))
}
HStack(alignment: .center) {
Text("settings_advanced_video_codecs_title")
.default_text_style_800(styleSize: 18)
.frame(maxWidth: .infinity, alignment: .leading)
Spacer()
Image(videoCodecsIsOpen ? "caret-up" : "caret-down")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c600)
.frame(width: 25, height: 25, alignment: .leading)
.padding(.all, 10)
}
.padding(.vertical, 10)
.padding(.horizontal, 20)
.background(Color.gray100)
.onTapGesture {
withAnimation {
videoCodecsIsOpen.toggle()
}
}
if videoCodecsIsOpen {
VStack(spacing: 0) {
VStack(spacing: 30) {
Toggle("settings_conversations_auto_download_title", isOn: $settingsViewModel.autoDownload)
.default_text_style_700(styleSize: 15)
}
.padding(.vertical, 30)
.padding(.horizontal, 20)
}
.background(.white)
.cornerRadius(15)
.padding(.horizontal)
.zIndex(-3)
.transition(.move(edge: .top))
}
*/
}
}
.background(Color.gray100)
}
.background(Color.gray100)
}
.navigationTitle("")
.navigationBarHidden(true)
}
}

View file

@ -25,7 +25,6 @@ struct SettingsFragment: View {
@Binding var isShowSettingsFragment: Bool
@State private var isOn: Bool = false
@State var securityIsOpen: Bool = false
@State var callsIsOpen: Bool = false
@State var conversationsIsOpen: Bool = false
@ -440,28 +439,29 @@ struct SettingsFragment: View {
.transition(.move(edge: .top))
}
*/
HStack(alignment: .center) {
Text("settings_advanced_title")
.default_text_style_800(styleSize: 18)
.frame(maxWidth: .infinity, alignment: .leading)
NavigationLink(destination: {
SettingsAdvancedFragment(settingsViewModel: settingsViewModel)
}, label: {
HStack(alignment: .center) {
Text("settings_advanced_title")
.default_text_style_800(styleSize: 18)
.frame(maxWidth: .infinity, alignment: .leading)
Spacer()
Image("caret-right")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c600)
.frame(width: 25, height: 25, alignment: .leading)
.padding(.all, 10)
}
.frame(maxWidth: .infinity)
Spacer()
Image("caret-right")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c600)
.frame(width: 25, height: 25, alignment: .leading)
.padding(.all, 10)
}
})
.padding(.vertical, 10)
.padding(.horizontal, 20)
.background(Color.gray100)
.onTapGesture {
withAnimation {
//networkIsOpen.toggle()
}
}
}
}
.background(Color.gray100)

View file

@ -27,7 +27,7 @@ class SettingsViewModel: ObservableObject {
// Security settings
@Published var enableVfs: Bool = false
//@Published var preventScreenshots: Bool = false
// @Published var preventScreenshots: Bool = false
// Calls settings
@Published var adaptiveRateControl: Bool = false
@ -44,6 +44,16 @@ class SettingsViewModel: ObservableObject {
@Published var useWifiOnly: Bool = false
@Published var allowIpv6: Bool = false
// Advanced settings
@Published var enableFec: Bool = false
@Published var mediaEncryption: String = ""
@Published var mediaEncryptionMandatory: Bool = false
@Published var acceptEarlyMedia: Bool = false
@Published var allowOutgoingEarlyMedia: Bool = false
@Published var deviceId: String = ""
@Published var uploadServerUrl: String = ""
@Published var remoteProvisioningUrl: String = ""
init() {
CoreContext.shared.doOnCoreQueue { core in
@ -60,6 +70,26 @@ class SettingsViewModel: ObservableObject {
let useWifiOnlyTmp = core.wifiOnlyEnabled
let allowIpv6Tmp = core.ipv6Enabled
// Advanced settings
let enableFecTmp = core.fecEnabled
var mediaEncryptionTmp = ""
switch core.mediaEncryption {
case .None:
mediaEncryptionTmp = "None"
case .SRTP:
mediaEncryptionTmp = "SRTP"
case .ZRTP:
mediaEncryptionTmp = "ZRTP"
case .DTLS:
mediaEncryptionTmp = "DTLS"
}
let mediaEncryptionMandatoryTmp = core.isMediaEncryptionMandatory
let acceptEarlyMediaTmp = CorePreferences.acceptEarlyMedia
let allowOutgoingEarlyMediaTmp = CorePreferences.allowOutgoingEarlyMedia
let deviceIdTmp = CorePreferences.deviceName
let fileSharingServerUrlTmp = core.fileTransferServer
let remoteProvisioningUrlTmp = core.provisioningUri
DispatchQueue.main.async {
self.enableVfs = enableVfsTmp
@ -74,6 +104,17 @@ class SettingsViewModel: ObservableObject {
self.useWifiOnly = useWifiOnlyTmp
self.allowIpv6 = allowIpv6Tmp
// Advanced settings
self.enableFec = enableFecTmp
self.mediaEncryption = mediaEncryptionTmp
self.mediaEncryptionMandatory = mediaEncryptionMandatoryTmp
self.acceptEarlyMedia = acceptEarlyMediaTmp
self.allowOutgoingEarlyMedia = allowOutgoingEarlyMediaTmp
self.deviceId = deviceIdTmp
self.uploadServerUrl = fileSharingServerUrlTmp ?? ""
self.remoteProvisioningUrl = remoteProvisioningUrlTmp ?? ""
self.coreDelegate = CoreDelegateStub(
onAudioDevicesListUpdated: { (_: Core) in
Log.info(
@ -95,6 +136,22 @@ class SettingsViewModel: ObservableObject {
}
}
func downloadAndApplyRemoteProvisioning() {
Log.info("\(SettingsViewModel.TAG) Updating remote provisioning URI now and then download/apply it")
CoreContext.shared.doOnCoreQueue { core in
if core.provisioningUri != self.remoteProvisioningUrl && !(core.provisioningUri == nil && self.remoteProvisioningUrl.isEmpty) {
try? core.setProvisioninguri(newValue: self.remoteProvisioningUrl)
Log.info("\(SettingsViewModel.TAG) Restarting the Core to apply configuration changes")
core.stop()
Log.info("\(SettingsViewModel.TAG) Core has been stopped, restarting it")
try? core.start()
Log.info("\(SettingsViewModel.TAG) Core has been restarted")
}
}
}
func saveChangesWhenLeaving() {
CoreContext.shared.doOnCoreQueue { core in
if CorePreferences.vfsEnabled != self.enableVfs {
@ -129,6 +186,49 @@ class SettingsViewModel: ObservableObject {
if core.ipv6Enabled != self.allowIpv6 {
core.ipv6Enabled = self.allowIpv6
}
if core.fecEnabled != self.enableFec {
core.fecEnabled = self.enableFec
}
if (core.mediaEncryption == .None && self.mediaEncryption != "None")
|| (core.mediaEncryption == .SRTP && self.mediaEncryption != "SRTP")
|| (core.mediaEncryption == .ZRTP && self.mediaEncryption != "ZRTP")
|| (core.mediaEncryption == .DTLS && self.mediaEncryption != "DTLS") {
switch self.mediaEncryption {
case "None":
try? core.setMediaencryption(newValue: .None)
case "SRTP":
try? core.setMediaencryption(newValue: .SRTP)
case "ZRTP":
try? core.setMediaencryption(newValue: .ZRTP)
case "DTLS":
try? core.setMediaencryption(newValue: .DTLS)
default:
break
}
}
if core.isMediaEncryptionMandatory != self.mediaEncryptionMandatory {
core.mediaEncryptionMandatory = self.mediaEncryptionMandatory
}
if CorePreferences.acceptEarlyMedia != self.acceptEarlyMedia {
CorePreferences.acceptEarlyMedia = self.acceptEarlyMedia
}
if CorePreferences.allowOutgoingEarlyMedia != self.allowOutgoingEarlyMedia {
CorePreferences.allowOutgoingEarlyMedia = self.allowOutgoingEarlyMedia
}
if CorePreferences.deviceName != self.deviceId {
CorePreferences.deviceName = self.deviceId
}
if core.fileTransferServer != self.uploadServerUrl && !(core.fileTransferServer == nil && self.uploadServerUrl.isEmpty) {
core.fileTransferServer = self.uploadServerUrl
}
}
}
}