Call Forward

This commit is contained in:
Christophe Deschamps 2025-05-02 21:15:44 +02:00
parent 3396d6d848
commit 305973038d
15 changed files with 343 additions and 3 deletions

View file

@ -124,6 +124,8 @@ SettingsCore::SettingsCore(QObject *parent) : QObject(parent) {
INIT_CORE_MEMBER(CallToneIndicationsEnabled, settingsModel)
INIT_CORE_MEMBER(CommandLine, settingsModel)
INIT_CORE_MEMBER(DisableCommandLine, settingsModel)
INIT_CORE_MEMBER(DisableCallForward, settingsModel)
INIT_CORE_MEMBER(CallForwardToAddress, settingsModel)
}
SettingsCore::SettingsCore(const SettingsCore &settingsCore) {
@ -198,6 +200,7 @@ SettingsCore::SettingsCore(const SettingsCore &settingsCore) {
mCallToneIndicationsEnabled = settingsCore.mCallToneIndicationsEnabled;
mCommandLine = settingsCore.mCommandLine;
mDisableCommandLine = settingsCore.mDisableCommandLine;
mDisableCallForward = settingsCore.mDisableCallForward;
mDefaultDomain = settingsCore.mDefaultDomain;
mShowAccountDevices = settingsCore.mShowAccountDevices;
@ -417,6 +420,10 @@ void SettingsCore::setSelf(QSharedPointer<SettingsCore> me) {
commandLine, CommandLine)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
disableCommandLine, DisableCommandLine)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
disableCallForward, DisableCallForward)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QString,
callForwardToAddress, CallForwardToAddress)
auto coreModelConnection = SafeConnection<SettingsCore, CoreModel>::create(me, CoreModel::getInstance());

View file

@ -231,6 +231,8 @@ public:
DECLARE_CORE_GETSET_MEMBER(bool, callToneIndicationsEnabled, CallToneIndicationsEnabled)
DECLARE_CORE_GETSET_MEMBER(bool, disableCommandLine, DisableCommandLine)
DECLARE_CORE_GETSET_MEMBER(QString, commandLine, CommandLine)
DECLARE_CORE_GETSET_MEMBER(bool, disableCallForward, DisableCallForward)
DECLARE_CORE_GETSET_MEMBER(QString, callForwardToAddress, CallForwardToAddress)
signals:

