diff --git a/Linphone/Core/CorePreferences.swift b/Linphone/Core/CorePreferences.swift index 34288b7ac..e2bf29d00 100644 --- a/Linphone/Core/CorePreferences.swift +++ b/Linphone/Core/CorePreferences.swift @@ -330,6 +330,15 @@ class CorePreferences { } } + var showDeveloperSettings: Bool { + get { + config.getBool(section: "ui", key: "show_developer_settings", defaultValue: false) + } + set { + config.setBool(section: "ui", key: "show_developer_settings", value: newValue) + } + } + var showDialogWhenCallingDeviceUuidDirectly: Bool { get { config.getBool(section: "app", key: "show_confirmation_dialog_zrtp_trust_call", defaultValue: true) diff --git a/Linphone/GeneratedGit.swift b/Linphone/GeneratedGit.swift index 267e068c0..7cc9f4600 100644 --- a/Linphone/GeneratedGit.swift +++ b/Linphone/GeneratedGit.swift @@ -1,7 +1,7 @@ import Foundation public enum AppGitInfo { - public static let branch = "master" - public static let commit = "fa9be23c2" + public static let branch = "feature/update_settings" + public static let commit = "5906c3449" public static let tag = "6.1.0-alpha" } diff --git a/Linphone/Localizable/en.lproj/Localizable.strings b/Linphone/Localizable/en.lproj/Localizable.strings index d234a0e94..7484b417c 100644 --- a/Linphone/Localizable/en.lproj/Localizable.strings +++ b/Linphone/Localizable/en.lproj/Localizable.strings @@ -475,10 +475,8 @@ "qr_code_validated" = "QR code validated"; "recordings_title" = "Recordings"; "recordings_list_empty" = "No recording for the moment…"; -"recordings_list_empty" = "No recording for the moment…"; -"recordings_list_empty" = "No recording for the moment…"; -"recordings_list_empty" = "No recording for the moment…"; "selected_participants_count" = "%@ selected participants"; +"settings_advanced_early_media_title" = "Early-media"; "settings_advanced_accept_early_media_title" = "Accept early media"; "settings_advanced_allow_outgoing_early_media_title" = "Allow outgoing early media"; "settings_advanced_audio_codecs_title" = "Audio codecs"; @@ -488,10 +486,13 @@ "settings_advanced_download_apply_remote_provisioning" = "Download & apply"; "settings_advanced_input_audio_device_title" = "Default input audio device"; "settings_advanced_media_encryption_mandatory_title" = "Media encryption mandatory"; +"settings_advanced_create_e2e_encrypted_conferences_title" = "Create end-to-end encrypted meetings & group calls"; "settings_advanced_output_audio_device_title" = "Default output audio device"; "settings_advanced_remote_provisioning_url" = "Remote provisioning URL"; "settings_advanced_title" = "Advanced settings"; "settings_advanced_upload_server_url" = "File sharing server URL"; +"settings_advanced_logs_upload_server_url" = "Logs sharing server URL"; +"settings_advanced_calls" = "Advanced calls settings"; "settings_advanced_video_codecs_title" = "Video codecs"; "settings_calls_adaptive_rate_control_title" = "Adaptive rate control"; "settings_calls_auto_record_title" = "Automatically start recording calls"; @@ -542,6 +543,21 @@ "settings_conversations_hide_message_content_in_notif_title" = "Do not show message content in iOS notification⁣"; "settings_conversations_mark_as_read_when_dismissing_notif_title" = "Mark conversation as read when dismissing message notification"; "settings_conversations_title" = "Conversations"; +"settings_developer_title" = "Developer settings"; +"settings_developer_show_title" = "Show developer settings"; +"settings_developer_two_more_clicks_required_toast" = "Click 2 more times to enable developer settings"; +"settings_developer_one_more_click_required_toast" = "Click 1 more time to enable developer settings"; +"settings_developer_enabled_toast" = "Developer settings enabled"; +"settings_developer_already_enabled_toast" = "Developer settings already enabled"; +"settings_developer_enable_vu_meters_title" = "Enable record/playback volume vu meters while in call"; +"settings_developer_enable_advanced_call_stats_title" = "Show advanced call statistics"; +"settings_developer_push_compatible_domains_list_title" = "List of push notifications compatible domains (comma separated)"; +"settings_developer_clear_native_friends_in_database_title" = "Clear imported contacts from native address book"; +"settings_developer_clear_native_friends_in_database_subtitle" = "They will be imported again the next time the app starts unless you remove the contacts permission"; +"settings_developer_cleared_native_friends_in_database_toast" = "Imported contacts have been deleted"; +"settings_developer_clear_orphan_auth_info_title" = "Clear authentication info no longer associated to any account"; +"settings_developer_no_auth_info_removed_toast" = "No orphan authentication info found"; +"settings_developer_cleared_auth_info_toast" = "Orphaned authentication info removed"; "settings_meetings_default_layout_title" = "Default layout"; "settings_meetings_layout_active_speaker_label" = "Active speaker"; "settings_meetings_layout_mosaic_label" = "Mosaic"; diff --git a/Linphone/Localizable/fr.lproj/Localizable.strings b/Linphone/Localizable/fr.lproj/Localizable.strings index 20d5d37a4..6fe138177 100644 --- a/Linphone/Localizable/fr.lproj/Localizable.strings +++ b/Linphone/Localizable/fr.lproj/Localizable.strings @@ -475,6 +475,7 @@ "recordings_title" = "Enregistrements"; "recordings_list_empty" = "Aucun appel enregistré…"; "selected_participants_count" = "%@ participants selectionnés"; +"settings_advanced_early_media_title" = "Early media"; "settings_advanced_accept_early_media_title" = "Accepter l'early media"; "settings_advanced_allow_outgoing_early_media_title" = "Autoriser l'early media pour les appels sortants"; "settings_advanced_audio_codecs_title" = "Codecs audio"; @@ -484,10 +485,13 @@ "settings_advanced_download_apply_remote_provisioning" = "Télécharger & appliquer"; "settings_advanced_input_audio_device_title" = "Périphérique de capture par défaut"; "settings_advanced_media_encryption_mandatory_title" = "Rendre le chiffrement du média obligatoire"; +"settings_advanced_create_e2e_encrypted_conferences_title" = "Créer en mode chiffré de bout en bout les réunions et les appels de groupe"; "settings_advanced_output_audio_device_title" = "Périphérique d'écoute par défaut"; "settings_advanced_remote_provisioning_url" = "URL de configuration distante"; "settings_advanced_title" = "Paramètres avancés"; "settings_advanced_upload_server_url" = "URL du serveur de partage de fichier"; +"settings_advanced_logs_upload_server_url" = "URL du serveur de partage des logs"; +"settings_advanced_calls" = "Paramètres d'appels avancés"; "settings_advanced_video_codecs_title" = "Codecs vidéo"; "settings_calls_adaptive_rate_control_title" = "Contrôle automatique de la qualité"; "settings_calls_auto_record_title" = "Enregistrement automatique des appels"; @@ -538,6 +542,22 @@ "settings_conversations_hide_message_content_in_notif_title" = "Masquer le contenu du message dans la notification iOS"; "settings_conversations_mark_as_read_when_dismissing_notif_title" = "Marquer la conversation comme lue lorsqu'une notification de message est supprimée"; "settings_conversations_title" = "Conversations"; +"settings_developer_title" = "Paramètres développeurs"; +"settings_developer_show_title" = "Afficher les paramètres développeurs"; +"settings_developer_two_more_clicks_required_toast" = "Encore 2 clicks pour activer les paramètres développeurs"; +"settings_developer_one_more_click_required_toast" = "Encore 1 click pour activer les paramètres développeurs"; +"settings_developer_enabled_toast" = "Paramètres développeurs activés"; +"settings_developer_already_enabled_toast" = "Paramètres développeurs déjà activés"; +"settings_developer_enable_vu_meters_title" = "Activer l'indicateur des volumes d'enregistrement et de lecture"; +"settings_developer_enable_advanced_call_stats_title" = "Afficher plus de statistiques d'appel"; +"settings_developer_push_compatible_domains_list_title" = "Liste des domaines qui supportent les notifications poussées (séparés par des virgules)"; +"settings_developer_clear_native_friends_in_database_title" = "Supprimer les contacts natifs importés"; +"settings_developer_clear_native_friends_in_database_subtitle" = "Ils seront synchronisés à nouveau au prochain démarrage de l'application sauf si vous retirez la permission de lire les contacts"; +"settings_developer_cleared_native_friends_in_database_toast" = "Contacts importés supprimés"; +"settings_developer_clear_orphan_auth_info_title" = "Supprimer les informations d'authentification orphelines"; +"settings_developer_no_auth_info_removed_toast" = "Aucune information d'authentification orpheline trouvée"; +"settings_developer_cleared_auth_info_toast_single" = "%@ information d'authentification supprimée"; +"settings_developer_cleared_auth_info_toast_multiple" = "%@ informations d'authentification supprimées"; "settings_meetings_default_layout_title" = "Disposition par défaut"; "settings_meetings_layout_active_speaker_label" = "Intervenant actif"; "settings_meetings_layout_mosaic_label" = "Mosaïque"; diff --git a/Linphone/UI/Main/Fragments/ToastView.swift b/Linphone/UI/Main/Fragments/ToastView.swift index 8ffb2f1da..f7d18d540 100644 --- a/Linphone/UI/Main/Fragments/ToastView.swift +++ b/Linphone/UI/Main/Fragments/ToastView.swift @@ -198,6 +198,55 @@ struct ToastView: View { .default_text_style(styleSize: 15) .padding(8) + case "Success_cleared_native_friends_toast": + Text("settings_developer_cleared_native_friends_in_database_toast") + .multilineTextAlignment(.center) + .foregroundStyle(Color.greenSuccess500) + .default_text_style(styleSize: 15) + .padding(8) + + case "Success_no_auth_info_removed_toast": + Text("settings_developer_no_auth_info_removed_toast") + .multilineTextAlignment(.center) + .foregroundStyle(Color.greenSuccess500) + .default_text_style(styleSize: 15) + .padding(8) + + case "Success_cleared_auth_info_toast": + Text("settings_developer_cleared_auth_info_toast") + .multilineTextAlignment(.center) + .foregroundStyle(Color.greenSuccess500) + .default_text_style(styleSize: 15) + .padding(8) + + case "Success_two_more_clicks_toast": + Text("settings_developer_two_more_clicks_required_toast") + .multilineTextAlignment(.center) + .foregroundStyle(Color.greenSuccess500) + .default_text_style(styleSize: 15) + .padding(8) + + case "Success_one_more_click_toast": + Text("settings_developer_one_more_click_required_toast") + .multilineTextAlignment(.center) + .foregroundStyle(Color.greenSuccess500) + .default_text_style(styleSize: 15) + .padding(8) + + case "Success_developer_enabled_toast": + Text("settings_developer_enabled_toast") + .multilineTextAlignment(.center) + .foregroundStyle(Color.greenSuccess500) + .default_text_style(styleSize: 15) + .padding(8) + + case "Success_developer_already_enabled_toast": + Text("settings_developer_already_enabled_toast") + .multilineTextAlignment(.center) + .foregroundStyle(Color.greenSuccess500) + .default_text_style(styleSize: 15) + .padding(8) + case "Failed_toast_call_transfer_failed": Text("call_transfer_failed_toast") .multilineTextAlignment(.center) diff --git a/Linphone/UI/Main/Help/Fragments/HelpFragment.swift b/Linphone/UI/Main/Help/Fragments/HelpFragment.swift index 8a5b6fba9..f9f889636 100644 --- a/Linphone/UI/Main/Help/Fragments/HelpFragment.swift +++ b/Linphone/UI/Main/Help/Fragments/HelpFragment.swift @@ -25,6 +25,8 @@ struct HelpFragment: View { @Binding var isShowHelpFragment: Bool + @State var clickCounter: Int = 0 + var showAssistant: Bool { (CoreContext.shared.coreIsStarted && CoreContext.shared.accounts.isEmpty) || SharedMainViewModel.shared.displayProfileMode @@ -198,6 +200,29 @@ struct HelpFragment: View { .background(Color.orangeMain100) .cornerRadius(60) } + .background(Color.gray100) + .onTapGesture { + if !AppServices.corePreferences.showDeveloperSettings { + clickCounter += 1 + + switch clickCounter { + case 1: + ToastViewModel.shared.show("Success_two_more_clicks_toast") + + case 2: + ToastViewModel.shared.show("Success_one_more_click_toast") + + case 3: + AppServices.corePreferences.showDeveloperSettings = true + ToastViewModel.shared.show("Success_developer_enabled_toast") + + default: + ToastViewModel.shared.show("Success_developer_already_enabled_toast") + } + } else { + ToastViewModel.shared.show("Success_developer_already_enabled_toast") + } + } Button { if let url = URL(string: NSLocalizedString("website_open_source_licences_usage_url", comment: "")) { diff --git a/Linphone/UI/Main/Help/ViewModel/HelpViewModel.swift b/Linphone/UI/Main/Help/ViewModel/HelpViewModel.swift index ec987d8db..2cccdb401 100644 --- a/Linphone/UI/Main/Help/ViewModel/HelpViewModel.swift +++ b/Linphone/UI/Main/Help/ViewModel/HelpViewModel.swift @@ -172,19 +172,5 @@ class HelpViewModel: ObservableObject { } } } - - func clearNativeFriendsDatabase() { - CoreContext.shared.doOnCoreQueue { core in - if let list = core.getFriendListByName(NATIVE_ADDRESS_BOOK_FRIEND_LIST) { - let friends = list.friends - Log.i("\(self.TAG) Friend list to remove found with [\(friends.count)] friends") - for friend in friends { - list.removeFriend(friend) - } - core.removeFriendList(list) - Log.i("\(self.TAG) Friend list [\(NATIVE_ADDRESS_BOOK_FRIEND_LIST)] removed") - } - } - } */ } diff --git a/Linphone/UI/Main/Settings/Fragments/SettingsAdvancedCallFragment.swift b/Linphone/UI/Main/Settings/Fragments/SettingsAdvancedCallFragment.swift new file mode 100644 index 000000000..2abcdcb7c --- /dev/null +++ b/Linphone/UI/Main/Settings/Fragments/SettingsAdvancedCallFragment.swift @@ -0,0 +1,274 @@ +/* + * 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 . + */ + +import SwiftUI +import UniformTypeIdentifiers + +struct SettingsAdvancedCallFragment: View { + @ObservedObject var settingsViewModel: SettingsViewModel + + @Environment(\.dismiss) var dismiss + + @State var earlyMediaIsOpen: Bool = false + @State var audioCodecsIsOpen: Bool = false + @State var videoCodecsIsOpen: Bool = false + + 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_advanced_calls") + .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: 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" + settingsViewModel.mediaEncryptionMandatory = false + } + Button("SRTP") { + settingsViewModel.mediaEncryption = "SRTP" + settingsViewModel.mediaEncryptionMandatory = true + } + Button("ZRTP") { + settingsViewModel.mediaEncryption = "ZRTP" + settingsViewModel.mediaEncryptionMandatory = true + } + Button("DTLS") { + settingsViewModel.mediaEncryption = "DTLS" + settingsViewModel.mediaEncryptionMandatory = true + } + } 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) + } + .padding(.vertical, 20) + .padding(.horizontal, 20) + .background(.white) + .cornerRadius(15) + .background(Color.gray100) + } + .padding(.vertical, 20) + .padding(.horizontal, 20) + .background(Color.gray100) + + HStack(alignment: .center) { + Text("settings_advanced_early_media_title") + .default_text_style_800(styleSize: 18) + .frame(maxWidth: .infinity, alignment: .leading) + + Spacer() + + Image(earlyMediaIsOpen ? "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 { + earlyMediaIsOpen.toggle() + } + } + + if earlyMediaIsOpen { + VStack(spacing: 0) { + VStack(spacing: 30) { + 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) + } + .padding(.vertical, 30) + .padding(.horizontal, 20) + } + .background(.white) + .cornerRadius(15) + .padding(.horizontal, 20) + .zIndex(-1) + .transition(.move(edge: .top)) + .background(Color.gray100) + } + + 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) { + ForEach(settingsViewModel.audioCodecs) { audioCodec in + SettingsToggleWidget(title: audioCodec.mimeType, subtitle: audioCodec.subtitle, isOn: Binding( + get: { audioCodec.isEnabled }, + set: { newValue in + audioCodec.toggleEnabled() + } + )) + } + } + .padding(.vertical, 30) + .padding(.horizontal, 20) + } + .background(.white) + .cornerRadius(15) + .padding(.horizontal, 20) + .zIndex(-2) + .transition(.move(edge: .top)) + .background(Color.gray100) + } + + 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) { + ForEach(settingsViewModel.videoCodecs) { videoCodec in + SettingsToggleWidget(title: videoCodec.mimeType, subtitle: videoCodec.subtitle, isOn: Binding( + get: { videoCodec.isEnabled }, + set: { newValue in + videoCodec.toggleEnabled() + } + )) + } + } + .padding(.vertical, 30) + .padding(.horizontal, 20) + } + .background(.white) + .cornerRadius(15) + .padding(.horizontal, 20) + .zIndex(-3) + .transition(.move(edge: .top)) + .background(Color.gray100) + } + } + .background(Color.gray100) + } + .background(Color.gray100) + } + .background(Color.gray100) + } + .navigationTitle("") + .navigationBarHidden(true) + } +} diff --git a/Linphone/UI/Main/Settings/Fragments/SettingsAdvancedFragment.swift b/Linphone/UI/Main/Settings/Fragments/SettingsAdvancedFragment.swift index 2ed857377..37ecf7d1e 100644 --- a/Linphone/UI/Main/Settings/Fragments/SettingsAdvancedFragment.swift +++ b/Linphone/UI/Main/Settings/Fragments/SettingsAdvancedFragment.swift @@ -26,11 +26,8 @@ struct SettingsAdvancedFragment: View { @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 { @@ -54,7 +51,7 @@ struct SettingsAdvancedFragment: View { dismiss() } - Text("settings_title") + Text("settings_advanced_title") .default_text_style_orange_800(styleSize: 16) .frame(maxWidth: .infinity, alignment: .leading) .padding(.top, 4) @@ -71,61 +68,6 @@ struct SettingsAdvancedFragment: View { 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" - settingsViewModel.mediaEncryptionMandatory = false - } - Button("SRTP") { - settingsViewModel.mediaEncryption = "SRTP" - settingsViewModel.mediaEncryptionMandatory = true - } - Button("ZRTP") { - settingsViewModel.mediaEncryption = "ZRTP" - settingsViewModel.mediaEncryptionMandatory = true - } - Button("DTLS") { - settingsViewModel.mediaEncryption = "DTLS" - settingsViewModel.mediaEncryptionMandatory = true - } - } 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) @@ -145,25 +87,6 @@ struct SettingsAdvancedFragment: View { .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) @@ -201,8 +124,10 @@ struct SettingsAdvancedFragment: View { .disabled(settingsViewModel.remoteProvisioningUrl.isEmpty) } } - .padding(.vertical, 30) + .padding(.vertical, 20) .padding(.horizontal, 20) + .background(.white) + .cornerRadius(15) .background(Color.gray100) /* @@ -307,102 +232,15 @@ struct SettingsAdvancedFragment: View { } .background(.white) .cornerRadius(15) - .padding(.horizontal) + .padding(.horizontal, 20) .zIndex(-1) .transition(.move(edge: .top)) + .background(Color.gray100) } */ - - 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) { - ForEach(settingsViewModel.audioCodecs) { audioCodec in - SettingsToggleWidget(title: audioCodec.mimeType, subtitle: audioCodec.subtitle, isOn: Binding( - get: { audioCodec.isEnabled }, - set: { newValue in - audioCodec.toggleEnabled() - } - )) - } - } - .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) { - ForEach(settingsViewModel.videoCodecs) { videoCodec in - SettingsToggleWidget(title: videoCodec.mimeType, subtitle: videoCodec.subtitle, isOn: Binding( - get: { videoCodec.isEnabled }, - set: { newValue in - videoCodec.toggleEnabled() - } - )) - } - } - .padding(.vertical, 30) - .padding(.horizontal, 20) - } - .background(.white) - .cornerRadius(15) - .padding(.horizontal) - .zIndex(-3) - .transition(.move(edge: .top)) - } } + .padding(.vertical, 20) + .padding(.horizontal, 20) } .background(Color.gray100) } diff --git a/Linphone/UI/Main/Settings/Fragments/SettingsDeveloperFragment.swift b/Linphone/UI/Main/Settings/Fragments/SettingsDeveloperFragment.swift new file mode 100644 index 000000000..cec5beff2 --- /dev/null +++ b/Linphone/UI/Main/Settings/Fragments/SettingsDeveloperFragment.swift @@ -0,0 +1,196 @@ +/* + * 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 . + */ + +import SwiftUI +import UniformTypeIdentifiers + +struct SettingsDeveloperFragment: View { + @ObservedObject var settingsViewModel: SettingsViewModel + + @Environment(\.dismiss) var dismiss + + @FocusState var isUploadServerUrlFocused: Bool + @FocusState var isLogsUploadServerUrlFocused: Bool + @FocusState var isPushCompatibleDomainsListFocused: 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_developer_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_developer_show_title", isOn: $settingsViewModel.showDeveloperSettings) + .default_text_style_700(styleSize: 15) + + Toggle("help_troubleshooting_print_logs_in_logcat", isOn: $settingsViewModel.printLogsInLogcat) + .default_text_style_700(styleSize: 15) + + 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_logs_upload_server_url") + .default_text_style_700(styleSize: 15) + .padding(.bottom, -5) + + TextField("settings_advanced_logs_upload_server_url", text: $settingsViewModel.logsUploadServerUrl) + .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(isLogsUploadServerUrlFocused ? Color.orangeMain500 : Color.gray200, lineWidth: 1) + ) + .focused($isLogsUploadServerUrlFocused) + } + + // TODO: Add these settings + /* + Toggle("settings_advanced_create_e2e_encrypted_conferences_title", isOn: $settingsViewModel.???) + .default_text_style_700(styleSize: 15) + + Toggle("settings_developer_enable_vu_meters_title", isOn: $settingsViewModel.???) + .default_text_style_700(styleSize: 15) + + Toggle("settings_developer_enable_advanced_call_stats_title", isOn: $settingsViewModel.???) + .default_text_style_700(styleSize: 15) + + VStack(alignment: .leading) { + Text("settings_developer_push_compatible_domains_list_title") + .default_text_style_700(styleSize: 15) + .padding(.bottom, -5) + + TextField("settings_developer_push_compatible_domains_list_title", text: $settingsViewModel.???) + .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(isPushCompatibleDomainsListFocused ? Color.orangeMain500 : Color.gray200, lineWidth: 1) + ) + .focused($isPushCompatibleDomainsListFocused) + } + */ + + VStack(alignment: .leading) { + Button( + action: { + settingsViewModel.clearNativeFriendsDatabase() + }, label: { + Text("settings_developer_clear_native_friends_in_database_title") + .default_text_style_white_600(styleSize: 15) + .frame(maxWidth: .infinity, alignment: .center) + } + ) + .padding(.horizontal, 20) + .padding(.vertical, 10) + .background(Color.redDanger500) + .cornerRadius(60) + + Text("settings_developer_clear_native_friends_in_database_subtitle") + .default_text_style(styleSize: 14) + .frame(maxWidth: .infinity, alignment: .leading) + } + + Button( + action: { + settingsViewModel.clearOrphanAuthInfo() + }, label: { + Text("settings_developer_clear_orphan_auth_info_title") + .default_text_style_white_600(styleSize: 15) + .frame(maxWidth: .infinity, alignment: .center) + } + ) + .padding(.horizontal, 20) + .padding(.vertical, 10) + .background(Color.redDanger500) + .cornerRadius(60) + + } + .padding(.vertical, 20) + .padding(.horizontal, 20) + .background(.white) + .cornerRadius(15) + .background(Color.gray100) + } + .padding(.vertical, 20) + .padding(.horizontal, 20) + } + .background(Color.gray100) + } + .background(Color.gray100) + } + .navigationTitle("") + .navigationBarHidden(true) + } +} diff --git a/Linphone/UI/Main/Settings/Fragments/SettingsFragment.swift b/Linphone/UI/Main/Settings/Fragments/SettingsFragment.swift index 0c8d16257..33c79ab7a 100644 --- a/Linphone/UI/Main/Settings/Fragments/SettingsFragment.swift +++ b/Linphone/UI/Main/Settings/Fragments/SettingsFragment.swift @@ -132,7 +132,7 @@ struct SettingsFragment: View { } .background(.white) .cornerRadius(15) - .padding(.horizontal) + .padding(.horizontal, 20) .zIndex(-1) .transition(.move(edge: .top)) } @@ -195,15 +195,36 @@ struct SettingsFragment: View { } } */ + + NavigationLink(destination: { + SettingsAdvancedCallFragment(settingsViewModel: settingsViewModel) + }, label: { + HStack(alignment: .center) { + Text("settings_advanced_calls") + .default_text_style_700(styleSize: 15) + .frame(maxWidth: .infinity, alignment: .leading) + + Spacer() + + Image("caret-right") + .renderingMode(.template) + .resizable() + .foregroundStyle(Color.grayMain2c600) + .frame(width: 25, height: 25, alignment: .leading) + } + .frame(maxWidth: .infinity) + + }) } .padding(.vertical, 30) .padding(.horizontal, 20) } .background(.white) .cornerRadius(15) - .padding(.horizontal) + .padding(.horizontal, 20) .zIndex(-2) .transition(.move(edge: .top)) + .background(Color.gray100) } HStack(alignment: .center) { @@ -243,9 +264,10 @@ struct SettingsFragment: View { } .background(.white) .cornerRadius(15) - .padding(.horizontal) + .padding(.horizontal, 20) .zIndex(-3) .transition(.move(edge: .top)) + .background(Color.gray100) } HStack(alignment: .center) { @@ -373,9 +395,10 @@ struct SettingsFragment: View { } .background(.white) .cornerRadius(15) - .padding(.horizontal) + .padding(.horizontal, 20) .zIndex(-4) .transition(.move(edge: .top)) + .background(Color.gray100) } HStack(alignment: .center) { @@ -438,9 +461,10 @@ struct SettingsFragment: View { } .background(.white) .cornerRadius(15) - .padding(.horizontal) + .padding(.horizontal, 20) .zIndex(-5) .transition(.move(edge: .top)) + .background(Color.gray100) } HStack(alignment: .center) { @@ -480,9 +504,10 @@ struct SettingsFragment: View { } .background(.white) .cornerRadius(15) - .padding(.horizontal) + .padding(.horizontal, 20) .zIndex(-6) .transition(.move(edge: .top)) + .background(Color.gray100) } /* @@ -525,11 +550,13 @@ struct SettingsFragment: View { } .background(.white) .cornerRadius(15) - .padding(.horizontal) + .padding(.horizontal, 20) .zIndex(-7) .transition(.move(edge: .top)) + .background(Color.gray100) } */ + NavigationLink(destination: { SettingsAdvancedFragment(settingsViewModel: settingsViewModel) }, label: { @@ -553,6 +580,32 @@ struct SettingsFragment: View { .padding(.vertical, 10) .padding(.horizontal, 20) .background(Color.gray100) + + if AppServices.corePreferences.showDeveloperSettings { + NavigationLink(destination: { + SettingsDeveloperFragment(settingsViewModel: settingsViewModel) + }, label: { + HStack(alignment: .center) { + Text("settings_developer_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) + + }) + .padding(.vertical, 10) + .padding(.horizontal, 20) + .background(Color.gray100) + } } } .background(Color.gray100) diff --git a/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift b/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift index d000c4e13..4f9b7d880 100644 --- a/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift +++ b/Linphone/UI/Main/Settings/ViewModel/SettingsViewModel.swift @@ -57,7 +57,6 @@ class SettingsViewModel: ObservableObject { @Published var acceptEarlyMedia: Bool = false @Published var allowOutgoingEarlyMedia: Bool = false @Published var deviceId: String = "" - @Published var uploadServerUrl: String = "" @Published var remoteProvisioningUrl: String = "" @Published var inputAudioDeviceLabels: [String] = [] @@ -71,6 +70,13 @@ class SettingsViewModel: ObservableObject { @Published var audioCodecs: [CodecModel] = [] @Published var videoCodecs: [CodecModel] = [] + + // Developer settings + @Published var showDeveloperSettings: Bool = false + @Published var printLogsInLogcat: Bool = false + @Published var uploadServerUrl: String = "" + @Published var logsUploadServerUrl: String = "" + init() { CoreContext.shared.doOnCoreQueue { core in @@ -105,9 +111,14 @@ class SettingsViewModel: ObservableObject { let acceptEarlyMediaTmp = AppServices.corePreferences.acceptEarlyMedia let allowOutgoingEarlyMediaTmp = AppServices.corePreferences.allowOutgoingEarlyMedia let deviceIdTmp = AppServices.corePreferences.deviceName - let fileSharingServerUrlTmp = core.fileTransferServer let remoteProvisioningUrlTmp = core.provisioningUri + // Developer settings + let showDeveloperSettingsTmp = AppServices.corePreferences.showDeveloperSettings + let printLogsInLogcatTmp = AppServices.corePreferences.printLogsInLogcat + let fileSharingServerUrlTmp = core.fileTransferServer + let logsTransferServerTmp = core.logCollectionUploadServerUrl + DispatchQueue.main.async { self.enableVfs = enableVfsTmp @@ -131,9 +142,14 @@ class SettingsViewModel: ObservableObject { self.allowOutgoingEarlyMedia = allowOutgoingEarlyMediaTmp self.deviceId = deviceIdTmp - self.uploadServerUrl = fileSharingServerUrlTmp ?? "" self.remoteProvisioningUrl = remoteProvisioningUrlTmp ?? "" + // Developer settings + self.showDeveloperSettings = showDeveloperSettingsTmp + self.printLogsInLogcat = printLogsInLogcatTmp + self.uploadServerUrl = fileSharingServerUrlTmp ?? "" + self.logsUploadServerUrl = logsTransferServerTmp ?? "" + /* self.setupAudioDevices() @@ -421,9 +437,74 @@ class SettingsViewModel: ObservableObject { AppServices.corePreferences.deviceName = self.deviceId } + // Developer settings + if AppServices.corePreferences.showDeveloperSettings != self.showDeveloperSettings { + AppServices.corePreferences.showDeveloperSettings = self.showDeveloperSettings + } + + if AppServices.corePreferences.printLogsInLogcat != self.printLogsInLogcat { + AppServices.corePreferences.printLogsInLogcat = self.printLogsInLogcat + } + if core.fileTransferServer != self.uploadServerUrl && !(core.fileTransferServer == nil && self.uploadServerUrl.isEmpty) { core.fileTransferServer = self.uploadServerUrl } + + if core.logCollectionUploadServerUrl != self.logsUploadServerUrl && !(core.logCollectionUploadServerUrl == nil && self.logsUploadServerUrl.isEmpty) { + core.logCollectionUploadServerUrl = self.logsUploadServerUrl + } + } + } + func clearNativeFriendsDatabase() { + CoreContext.shared.doOnCoreQueue { core in + let nativeAddressBookFriendList = "Native address-book" + if let list = core.getFriendListByName(name: nativeAddressBookFriendList) { + let friends = list.friends + Log.info("\(SettingsViewModel.TAG) Friend list to remove found with \(friends.count) friends") + for friend in friends { + _ = list.removeFriend(linphoneFriend: friend) + } + core.removeFriendList(list: list) + Log.info("\(SettingsViewModel.TAG) Friend list \(nativeAddressBookFriendList) removed") + } + + DispatchQueue.main.async { + ToastViewModel.shared.show("Success_cleared_native_friends_toast") + } + } + } + + func clearOrphanAuthInfo() { + CoreContext.shared.doOnCoreQueue { core in + var count = 0 + + for authInfo in core.authInfoList { + if let username = authInfo.username { + let account = core.accountList.first { + $0.params?.identityAddress?.username == username + } + + if account == nil { + Log.info("\(SettingsViewModel.TAG) Removing auth info \(authInfo) with username \(username) for which no account was found") + core.removeAuthInfo(info: authInfo) + count += 1 + } + } else { + Log.info("\(SettingsViewModel.TAG) Removing auth info \(authInfo) without username") + core.removeAuthInfo(info: authInfo) + count += 1 + } + } + + if count == 0 { + DispatchQueue.main.async { + ToastViewModel.shared.show("Success_no_auth_info_removed_toast") + } + } else { + DispatchQueue.main.async { + ToastViewModel.shared.show("Success_cleared_auth_info_toast") + } + } } } } diff --git a/LinphoneApp.xcodeproj/project.pbxproj b/LinphoneApp.xcodeproj/project.pbxproj index ad4d9f6d7..9e8cc70fc 100644 --- a/LinphoneApp.xcodeproj/project.pbxproj +++ b/LinphoneApp.xcodeproj/project.pbxproj @@ -205,6 +205,8 @@ D7D5AD872DD34F3C00016721 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = D7D5AD862DD34F3C00016721 /* FirebaseCrashlytics */; }; D7D67B6A2F601F6100DD9976 /* AppIntentVocabulary.plist in Resources */ = {isa = PBXBuildFile; fileRef = D7D67B692F601F6100DD9976 /* AppIntentVocabulary.plist */; }; D7D67B6B2F601F6100DD9976 /* AppIntentVocabulary.plist in Resources */ = {isa = PBXBuildFile; fileRef = D7D67B692F601F6100DD9976 /* AppIntentVocabulary.plist */; }; + D7D67B8B2F62B0DA00DD9976 /* SettingsAdvancedCallFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D67B8A2F62B07F00DD9976 /* SettingsAdvancedCallFragment.swift */; }; + D7D67B8D2F62B0F100DD9976 /* SettingsDeveloperFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D67B8C2F62B0EF00DD9976 /* SettingsDeveloperFragment.swift */; }; D7DA67622ACCB2FA00E95002 /* LoginFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DA67612ACCB2FA00E95002 /* LoginFragment.swift */; }; D7DA67642ACCB31700E95002 /* ProfileModeFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DA67632ACCB31700E95002 /* ProfileModeFragment.swift */; }; D7DC096F2CFA1D7600A6D47C /* AccountProfileFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7DC096E2CFA1D7400A6D47C /* AccountProfileFragment.swift */; }; @@ -487,6 +489,8 @@ D7D67B7A2F601F7400DD9976 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = sk; path = sk.lproj/AppIntentVocabulary.plist; sourceTree = ""; }; D7D67B7B2F601F7400DD9976 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = es; path = es.lproj/AppIntentVocabulary.plist; sourceTree = ""; }; D7D67B7C2F601F7500DD9976 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = uk; path = uk.lproj/AppIntentVocabulary.plist; sourceTree = ""; }; + D7D67B8A2F62B07F00DD9976 /* SettingsAdvancedCallFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsAdvancedCallFragment.swift; sourceTree = ""; }; + D7D67B8C2F62B0EF00DD9976 /* SettingsDeveloperFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsDeveloperFragment.swift; sourceTree = ""; }; D7DA67612ACCB2FA00E95002 /* LoginFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginFragment.swift; sourceTree = ""; }; D7DA67632ACCB31700E95002 /* ProfileModeFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileModeFragment.swift; sourceTree = ""; }; D7DC096E2CFA1D7400A6D47C /* AccountProfileFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountProfileFragment.swift; sourceTree = ""; }; @@ -1191,12 +1195,14 @@ D7DC096B2CFA192F00A6D47C /* Fragments */ = { isa = PBXGroup; children = ( + D7DC096E2CFA1D7400A6D47C /* AccountProfileFragment.swift */, + D7C5003F2D27F16900DD53EC /* AccountSettingsFragment.swift */, D762102B2E97FDF8002E7999 /* CardDavAddressBookConfigurationFragment.swift */, D711B1332E93F18300DF8C71 /* LdapServerConfigurationFragment.swift */, - D78607702D36CB87009E6A7E /* SettingsAdvancedFragment.swift */, D732C38B2D311D2100F78100 /* SettingsFragment.swift */, - D7C5003F2D27F16900DD53EC /* AccountSettingsFragment.swift */, - D7DC096E2CFA1D7400A6D47C /* AccountProfileFragment.swift */, + D78607702D36CB87009E6A7E /* SettingsAdvancedFragment.swift */, + D7D67B8C2F62B0EF00DD9976 /* SettingsDeveloperFragment.swift */, + D7D67B8A2F62B07F00DD9976 /* SettingsAdvancedCallFragment.swift */, ); path = Fragments; sourceTree = ""; @@ -1508,6 +1514,7 @@ D71A0E192B485ADF0002C6CD /* ViewExtension.swift in Sources */, D759CB642C3FBD4200AC35E8 /* StartConversationFragment.swift in Sources */, D7DF8BE92E2104EC003A3BC7 /* EmojiPickerView.swift in Sources */, + D7D67B8B2F62B0DA00DD9976 /* SettingsAdvancedCallFragment.swift in Sources */, 66FDB7812C7C689A00561566 /* EventEditViewController.swift in Sources */, D750D3392AD3E6EE00EC99C5 /* PopupLoadingView.swift in Sources */, D7E6D0492AE933AD00A57AAF /* FavoriteContactsListFragment.swift in Sources */, @@ -1593,6 +1600,7 @@ D79F2D0A2C47F4BF0038FA07 /* TouchFeedback.swift in Sources */, D78E06282BE3811D00CE3783 /* CallStatsModel.swift in Sources */, D7E6D0512AEBDBD500A57AAF /* ContactsListBottomSheet.swift in Sources */, + D7D67B8D2F62B0F100DD9976 /* SettingsDeveloperFragment.swift in Sources */, D75759322B56D40900E7AC10 /* ZRTPPopup.swift in Sources */, D78E062E2BEA69F400CE3783 /* AudioRouteBottomSheet.swift in Sources */, D7A0ACBB2C415D630043AE79 /* StartGroupConversationFragment.swift in Sources */,