From 54a299f23cabef48e1cd1893771f5c2c7c007a75 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 13 Sep 2023 14:17:08 +0200 Subject: [PATCH] Started settings --- .../java/org/linphone/core/CorePreferences.kt | 20 + .../settings/fragment/SettingsFragment.kt | 8 + .../settings/viewmodel/SettingsViewModel.kt | 181 ++++++ app/src/main/res/drawable/caret_up.xml | 16 +- .../res/layout/account_profile_fragment.xml | 4 +- .../account_profile_secure_mode_fragment.xml | 4 +- .../layout/assistant_secure_mode_fragment.xml | 4 +- app/src/main/res/layout/contact_fragment.xml | 6 +- app/src/main/res/layout/settings_fragment.xml | 545 +++++++++++++++++- .../res/layout/voip_call_main_actions.xml | 4 +- app/src/main/res/values/colors.xml | 2 +- app/src/main/res/values/strings.xml | 17 + 12 files changed, 760 insertions(+), 51 deletions(-) create mode 100644 app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt diff --git a/app/src/main/java/org/linphone/core/CorePreferences.kt b/app/src/main/java/org/linphone/core/CorePreferences.kt index 3c4f92856..7c07b8dd6 100644 --- a/app/src/main/java/org/linphone/core/CorePreferences.kt +++ b/app/src/main/java/org/linphone/core/CorePreferences.kt @@ -62,6 +62,20 @@ class CorePreferences @UiThread constructor(private val context: Context) { config.setBool("app", "publish_presence", value) } + // Calls settings + + var routeAudioToBluetoothIfAvailable: Boolean + get() = config.getBool("app", "route_audio_to_bluetooth_if_available", true) + set(value) { + config.setBool("app", "route_audio_to_bluetooth_if_available", value) + } + + var automaticallyStartCallRecording: Boolean + get() = config.getBool("app", "auto_start_call_record", false) + set(value) { + config.setBool("app", "auto_start_call_record", value) + } + // Will disable chat feature completely @get:WorkerThread val disableChat: Boolean @@ -91,6 +105,12 @@ class CorePreferences @UiThread constructor(private val context: Context) { val thirdPartyDefaultValuesPath: String get() = context.filesDir.absolutePath + "/assistant_third_party_default_values" + private val ringtonesPath: String + get() = context.filesDir.absolutePath + "/share/sounds/linphone/rings/" + + val defaultRingtonePath: String + get() = ringtonesPath + "notes_of_the_optimistic.mkv" + @UiThread fun copyAssetsFromPackage() { copy("linphonerc_default", configPath) diff --git a/app/src/main/java/org/linphone/ui/main/settings/fragment/SettingsFragment.kt b/app/src/main/java/org/linphone/ui/main/settings/fragment/SettingsFragment.kt index 8ec0e54ad..aa0ea0122 100644 --- a/app/src/main/java/org/linphone/ui/main/settings/fragment/SettingsFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/settings/fragment/SettingsFragment.kt @@ -5,13 +5,20 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.annotation.UiThread +import androidx.navigation.navGraphViewModels +import org.linphone.R import org.linphone.databinding.SettingsFragmentBinding import org.linphone.ui.main.fragment.GenericFragment +import org.linphone.ui.main.settings.viewmodel.SettingsViewModel @UiThread class SettingsFragment : GenericFragment() { private lateinit var binding: SettingsFragmentBinding + private val viewModel: SettingsViewModel by navGraphViewModels( + R.id.main_nav_graph + ) + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -24,6 +31,7 @@ class SettingsFragment : GenericFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.lifecycleOwner = viewLifecycleOwner + binding.viewModel = viewModel binding.setBackClickListener { goBack() diff --git a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt new file mode 100644 index 000000000..a544b0c98 --- /dev/null +++ b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/SettingsViewModel.kt @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2010-2023 Belledonne Communications SARL. + * + * This file is part of linphone-android + * (see https://www.linphone.org). + * + * 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 . + */ +package org.linphone.ui.main.settings.viewmodel + +import android.os.Vibrator +import androidx.annotation.UiThread +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import org.linphone.LinphoneApplication.Companion.coreContext +import org.linphone.LinphoneApplication.Companion.corePreferences +import org.linphone.core.tools.Log + +class SettingsViewModel @UiThread constructor() : ViewModel() { + companion object { + private const val TAG = "[Settings ViewModel]" + } + + val expandCalls = MutableLiveData() + val expandNetwork = MutableLiveData() + val expandUserInterface = MutableLiveData() + + // Calls settings + val echoCancellerEnabled = MutableLiveData() + val routeAudioToBluetooth = MutableLiveData() + val videoEnabled = MutableLiveData() + val autoInitiateVideoCalls = MutableLiveData() + val autoAcceptVideoRequests = MutableLiveData() + val useDeviceRingtone = MutableLiveData() + val vibrateDuringIncomingCall = MutableLiveData() + val autoRecordCalls = MutableLiveData() + + // Network settings + val useWifiOnly = MutableLiveData() + + // User Interface settings + + val isVibrationAvailable = MutableLiveData() + + init { + expandCalls.value = true + expandNetwork.value = true + expandUserInterface.value = false + + val vibrator = coreContext.context.getSystemService(Vibrator::class.java) + isVibrationAvailable.value = vibrator.hasVibrator() + if (isVibrationAvailable.value == false) { + Log.w("$TAG Device doesn't seem to have a vibrator, hiding related setting") + } + + coreContext.postOnCoreThread { core -> + echoCancellerEnabled.postValue(core.isEchoCancellationEnabled) + routeAudioToBluetooth.postValue(corePreferences.routeAudioToBluetoothIfAvailable) + videoEnabled.postValue(core.isVideoEnabled) + autoInitiateVideoCalls.postValue(core.videoActivationPolicy.automaticallyInitiate) + autoAcceptVideoRequests.postValue(core.videoActivationPolicy.automaticallyAccept) + useDeviceRingtone.postValue(core.ring == null) + vibrateDuringIncomingCall.postValue(core.isVibrationOnIncomingCallEnabled) + autoRecordCalls.postValue(corePreferences.automaticallyStartCallRecording) + + useWifiOnly.postValue(core.isWifiOnlyEnabled) + } + } + + @UiThread + fun toggleEchoCanceller() { + val newValue = echoCancellerEnabled.value == false + coreContext.postOnCoreThread { core -> + core.isEchoCancellationEnabled = newValue + echoCancellerEnabled.postValue(newValue) + } + } + + @UiThread + fun toggleRouteAudioToBluetooth() { + val newValue = routeAudioToBluetooth.value == false + coreContext.postOnCoreThread { + corePreferences.routeAudioToBluetoothIfAvailable = newValue + routeAudioToBluetooth.postValue(newValue) + } + } + + @UiThread + fun toggleEnableVideo() { + val newValue = videoEnabled.value == false + coreContext.postOnCoreThread { core -> + core.isVideoCaptureEnabled = newValue + core.isVideoDisplayEnabled = newValue + videoEnabled.postValue(newValue) + } + } + + @UiThread + fun toggleAutoInitiateVideoCalls() { + val newValue = autoInitiateVideoCalls.value == false + coreContext.postOnCoreThread { core -> + val policy = core.videoActivationPolicy + policy.automaticallyInitiate = newValue + core.videoActivationPolicy = policy + autoInitiateVideoCalls.postValue(newValue) + } + } + + @UiThread + fun toggleAutoAcceptVideoRequests() { + val newValue = autoAcceptVideoRequests.value == false + coreContext.postOnCoreThread { core -> + val policy = core.videoActivationPolicy + policy.automaticallyAccept = newValue + core.videoActivationPolicy = policy + autoAcceptVideoRequests.postValue(newValue) + } + } + + @UiThread + fun toggleDeviceRingtone() { + val newValue = useDeviceRingtone.value == false + coreContext.postOnCoreThread { core -> + core.ring = if (newValue) null else corePreferences.defaultRingtonePath + useDeviceRingtone.postValue(newValue) + } + } + + @UiThread + fun toggleVibrateOnIncomingCalls() { + val newValue = vibrateDuringIncomingCall.value == false + coreContext.postOnCoreThread { core -> + core.isVibrationOnIncomingCallEnabled = newValue + vibrateDuringIncomingCall.postValue(newValue) + } + } + + @UiThread + fun toggleAutoRecordCall() { + val newValue = autoRecordCalls.value == false + coreContext.postOnCoreThread { + corePreferences.automaticallyStartCallRecording = newValue + autoRecordCalls.postValue(newValue) + } + } + + @UiThread + fun toggleUseWifiOnly() { + val newValue = useWifiOnly.value == false + coreContext.postOnCoreThread { core -> + core.isWifiOnlyEnabled = newValue + useWifiOnly.postValue(newValue) + } + } + + @UiThread + fun toggleCallsExpand() { + expandCalls.value = expandCalls.value == false + } + + @UiThread + fun toggleNetworkExpand() { + expandNetwork.value = expandNetwork.value == false + } + + @UiThread + fun toggleUserInterfaceExpand() { + expandUserInterface.value = expandUserInterface.value == false + } +} diff --git a/app/src/main/res/drawable/caret_up.xml b/app/src/main/res/drawable/caret_up.xml index b1fdf9889..a8354428f 100644 --- a/app/src/main/res/drawable/caret_up.xml +++ b/app/src/main/res/drawable/caret_up.xml @@ -1,13 +1,9 @@ - - + android:viewportWidth="256" + android:viewportHeight="256"> + diff --git a/app/src/main/res/layout/account_profile_fragment.xml b/app/src/main/res/layout/account_profile_fragment.xml index 455b9fe1f..6e2580a36 100644 --- a/app/src/main/res/layout/account_profile_fragment.xml +++ b/app/src/main/res/layout/account_profile_fragment.xml @@ -145,7 +145,7 @@ android:id="@+id/details_background" android:layout_width="0dp" android:layout_height="0dp" - android:layout_marginTop="16dp" + android:layout_marginTop="8dp" android:layout_marginStart="17dp" android:layout_marginEnd="17dp" android:src="@drawable/shape_squircle_gray_2_background" @@ -351,7 +351,7 @@ android:id="@+id/actions_background" android:layout_width="0dp" android:layout_height="0dp" - android:layout_marginTop="10dp" + android:layout_marginTop="8dp" android:layout_marginStart="17dp" android:layout_marginEnd="17dp" android:src="@drawable/shape_squircle_gray_2_background" diff --git a/app/src/main/res/layout/account_profile_secure_mode_fragment.xml b/app/src/main/res/layout/account_profile_secure_mode_fragment.xml index 0bcc7091d..8cd66f892 100644 --- a/app/src/main/res/layout/account_profile_secure_mode_fragment.xml +++ b/app/src/main/res/layout/account_profile_secure_mode_fragment.xml @@ -63,7 +63,7 @@ style="@style/default_text_style_800" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="30dp" + android:layout_marginTop="32dp" android:layout_marginStart="16dp" android:text="@string/assistant_secure_mode_default_title" android:textSize="16sp" @@ -197,7 +197,7 @@ style="@style/default_text_style_800" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="30dp" + android:layout_marginTop="32dp" android:layout_marginStart="16dp" android:text="@string/assistant_secure_mode_interoperable_title" android:textSize="16sp" diff --git a/app/src/main/res/layout/assistant_secure_mode_fragment.xml b/app/src/main/res/layout/assistant_secure_mode_fragment.xml index eae4fdd0b..50ed69ed9 100644 --- a/app/src/main/res/layout/assistant_secure_mode_fragment.xml +++ b/app/src/main/res/layout/assistant_secure_mode_fragment.xml @@ -86,7 +86,7 @@ style="@style/default_text_style_800" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="30dp" + android:layout_marginTop="32dp" android:layout_marginStart="16dp" android:text="@string/assistant_secure_mode_default_title" android:textSize="16sp" @@ -220,7 +220,7 @@ style="@style/default_text_style_800" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="30dp" + android:layout_marginTop="32dp" android:layout_marginStart="16dp" android:text="@string/assistant_secure_mode_interoperable_title" android:textSize="16sp" diff --git a/app/src/main/res/layout/contact_fragment.xml b/app/src/main/res/layout/contact_fragment.xml index adf66b4ce..9418196cc 100644 --- a/app/src/main/res/layout/contact_fragment.xml +++ b/app/src/main/res/layout/contact_fragment.xml @@ -260,7 +260,7 @@ android:orientation="vertical" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" - android:layout_marginTop="10dp" + android:layout_marginTop="8dp" android:padding="10dp" android:background="@drawable/shape_squircle_gray_2_background" app:layout_constraintStart_toStartOf="parent" @@ -378,7 +378,7 @@ android:id="@+id/trust_background" android:layout_width="0dp" android:layout_height="0dp" - android:layout_marginTop="10dp" + android:layout_marginTop="8dp" android:layout_marginStart="17dp" android:layout_marginEnd="17dp" android:src="@drawable/shape_squircle_gray_2_background" @@ -465,7 +465,7 @@ android:id="@+id/actions_background" android:layout_width="0dp" android:layout_height="0dp" - android:layout_marginTop="10dp" + android:layout_marginTop="8dp" android:layout_marginStart="17dp" android:layout_marginEnd="17dp" android:src="@drawable/shape_squircle_gray_2_background" diff --git a/app/src/main/res/layout/settings_fragment.xml b/app/src/main/res/layout/settings_fragment.xml index 159772c0c..99b281838 100644 --- a/app/src/main/res/layout/settings_fragment.xml +++ b/app/src/main/res/layout/settings_fragment.xml @@ -8,42 +8,529 @@ + - - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/voip_call_main_actions.xml b/app/src/main/res/layout/voip_call_main_actions.xml index 35977dbec..647937733 100644 --- a/app/src/main/res/layout/voip_call_main_actions.xml +++ b/app/src/main/res/layout/voip_call_main_actions.xml @@ -15,7 +15,7 @@ #EEF7F8 - #6C7A870xFF + #6C7A87 #F9F9F9 #EEF6F8 #949494 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 63d06b6bd..708040bc6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -138,6 +138,23 @@ Debug logs URL copied into clipboard Failed to upload debug logs + Calls + Use echo canceller + Prevents echo from being heard by remote end + Route audio to bluetooth device, if any + Enable video + Start video calls + Always initiate calls as video + Accept video calls + Always accept video calls + Use this device\'s ringtone + Vibrate while incoming call is ringing + Automatically start recording calls + Network + Use only Wi-Fi networks + User interface + Advanced settings + Manage account Details Add a picture