View file

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.1334 15.1013L15.8935 13.2014L15.8818 13.196C15.6617 13.1018 15.4216 13.0641 15.1832 13.0861C14.9448 13.1081 14.7157 13.1892 14.5165 13.322C14.493 13.3375 14.4705 13.3543 14.449 13.3724L12.2584 15.2399C10.8706 14.5658 9.43775 13.1438 8.76365 11.774L10.6339 9.55006C10.6519 9.52756 10.669 9.50506 10.6852 9.48076C10.8151 9.28213 10.894 9.05445 10.9147 8.81798C10.9355 8.5815 10.8974 8.34357 10.804 8.12535V8.11455L8.89865 3.86742C8.77512 3.58236 8.5627 3.34489 8.29311 3.19047C8.02353 3.03605 7.71123 2.97296 7.40284 3.01062C6.1833 3.1711 5.06388 3.77001 4.25366 4.69552C3.44343 5.62102 2.9978 6.80981 3.00001 8.03985C3.00001 15.1859 8.81405 20.9999 15.9601 20.9999C17.1901 21.0021 18.3789 20.5565 19.3044 19.7463C20.2299 18.9361 20.8289 17.8166 20.9893 16.5971C21.0271 16.2888 20.9641 15.9766 20.8098 15.707C20.6556 15.4375 20.4183 15.225 20.1334 15.1013ZM15.9601 19.5599C12.9058 19.5566 9.97757 18.3418 7.81786 16.1821C5.65814 14.0224 4.44335 11.0941 4.44002 8.03985C4.43663 7.16099 4.75327 6.31094 5.33079 5.64845C5.90831 4.98597 6.70723 4.55635 7.57834 4.43983C7.57799 4.44342 7.57799 4.44704 7.57834 4.45063L9.46835 8.68066L7.60804 10.9073C7.58916 10.929 7.57201 10.9522 7.55674 10.9766C7.4213 11.1844 7.34185 11.4237 7.32608 11.6713C7.31031 11.9188 7.35876 12.1663 7.46674 12.3896C8.28215 14.0573 9.96246 15.725 11.6482 16.5395C11.8731 16.6465 12.122 16.6933 12.3705 16.6753C12.6189 16.6573 12.8585 16.5752 13.0657 16.4369C13.0888 16.4213 13.111 16.4045 13.1323 16.3865L15.3202 14.5199L19.5502 16.4144C19.5502 16.4144 19.5574 16.4144 19.5601 16.4144C19.445 17.2868 19.016 18.0873 18.3534 18.6662C17.6908 19.2452 16.84 19.5629 15.9601 19.5599Z" fill="#FFDC2E"/>
<path d="M18.486 4.67027L20.1735 6.35777C20.2128 6.39697 20.244 6.44354 20.2653 6.49482C20.2866 6.5461 20.2976 6.60108 20.2976 6.6566C20.2976 6.71213 20.2866 6.7671 20.2653 6.81838C20.244 6.86966 20.2128 6.91624 20.1735 6.95543L18.486 8.64293C18.4067 8.72218 18.2992 8.76671 18.1871 8.76671C18.0751 8.76671 17.9676 8.72218 17.8883 8.64293C17.8091 8.56368 17.7645 8.45618 17.7645 8.3441C17.7645 8.23202 17.8091 8.12453 17.8883 8.04527L18.8555 7.07813L16.5 7.07813C15.717 7.07896 14.9664 7.39036 14.4128 7.944C13.8591 8.49764 13.5477 9.24829 13.5469 10.0312C13.5469 10.1431 13.5024 10.2504 13.4233 10.3296C13.3442 10.4087 13.2369 10.4531 13.125 10.4531C13.0131 10.4531 12.9058 10.4087 12.8267 10.3296C12.7476 10.2504 12.7031 10.1431 12.7031 10.0312C12.7042 9.0246 13.1046 8.0595 13.8164 7.34769C14.5282 6.63588 15.4933 6.23549 16.5 6.23438H18.8555L17.888 5.26723C17.8087 5.18797 17.7642 5.08048 17.7642 4.9684C17.7642 4.85632 17.8087 4.74882 17.888 4.66957C17.9672 4.59032 18.0747 4.54579 18.1868 4.54579C18.2989 4.54579 18.4064 4.59032 18.4856 4.66957L18.486 4.67027Z" fill="#FFDC2E"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -871,6 +871,18 @@
</context>
<context>
<name>CallPage</name>
<message>
<location filename="../../view/Page/Main/Call/CallPage.qml"/>
<source>call_forward_to_address_info</source>
<extracomment>&quot;Forward calls to: &quot;</extracomment>
<translation>Forward calls to: </translation>
</message>
<message>
<location filename="../../view/Page/Main/Call/CallPage.qml"/>
<source>call_forward_to_address_info_voicemail</source>
<extracomment>&quot;Voicemail&quot;</extracomment>
<translation>Voicemail</translation>
</message>
<message>
<location filename="../../view/Page/Main/Call/CallPage.qml" line="14"/>
<source>history_call_start_title</source>
@ -3930,6 +3942,12 @@ To enable them in a commercial project, please contact us.</translation>
<extracomment>&quot;Appels&quot;</extracomment>
<translation>Calls</translation>
</message>
<message>
<location filename="../../view/Page/Form/Settings/SettingsPage.qml"/>
<source>settings_call_forward</source>
<extracomment>&quot;Transfert d'appels&quot;</extracomment>
<translation>Call forward</translation>
</message>
<message>
<location filename="../../view/Page/Form/Settings/SettingsPage.qml" line="17"/>
<source>settings_conversations_title</source>
@ -5506,4 +5524,85 @@ To enable them in a commercial project, please contact us.</translation>
<translation>Ok</translation>
</message>
</context>
<context>
<name>CallForwardSettingsLayout</name>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_activate_title</source>
<extracomment>&quot;Forward calls&quot;</extracomment>
<translation>Forward calls</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_activate_subtitle</source>
<extracomment>&quot;Forward calls&quot;</extracomment>
<translation>Forward calls to voicemail or a Number / SIP Address / number</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_destination_choose</source>
<extracomment>&quot;Forward calls to&quot;</extracomment>
<translation>Forward calls to:</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_to_voicemail</source>
<extracomment>&quot;Voicemail&quot;</extracomment>
<translation>Voicemail</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_to_sipaddress</source>
<extracomment>&quot;Number / SIP address&quot;</extracomment>
<translation>Number / SIP Address</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_sipaddress_title</source>
<extracomment>&quot;Number / Sip address:&quot;</extracomment>
<translation>Number / SIP Address:</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_sipaddress_placeholder</source>
<extracomment>&quot;John.doe&quot;</extracomment>
<translation>John.doe</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_address_cannot_be_empty</source>
<extracomment>&quot;A number or SIP address is mandatory&quot;</extracomment>
<translation>A number or SIP address is mandatory</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_address_timeout</source>
<extracomment>&quot;Unable to set call forward, request timeout&quot;</extracomment>
<translation>Unable to set call forward, request timeout</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_address_progress_disabling</source>
<extracomment>&quot;Disabling call forward&quot;</extracomment>
<translation>Disabling call forward</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_address_progress_enabling</source>
<extracomment>&quot;Enabling call forward to:&quot;</extracomment>
<translation>Enabling call forward to:</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_activation_success</source>
<extracomment>&quot;Call forward activated to : &quot;</extracomment>
<translation>Call forward activated to : </translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/CallForwardSettingsLayout.qml"/>
<source>settings_call_forward_deactivation_success</source>
<extracomment>&quot;Call forward deactivated&quot;</extracomment>
<translation>Call forward deactivated</translation>
</message>
</context>
</TS>

