From 2338dae8e584ec7603c95e76a858166e9a0e318c Mon Sep 17 00:00:00 2001 From: Julien Wadel Date: Tue, 12 Mar 2024 09:05:33 +0100 Subject: [PATCH] - Keyboard shortcuts: * 'Ctrl+Shift+W' (or V): accept with video the last incoming call. * 'Ctrl+Shift+A': accept without video the last incoming call. * 'Ctrl+Shift+D': terminate the last call. * 'Ctrl+Shift+E': Enable/disable echo cancellation. * 'Ctrl+Shift+L': Unmute/Mute speaker. * 'Ctrl+Shift+M': Unmute/Mute microphone. - Request application focus when hovering a call notification. - Forbid to calibrate echo cancellation while being in call because it is not supported. # Conflicts: # CHANGELOG.md # linphone-app/src/components/settings/SettingsModel.hpp # linphone-app/ui/modules/Common/Form/MouseArea.qml --- CHANGELOG.md | 12 +++++ linphone-app/assets/languages/zh_CN.ts | 4 +- .../src/components/calls/CallsListModel.cpp | 49 +++++++++++++++++++ .../src/components/calls/CallsListModel.hpp | 7 +++ .../src/components/settings/SettingsModel.cpp | 5 ++ .../src/components/settings/SettingsModel.hpp | 9 ++-- .../ui/modules/Common/Form/MouseArea.qml | 7 +-- .../Linphone/Notifications/Notification.qml | 6 +-- .../NotificationReceivedCall.qml | 10 +++- .../Notifications/NotificationStyle.qml | 4 ++ linphone-app/ui/views/App/Main/MainWindow.qml | 33 +++++++++++++ .../ui/views/App/Settings/SettingsAudio.qml | 4 +- 12 files changed, 135 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46bc5ad4b..f0cd45c3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - '[ui] logs_max_size' : option to set the max size of one log file. +- '[ui] notification_origin' : option to specify where to display notifications (only supported: 0=bottom-right and 1=top-right). +- '[ui] systray_notification_blink' : option to activate/deactivate the blinking systray on unread notifications. +- '[ui] systray_notification_global' : option to display notification number from all accounts or only selected. +- '[ui] systray_notification_filtered' : option to filter the notification number (not count if chat room is muted). +- Keyboard shortcuts: + * 'Ctrl+Shift+W' (or V): accept with video the last incoming call. + * 'Ctrl+Shift+A': accept without video the last incoming call. + * 'Ctrl+Shift+D': terminate the last call. + * 'Ctrl+Shift+E': Enable/disable echo cancellation. + * 'Ctrl+Shift+L': Unmute/Mute speaker. + * 'Ctrl+Shift+M': Unmute/Mute microphone. +- Request application focus when hovering a call notification. ## 5.2.1 - 2024-02-01 diff --git a/linphone-app/assets/languages/zh_CN.ts b/linphone-app/assets/languages/zh_CN.ts index 60beba189..d37e5130d 100644 --- a/linphone-app/assets/languages/zh_CN.ts +++ b/linphone-app/assets/languages/zh_CN.ts @@ -2076,7 +2076,7 @@ checkForUpdates 'Check for updates' : Item menu for checking updates - + 检测软件更新 recordings @@ -2106,7 +2106,7 @@ checkForUpdates 'Check for updates' : Item menu for checking updates - + 检测软件更新 recordings diff --git a/linphone-app/src/components/calls/CallsListModel.cpp b/linphone-app/src/components/calls/CallsListModel.cpp index f11abb91f..f52572d3a 100644 --- a/linphone-app/src/components/calls/CallsListModel.cpp +++ b/linphone-app/src/components/calls/CallsListModel.cpp @@ -501,6 +501,55 @@ void CallsListModel::terminateCall (const QString& sipAddress) const{ } } +QSharedPointer CallsListModel::getLastCall(bool incoming) const{ + QSharedPointer lastCall = nullptr; + time_t lastTime = 0; + auto item = mList.rbegin(); + while(item != mList.rend() && !lastCall) { + auto call = item->objectCast(); + if(!incoming || call->getStatus() == CallModel::CallStatusIncoming) { + lastCall = call; + } + } + return lastCall; +} + +QSharedPointer CallsListModel::getCallModel(const std::shared_ptr &call) const{ + QSharedPointer callModel; + if(call) { + auto itCall = std::find_if(mList.begin(), mList.end(), [call](const QSharedPointer &item){ + auto c = item.objectCast(); + return c && c->getCall() == call; + }); + if( itCall != mList.end()) + callModel = itCall->objectCast(); + } + return callModel; +} + +void CallsListModel::acceptLastIncomingCall(bool video) { + auto call = getLastCall(true); + if(call) { + if(video) call->acceptWithVideo(); + else call->accept(); + } +} + +void CallsListModel::terminateLastCall() { + auto call = getLastCall(false); // Allow to terminate last outgoing call + if(call) call->terminate(); +} + +void CallsListModel::toggleMuteSpeaker() { + auto currentCall = getCallModel(CoreManager::getInstance()->getCore()->getCurrentCall()); + if(currentCall) currentCall->setSpeakerMuted(!currentCall->getSpeakerMuted()); +} + +void CallsListModel::toggleMuteMicrophone() { + auto currentCall = getCallModel(CoreManager::getInstance()->getCore()->getCurrentCall()); + if(currentCall) currentCall->setMicroMuted(!currentCall->getMicroMuted()); +} + std::list> CallsListModel::getCallHistory(const QString& peerAddress, const QString& localAddress){ std::shared_ptr cleanedPeerAddress = Utils::interpretUrl(Utils::cleanSipAddress(peerAddress)); std::shared_ptr cleanedLocalAddress = Utils::interpretUrl(Utils::cleanSipAddress(localAddress)); diff --git a/linphone-app/src/components/calls/CallsListModel.hpp b/linphone-app/src/components/calls/CallsListModel.hpp index 5e5562c6e..81444a014 100644 --- a/linphone-app/src/components/calls/CallsListModel.hpp +++ b/linphone-app/src/components/calls/CallsListModel.hpp @@ -68,6 +68,13 @@ public: Q_INVOKABLE void terminateAllCalls () const; Q_INVOKABLE void terminateCall (const QString& sipAddress) const; +// Call commands + QSharedPointer getLastCall(bool incoming) const; + QSharedPointer getCallModel(const std::shared_ptr &call) const; + Q_INVOKABLE void acceptLastIncomingCall(bool video); + Q_INVOKABLE void terminateLastCall(); + Q_INVOKABLE void toggleMuteSpeaker(); + Q_INVOKABLE void toggleMuteMicrophone(); static std::list> getCallHistory(const QString& peerAddress, const QString& localAddress); diff --git a/linphone-app/src/components/settings/SettingsModel.cpp b/linphone-app/src/components/settings/SettingsModel.cpp index f7041fdf6..ef5fbbc78 100644 --- a/linphone-app/src/components/settings/SettingsModel.cpp +++ b/linphone-app/src/components/settings/SettingsModel.cpp @@ -552,6 +552,10 @@ void SettingsModel::setEchoCancellationEnabled(bool status) { void SettingsModel::startEchoCancellerCalibration() { CoreManager::getInstance()->getCore()->startEchoCancellerCalibration(); } + +int SettingsModel::getEchoCancellationCalibration()const { + return CoreManager::getInstance()->getCore()->getEchoCancellationCalibration(); +} // ----------------------------------------------------------------------------- bool SettingsModel::getShowAudioCodecs() const { @@ -2051,6 +2055,7 @@ void SettingsModel::handleCallStateChanged(const shared_ptr &, l } void SettingsModel::handleEcCalibrationResult(linphone::EcCalibratorStatus status, int delayMs) { emit echoCancellationStatus((int)status, delayMs); + emit echoCancellationCalibrationChanged(); } bool SettingsModel::getIsInCall() const { return CoreManager::getInstance()->getCore()->getCallsNb() != 0; diff --git a/linphone-app/src/components/settings/SettingsModel.hpp b/linphone-app/src/components/settings/SettingsModel.hpp index 742a33a02..2a9e035b5 100644 --- a/linphone-app/src/components/settings/SettingsModel.hpp +++ b/linphone-app/src/components/settings/SettingsModel.hpp @@ -93,10 +93,10 @@ class SettingsModel : public QObject { Q_PROPERTY(QString ringerDevice READ getRingerDevice WRITE setRingerDevice NOTIFY ringerDeviceChanged) Q_PROPERTY(QString ringPath READ getRingPath WRITE setRingPath NOTIFY ringPathChanged) - Q_PROPERTY(bool echoCancellationEnabled READ getEchoCancellationEnabled WRITE setEchoCancellationEnabled NOTIFY echoCancellationEnabledChanged) - + Q_PROPERTY( + int echoCancellationCalibration READ getEchoCancellationCalibration NOTIFY echoCancellationCalibrationChanged) Q_PROPERTY(bool showAudioCodecs READ getShowAudioCodecs WRITE setShowAudioCodecs NOTIFY showAudioCodecsChanged) // Video. -------------------------------------------------------------------- @@ -372,7 +372,7 @@ public: Q_INVOKABLE void startCaptureGraph(); Q_INVOKABLE void stopCaptureGraph(); - ; + Q_INVOKABLE void stopCaptureGraphs(); Q_INVOKABLE void resetCaptureGraph(); void createCaptureGraph(); @@ -406,6 +406,7 @@ public: bool getEchoCancellationEnabled() const; void setEchoCancellationEnabled(bool status); + int getEchoCancellationCalibration() const; Q_INVOKABLE void startEchoCancellerCalibration(); @@ -813,9 +814,9 @@ signals: void echoCancellationEnabledChanged(bool status); void echoCancellationStatus(int status, int msDelay); + void echoCancellationCalibrationChanged(); void showAudioCodecsChanged(bool status); - // Video. -------------------------------------------------------------------- void videoEnabledChanged(); void videoAvailableChanged(); diff --git a/linphone-app/ui/modules/Common/Form/MouseArea.qml b/linphone-app/ui/modules/Common/Form/MouseArea.qml index 7ded9e4c5..17ccab5e2 100644 --- a/linphone-app/ui/modules/Common/Form/MouseArea.qml +++ b/linphone-app/ui/modules/Common/Form/MouseArea.qml @@ -4,9 +4,10 @@ import Common 1.0 import Common.Styles 1.0 Quick.MouseArea { + property int hoveredCursor: Qt.PointingHandCursor property bool interactive: true - cursorShape: containsMouse && interactive - ? Qt.PointingHandCursor + cursorShape: containsMouse && interactive + ? hoveredCursor : Qt.ArrowCursor - hoverEnabled: interactive + hoverEnabled: interactive } diff --git a/linphone-app/ui/modules/Linphone/Notifications/Notification.qml b/linphone-app/ui/modules/Linphone/Notifications/Notification.qml index 5f4826395..5ae87a7f5 100644 --- a/linphone-app/ui/modules/Linphone/Notifications/Notification.qml +++ b/linphone-app/ui/modules/Linphone/Notifications/Notification.qml @@ -7,7 +7,7 @@ import Linphone.Styles 1.0 DesktopPopup { id: notification - + property bool selected: false property alias icon: iconSign.icon property var notificationData: ({ timelineModel : null @@ -35,8 +35,8 @@ DesktopPopup { width: NotificationStyle.width border { - color: NotificationStyle.border.colorModel.color - width: NotificationStyle.border.width + color: notification.selected ? NotificationStyle.selectedBorder.colorModel.color : NotificationStyle.border.colorModel.color + width: notification.selected ? NotificationStyle.selectedBorder.width : NotificationStyle.border.width } Item { diff --git a/linphone-app/ui/modules/Linphone/Notifications/NotificationReceivedCall.qml b/linphone-app/ui/modules/Linphone/Notifications/NotificationReceivedCall.qml index 30bcacd66..dfb6c368c 100644 --- a/linphone-app/ui/modules/Linphone/Notifications/NotificationReceivedCall.qml +++ b/linphone-app/ui/modules/Linphone/Notifications/NotificationReceivedCall.qml @@ -17,7 +17,15 @@ Notification { readonly property var call: notificationData && notificationData.call // --------------------------------------------------------------------------- - + + selected: focusArea.containsMouse + onSelectedChanged: { if(selected) Window.window.requestActivate()} + MouseArea{ + id: focusArea + anchors.fill: parent + acceptedButtons: Qt.NoButton + hoveredCursor: Qt.ArrowCursor + } Loader { active: Boolean(notification.call) anchors { diff --git a/linphone-app/ui/modules/Linphone/Styles/Notifications/NotificationStyle.qml b/linphone-app/ui/modules/Linphone/Styles/Notifications/NotificationStyle.qml index 001f7a0bb..b3dbb68e9 100644 --- a/linphone-app/ui/modules/Linphone/Styles/Notifications/NotificationStyle.qml +++ b/linphone-app/ui/modules/Linphone/Styles/Notifications/NotificationStyle.qml @@ -16,4 +16,8 @@ QtObject { property var colorModel: ColorsList.add(sectionName+'_border', 'n') property int width: 1 } + property QtObject selectedBorder: QtObject { + property var colorModel: ColorsList.add(sectionName+'_selected_border', 'i') + property int width: 1 + } } diff --git a/linphone-app/ui/views/App/Main/MainWindow.qml b/linphone-app/ui/views/App/Main/MainWindow.qml index fa957ea23..c65bdf0db 100644 --- a/linphone-app/ui/views/App/Main/MainWindow.qml +++ b/linphone-app/ui/views/App/Main/MainWindow.qml @@ -72,9 +72,42 @@ ApplicationWindow { } Shortcut { + context: Qt.ApplicationShortcut sequence: StandardKey.Close onActivated: window.hide() } + Shortcut { + context: Qt.ApplicationShortcut + sequence: ['Ctrl+Shift+W', 'Ctrl+Shift+V'] + onActivated: CallsListModel.acceptLastIncomingCall(true) + } + Shortcut { + context: Qt.ApplicationShortcut + sequence: 'Ctrl+Shift+A' + onActivated: CallsListModel.acceptLastIncomingCall(false) + } + Shortcut { + sequence: 'Ctrl+Shift+D' + context: Qt.ApplicationShortcut + onActivated: CallsListModel.terminateLastCall(true) + } + Shortcut { + sequence: 'Ctrl+Shift+E' + context: Qt.ApplicationShortcut + onActivated: {// startEchoCancellerCalibration is unsupported while being in call. + SettingsModel.echoCancellationEnabled = !SettingsModel.echoCancellationEnabled; + } + } + Shortcut { + sequence: 'Ctrl+Shift+L' + context: Qt.ApplicationShortcut + onActivated: CallsListModel.toggleMuteSpeaker() + } + Shortcut { + sequence: 'Ctrl+Shift+M' + context: Qt.ApplicationShortcut + onActivated: CallsListModel.toggleMuteMicrophone() + } // --------------------------------------------------------------------------- Loader { diff --git a/linphone-app/ui/views/App/Settings/SettingsAudio.qml b/linphone-app/ui/views/App/Settings/SettingsAudio.qml index 8e1d8829b..b091aa8ce 100644 --- a/linphone-app/ui/views/App/Settings/SettingsAudio.qml +++ b/linphone-app/ui/views/App/Settings/SettingsAudio.qml @@ -254,7 +254,7 @@ TabContainer { } Text{ id:echoCalibrationStatus - text: '' + text: SettingsModel.echoCancellationCalibration > 0 ? qsTr("calibratingEchoCancellationDone").replace('%1', SettingsModel.echoCancellationCalibration) : '' Layout.fillWidth:true height:parent.height verticalAlignment: Text.AlignVCenter @@ -262,7 +262,7 @@ TabContainer { } TextButtonB { id: echoCalibration - enabled: SettingsModel.echoCancellationEnabled + enabled: SettingsModel.echoCancellationEnabled && !SettingsModel.isInCall text: qsTr('echoCancellationCalibrationLabel')