View file

@ -706,6 +706,29 @@ QString SettingsModel::getDefaultDomain() const {
mConfig->getString(SettingsModel::AppSection, "default_domain", "sip.linphone.org"));
}
void SettingsModel::enableCallForward(QString destination) {
// TODO implement business logic to activate call forward to destination on PBX via external API (contains voicemail
// or a destination).
mConfig->setString(UiSection, "call_forward_to_address", Utils::appStringToCoreString(destination));
emit callForwardToAddressChanged(getCallForwardToAddress());
}
void SettingsModel::disableCallForward() {
// TODO implement business logic to de-activate call forward on PBX via external API
mConfig->setString(UiSection, "call_forward_to_address", "");
}
QString SettingsModel::getCallForwardToAddress() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return Utils::coreStringToAppString(mConfig->getString(UiSection, "call_forward_to_address", ""));
}
void SettingsModel::setCallForwardToAddress(QString data) {
if (data == "") disableCallForward();
else enableCallForward(data);
emit(callForwardToAddressChanged(data));
}
// clang-format off
void SettingsModel::notifyConfigReady(){
DEFINE_NOTIFY_CONFIG_READY(disableChatFeature, DisableChatFeature)
@ -874,5 +897,11 @@ DEFINE_GETSET_CONFIG(SettingsModel,
DisableCommandLine,
"disable_command_line",
false)
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,
disableCallForward,
DisableCallForward,
"disable_call_forward",
true)
// clang-format on

View file

@ -186,6 +186,8 @@ public:
DECLARE_GETSET(bool, usernameOnlyForCardDAVLookupsInCalls, UsernameOnlyForCardDAVLookupsInCalls)
DECLARE_GETSET(QString, commandLine, CommandLine)
DECLARE_GETSET(bool, disableCommandLine, DisableCommandLine)
DECLARE_GETSET(bool, disableCallForward, DisableCallForward)
DECLARE_GETSET(QString, callForwardToAddress, CallForwardToAddress)
signals:
void logsUploadUrlChanged();
@ -235,6 +237,9 @@ private:
MediastreamerUtils::SimpleCaptureGraph *mSimpleCaptureGraph = nullptr;
int mCaptureGraphListenerCount = 0;
void enableCallForward(QString destination);
void disableCallForward();
static std::shared_ptr<SettingsModel> gSettingsModel;
DECLARE_ABSTRACT_OBJECT

View file

@ -122,6 +122,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Page/Layout/Settings/AccountSettingsGeneralLayout.qml
view/Page/Layout/Settings/AccountSettingsParametersLayout.qml
view/Page/Layout/Settings/CallSettingsLayout.qml
view/Page/Layout/Settings/CallForwardSettingsLayout.qml
view/Page/Layout/Settings/ContactsSettingsLayout.qml
view/Page/Layout/Settings/MeetingsSettingsLayout.qml
view/Page/Layout/Settings/ContactsSettingsProviderLayout.qml

View file

@ -29,6 +29,10 @@ FormItemLayout {
property var isValid: function(text) {
return true
}
function empty() {
textField.text = ""
}
contentItem: TextField {
id: textField

View file

@ -22,6 +22,7 @@ AbstractMainPage {
}
property var families
property var defaultIndex: -1
leftPanelContent: ColumnLayout {
id: leftPanel
@ -62,7 +63,7 @@ AbstractMainPage {
model: mainItem.families
Layout.topMargin: Math.round(41 * DefaultStyle.dp)
Layout.leftMargin: leftPanel.sideMargin
property int selectedIndex: 0
property int selectedIndex: mainItem.defaultIndex != -1 ? mainItem.defaultIndex : 0
activeFocusOnTab: true
delegate: SettingsMenuItem {

View file

@ -13,6 +13,8 @@ AbstractSettingsMenu {
families: [
//: "Appels"
{title: qsTr("settings_calls_title"), layout: "CallSettingsLayout"},
//: "Transfert d'appel"
{title: qsTr("settings_call_forward"), layout: "CallForwardSettingsLayout"},
//: "Conversations"
{title: qsTr("settings_conversations_title"), layout: "ChatSettingsLayout", visible: !SettingsCpp.disableChatFeature},
//: "Contacts"

View file

@ -608,6 +608,12 @@ Item {
Component.onCompleted: {
magicSearchBar.numericPadPopup = callPage.numericPadPopup
}
onGoToCallForwardSettings: {
var page = settingsPageComponent.createObject(parent, {
defaultIndex: 1
});
openContextualMenuComponent(page)
}
}
ContactPage {
id: contactPage

View file

@ -0,0 +1,139 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls.Basic as Control
import Linphone
import SettingsCpp 1.0
import UtilsCpp
AbstractSettingsLayout {
id: mainItem
property bool enableCallForward: SettingsCpp.callForwardToAddress.length > 0
property string localCallForwardToAddress: SettingsCpp.callForwardToAddress
width: parent?.width
contentModel: [
{
title: "",
subTitle: "",
contentComponent: parametersComponent
}
]
Connections {
target: SettingsCpp
function onCallForwardToAddressChanged() {
requestTimeOut.stop()
UtilsCpp.getMainWindow().closeLoadingPopup()
UtilsCpp.showInformationPopup("",
SettingsCpp.callForwardToAddress
? qsTr("settings_call_forward_activation_success") + (SettingsCpp.callForwardToAddress == "voicemail" ? qsTr("settings_call_forward_to_voicemail") : SettingsCpp.callForwardToAddress)
: qsTr("settings_call_forward_deactivation_success")
, true)
}
}
Timer {
id: requestTimeOut
interval: 10000
running: false
repeat: false
onTriggered: {
UtilsCpp.getMainWindow().closeLoadingPopup()
UtilsCpp.showInformationPopup("", qsTr("settings_call_forward_address_timeout"), false)
}
}
onSave: {
if (mainItem.enableCallForward && mainItem.localCallForwardToAddress.length == 0) {
UtilsCpp.getMainWindow().showInformationPopup("", qsTr("settings_call_forward_address_cannot_be_empty"), false)
return
}
requestTimeOut.start()
if (!mainItem.enableCallForward && SettingsCpp.callForwardToAddress.length > 0) {
UtilsCpp.getMainWindow().showLoadingPopup(qsTr("settings_call_forward_address_progress_disabling") + " ...")
SettingsCpp.callForwardToAddress = ""
} else if (SettingsCpp.callForwardToAddress != mainItem.localCallForwardToAddress) {
UtilsCpp.getMainWindow().showLoadingPopup(qsTr("settings_call_forward_address_progress_enabling")+(mainItem.localCallForwardToAddress === 'voicemail' ? qsTr("settings_call_forward_to_voicemail") : mainItem.localCallForwardToAddress) + " ...")
SettingsCpp.callForwardToAddress = mainItem.localCallForwardToAddress
}
}
// Generic forward parameters
/////////////////////////////
Component {
id: parametersComponent
ColumnLayout {
spacing: Math.round(20 * DefaultStyle.dp)
SwitchSetting {
//: "Forward calls"
titleText: qsTr("settings_call_forward_activate_title")
//: "Enable call forwarding to voicemail or sip address"
subTitleText: qsTr("settings_call_forward_activate_subtitle")
propertyName: "enableCallForward"
propertyOwner: mainItem
}
Text {
visible: mainItem.enableCallForward
//: Forward to destination
text: qsTr("settings_call_forward_destination_choose")
font {
pixelSize: Typography.p2l.pixelSize
weight: Typography.p2l.weight
}
}
ComboBox {
id: forwardDestination
visible: mainItem.enableCallForward
Layout.fillWidth: true
Layout.preferredHeight: Math.round(49 * DefaultStyle.dp)
model: [
{text: qsTr("settings_call_forward_to_voicemail")},
{text: qsTr("settings_call_forward_to_sipaddress")}
]
property bool isInitialized: false
Component.onCompleted: {
if (mainItem.enableCallForward) {
forwardDestination.currentIndex =
(mainItem.localCallForwardToAddress === "voicemail" || mainItem.localCallForwardToAddress.length === 0) ? 0 : 1;
} else {
forwardDestination.currentIndex = 0;
}
forwardDestination.isInitialized = true;
}
onCurrentIndexChanged: {
if (!forwardDestination.isInitialized)
return;
if (currentIndex == 0)
mainItem.localCallForwardToAddress = "voicemail";
else {
mainItem.localCallForwardToAddress = "";
sipInputField.empty();
}
}
onVisibleChanged: {
if (visible) {
currentIndex = 0
mainItem.localCallForwardToAddress = "voicemail";
}
}
}
DecoratedTextField {
id: sipInputField
visible: mainItem.enableCallForward && forwardDestination.currentIndex == 1
Layout.fillWidth: true
propertyName: "localCallForwardToAddress"
propertyOwner: mainItem
//: SIP Address
title: qsTr("settings_call_forward_sipaddress_title")
placeHolder: qsTr("settings_call_forward_sipaddress_placeholder")
useTitleAsPlaceHolder: false
toValidate: true
}
}
}
}

View file

@ -18,6 +18,7 @@ AbstractMainPage {
property var selectedRowHistoryGui
signal listViewUpdated
signal goToCallForwardSettings
onVisibleChanged: if (!visible) {
goToCallHistory()
@ -217,6 +218,42 @@ AbstractMainPage {
value: false
}
}
Rectangle {
visible: SettingsCpp.callForwardToAddress.length > 0
Layout.fillWidth: true
Layout.preferredHeight: Math.round(40 * DefaultStyle.dp)
Layout.topMargin: Math.round(18 * DefaultStyle.dp)
Layout.rightMargin: Math.round(39 * DefaultStyle.dp)
color: "transparent"
radius: 25 * DefaultStyle.dp
border.color: DefaultStyle.warning_500_main
border.width: 2 * DefaultStyle.dp
RowLayout {
anchors.centerIn: parent
spacing: 10 * DefaultStyle.dp
EffectImage {
fillMode: Image.PreserveAspectFit
imageSource: AppIcons.callForward
colorizationColor: DefaultStyle.warning_500_main
Layout.preferredHeight: Math.round(24 * DefaultStyle.dp)
Layout.preferredWidth: Math.round(24 * DefaultStyle.dp)
}
Text {
text: qsTr("call_forward_to_address_info") + (SettingsCpp.callForwardToAddress == 'voicemail' ? qsTr("call_forward_to_address_info_voicemail") : SettingsCpp.callForwardToAddress)
color: DefaultStyle.warning_500_main
font: Typography.p1
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
goToCallForwardSettings()
}
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
@ -276,6 +313,7 @@ AbstractMainPage {
policy: Control.ScrollBar.AsNeeded
}
}
}
}
}

View file

@ -126,4 +126,5 @@ QtObject {
property string resourcePackage: "image://internal/package.svg"
property string appWindow: "image://internal/app-window.svg"
property string bellMwi: "image://internal/bell-simple.svg"
property string callForward: "image://internal/call-forward.svg"
}

View file

@ -61,5 +61,6 @@ QtObject {
property color groupCallButtonColor: "#EEF7F8"
property color placeholders: '#CACACA' // No name in design
property color warning_500_main: "#FFDC2E"
}