mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-18 11:58:11 +00:00
Compare commits
40 commits
master
...
6.0.1-Call
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff83c1794e | ||
|
|
fd0cbdcd41 | ||
|
|
971e7a7201 | ||
|
|
480704664e | ||
|
|
e78c7d04f0 | ||
|
|
f25b4a83db | ||
|
|
b3734702cb | ||
|
|
9c3922db95 | ||
|
|
18e8d29959 | ||
|
|
e018173b5f | ||
|
|
f84280e09d | ||
|
|
cdb477853b | ||
|
|
40df729a88 | ||
|
|
9cb5758233 | ||
|
|
33b7cf62f0 | ||
|
|
ea2135d875 | ||
|
|
a649266c26 | ||
|
|
29caaf619a | ||
|
|
ea7621cf35 | ||
|
|
f6e20a9aff | ||
|
|
18ee1566f0 | ||
|
|
14a959ef57 | ||
|
|
c0ad0de987 | ||
|
|
23f5abe0f1 | ||
|
|
a3130c6067 | ||
|
|
aa871c2735 | ||
|
|
8391d438eb | ||
|
|
5ca6876e92 | ||
|
|
7490cf0ca5 | ||
|
|
76277fbe9d | ||
|
|
ca5f4411e7 | ||
|
|
e18a1f78e8 | ||
|
|
e08d5e0377 | ||
|
|
6b02ebed39 | ||
|
|
490f5cdca1 | ||
|
|
fb786c2a9d | ||
|
|
23e32d1953 | ||
|
|
d025aaaeec | ||
|
|
faeed359fb | ||
|
|
1e82f48839 |
80 changed files with 41855 additions and 2695 deletions
171
.gitlab-ci-files/linux-desktop-ubuntu-2204.yml
Normal file
171
.gitlab-ci-files/linux-desktop-ubuntu-2204.yml
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
.factorize_ubuntu2204: &docker_image_platform_and_runner_tag
|
||||
tags: [ "docker" ]
|
||||
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-22-04-lts:$UBUNTU_2204_IMAGE_VERSION
|
||||
|
||||
ubuntu2204-ninja-gcc:
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $DOCKER_UPDATE == null && $SKIP_LINUX == null
|
||||
variables:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
CMAKE_OPTIONS: -DENABLE_PQCRYPTO=ON
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
extends: .linux-desktop
|
||||
<<: *docker_image_platform_and_runner_tag
|
||||
|
||||
|
||||
#################################################
|
||||
# Nightly
|
||||
#################################################
|
||||
|
||||
ubuntu2204-makefile-gcc:
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
variables:
|
||||
CMAKE_GENERATOR: Unix Makefiles
|
||||
CMAKE_OPTIONS: -DENABLE_PQCRYPTO=ON
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
ADDITIONAL_BUILD_OPTIONS: -j$MAKEFILE_JOBS
|
||||
extends: .linux-desktop
|
||||
<<: *docker_image_platform_and_runner_tag
|
||||
|
||||
ubuntu2204-ninja-clang:
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_DOC=ON -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
|
||||
CMAKE_GENERATOR: Ninja
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
extends: .linux-desktop
|
||||
allow_failure: true
|
||||
<<: *docker_image_platform_and_runner_tag
|
||||
|
||||
ubuntu2204-ninja-clang-small:
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_VIDEO=NO -DENABLE_ADVANCED_IM=NO -DENABLE_DB_STORAGE=NO -DENABLE_PQCRYPTO=OFF
|
||||
allow_failure: true
|
||||
extends: ubuntu2204-ninja-clang
|
||||
|
||||
ubuntu2204-makefile-gcc:
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
- if: $DEPLOY_PLUGINS
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DLINPHONE_BUILDER_SIGNING_IDENTITY=$GPG_SIGNING_KEYID -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
|
||||
CMAKE_GENERATOR: Unix Makefiles
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
ADDITIONAL_BUILD_OPTIONS: -j$MAKEFILE_JOBS
|
||||
APPIMAGETOOL_SIGN_PASSPHRASE: $GPG_SIGNING_PASS
|
||||
script:
|
||||
- echo "$GPG_SIGNING_PUB" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- gpg --import file.key
|
||||
- rm -f file.key
|
||||
- echo "$GPG_SIGNING_KEY" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- base64 -w 0 file.key | base64 -d | gpg --import --no-tty --batch --yes
|
||||
- rm -f file.key
|
||||
- cmake --version
|
||||
- export CC=$CC
|
||||
- export CXX=$CXX
|
||||
- mkdir -p build/OUTPUT
|
||||
- echo $CI_BUILD_TYPE
|
||||
- echo $CMAKE_GENERATOR
|
||||
- echo $DEFAULT_LINUX_CMAKE_OPTIONS
|
||||
- echo $CMAKE_SANITIZER_OPTIONS
|
||||
- eval "$(qtchooser -qt=$QT_LINUX_VER -print-env)"
|
||||
- export PATH=${QTTOOLDIR}:$PATH
|
||||
- export Qt6_DIR=${QTLIBDIR}/cmake/Qt6
|
||||
- echo "Using Qt $QT_LINUX_VER at ${QTLIBDIR}"
|
||||
- cd build
|
||||
- cmake .. -G "$CMAKE_GENERATOR" -DCMAKE_VERBOSE_MAKEFILE=ON -DLINPHONESDK_PLATFORM=Desktop -DCMAKE_BUILD_TYPE=$CI_BUILD_TYPE -DLINPHONEAPP_APPLICATION_NAME="$APPLICATION_NAME" -DLINPHONEAPP_EXECUABLE_NAME="$EXECUTABLE_NAME" $DEFAULT_LINUX_CMAKE_OPTIONS $CMAKE_OPTIONS $SCHEDULE_CMAKE_OPTIONS $CMAKE_SANITIZER_OPTIONS
|
||||
- cmake --build . --target install --config $CI_BUILD_TYPE $LBC_NODEBUG_OPTIONS
|
||||
extends: .linux-desktop
|
||||
<<: *docker_image_platform_and_runner_tag
|
||||
|
||||
#################################################
|
||||
# Package - Nightly
|
||||
#################################################
|
||||
|
||||
ubuntu2204-makefile-gcc-package:
|
||||
stage: package
|
||||
tags: [ "docker" ]
|
||||
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-22-04-lts:$UBUNTU_2204_IMAGE_VERSION
|
||||
dependencies: []
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
- if: $PACKAGE_LINUX
|
||||
- if: $DEPLOY_LINUX
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DLINPHONE_BUILDER_SIGNING_IDENTITY=$GPG_SIGNING_KEYID -DENABLE_G729=ON -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$LINUX_PLATFORM/$APP_FOLDER -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
|
||||
CMAKE_GENERATOR: Unix Makefiles
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
APPIMAGETOOL_SIGN_PASSPHRASE: $GPG_SIGNING_PASS
|
||||
extends: .linux-desktop
|
||||
script:
|
||||
- echo "$GPG_SIGNING_PUB" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- gpg --import file.key
|
||||
- rm -f file.key
|
||||
- echo "$GPG_SIGNING_KEY" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- base64 -w 0 file.key | base64 -d | gpg --import --no-tty --batch --yes
|
||||
- rm -f file.key
|
||||
- cmake --version
|
||||
- export CC=$CC
|
||||
- export CXX=$CXX
|
||||
- mkdir -p build/OUTPUT
|
||||
- echo $CI_BUILD_TYPE
|
||||
- echo $CMAKE_GENERATOR
|
||||
- echo $DEFAULT_LINUX_CMAKE_OPTIONS
|
||||
- echo $CMAKE_SANITIZER_OPTIONS
|
||||
- eval "$(qtchooser -qt=$QT_LINUX_VER -print-env)"
|
||||
- export PATH=${QTTOOLDIR}:$PATH
|
||||
- cd build
|
||||
- cmake .. -G "$CMAKE_GENERATOR" -DCMAKE_VERBOSE_MAKEFILE=ON -DLINPHONESDK_PLATFORM=Desktop -DCMAKE_BUILD_TYPE=$CI_BUILD_TYPE -DLINPHONEAPP_APPLICATION_NAME="$APPLICATION_NAME" -DLINPHONEAPP_EXECUTABLE_NAME="$EXECUTABLE_NAME" $DEFAULT_LINUX_CMAKE_OPTIONS $CMAKE_OPTIONS $SCHEDULE_CMAKE_OPTIONS $CMAKE_SANITIZER_OPTIONS
|
||||
- cmake --build . --target install --config $CI_BUILD_TYPE $LBC_NODEBUG_OPTIONS
|
||||
artifacts:
|
||||
paths:
|
||||
- build/OUTPUT/*
|
||||
expire_in: 1 week
|
||||
|
||||
#################################################
|
||||
# Deploy - Nightly
|
||||
#################################################
|
||||
|
||||
ubuntu2204-makefile-gcc-deploy:
|
||||
stage: deploy
|
||||
tags: [ "deploy" ]
|
||||
needs:
|
||||
- ubuntu2204-makefile-gcc-package
|
||||
only:
|
||||
variables:
|
||||
- $NIGHTLY_MASTER
|
||||
- $DEPLOY_LINUX
|
||||
script:
|
||||
- rsync -rlv --ignore-existing build/OUTPUT/Packages/*.AppImage $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM/$APP_FOLDER
|
||||
- |-
|
||||
if [[ $MAKE_RELEASE_FILE_URL != "" ]]; then
|
||||
rsync -rlv build/OUTPUT/Packages/RELEASE $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM
|
||||
rsync -rlv build/OUTPUT/Packages/RELEASE $MAIN_DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM
|
||||
fi
|
||||
|
||||
|
||||
ubuntu2204-makefile-gcc-plugins-deploy:
|
||||
stage: deploy
|
||||
tags: [ "deploy" ]
|
||||
needs:
|
||||
- ubuntu2204-makefile-gcc
|
||||
only:
|
||||
variables:
|
||||
- $DEPLOY_PLUGINS
|
||||
script:
|
||||
- rsync -rlv --ignore-existing build/OUTPUT/plugins/app/*.so $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM/$APP_FOLDER/plugins/
|
||||
|
||||
|
|
@ -204,6 +204,7 @@ win64-ninja-vs2022-package-windows:
|
|||
|
||||
win64-codesigning:
|
||||
stage: signing
|
||||
allow_failure: true
|
||||
extends:
|
||||
- .windows-codesigning
|
||||
needs:
|
||||
|
|
@ -218,6 +219,7 @@ win64-codesigning:
|
|||
script:
|
||||
- cd build-desktop/OUTPUT/Packages/
|
||||
- Invoke-Expression "& ${WINDOWS_SIGN_TOOL} sign /fd SHA256 /t ${WINDOWS_SIGN_TIMESTAMP_URL} /sha1 ${WINDOWS_SIGN_HASH} *.exe"
|
||||
- 'if (-not ($LastExitCode -eq 0)) {throw "Error: Signature failed"}'
|
||||
artifacts:
|
||||
paths:
|
||||
- build-desktop\OUTPUT\Packages\*
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ variables:
|
|||
DEBIAN_10_IMAGE_VERSION: 20210217_python3
|
||||
UBUNTU_ROLLING_IMAGE_VERSION: 20211012_add_qtwebview
|
||||
UBUNTU_2004_IMAGE_VERSION: 20250226_qt6-8-0
|
||||
UBUNTU_2204_IMAGE_VERSION: 20250630_add-qtshadertools
|
||||
|
||||
|
||||
workflow:
|
||||
|
|
@ -50,7 +51,8 @@ include:
|
|||
- '.gitlab-ci-files/rules.yml'
|
||||
- '.gitlab-ci-files/linux-prepare.yml'
|
||||
- '.gitlab-ci-files/linux-desktop.yml'
|
||||
- '.gitlab-ci-files/linux-desktop-ubuntu-2004.yml'
|
||||
# - '.gitlab-ci-files/linux-desktop-ubuntu-2004.yml'
|
||||
- '.gitlab-ci-files/linux-desktop-ubuntu-2204.yml'
|
||||
- '.gitlab-ci-files/windows-desktop.yml'
|
||||
- '.gitlab-ci-files/macosx-desktop.yml'
|
||||
|
||||
|
|
|
|||
45
CHANGELOG.md
Normal file
45
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Change Log
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
Group changes to describe their impact on the project, as follows:
|
||||
|
||||
Added for new features.
|
||||
Changed for changes in existing functionality.
|
||||
Deprecated for once-stable features removed in upcoming releases.
|
||||
Removed for deprecated features removed in this release.
|
||||
Fixed for any bug fixes.
|
||||
Security to invite users to upgrade in case of vulnerabilities.
|
||||
|
||||
## [6.0.1] - 2025-09-08
|
||||
|
||||
### Changed
|
||||
- SDK updated to 5.4.42 release
|
||||
- Updated translations from Weblate
|
||||
|
||||
### Fixed
|
||||
- Various issues related to OpenID connect
|
||||
- Wrong thread issue for remote provisioning
|
||||
- Other UI related fixes
|
||||
|
||||
## [6.0.0] - 2025-05-16
|
||||
|
||||
6.0.0 release is a complete rework of Linphone Desktop, with only the call and contact list features availables.
|
||||
Disclaimer: this release is focused on calls, meetings/conferences are available but aren't stable yet and chat features are missing.
|
||||
|
||||
### Added
|
||||
- Contacts trust: contacts for which all devices have been validated through a ZRTP call with SAS exchange are now highlighted with a blue circle (and with a red one in case of mistrust). That trust is now handled at contact level (instead of conversation level in previous versions).
|
||||
- Security focus: security & trust is more visible than ever, and unsecure conversations & calls are even more visible than before.
|
||||
- CardDAV: you can configure as many CardDAV servers you want to synchronize you contacts in Linphone (in addition or in replacement of native addressbook import).
|
||||
- OpenID: when used with a SSO compliant SIP server (such as Flexisip), we support single-sign-on login.
|
||||
- MWI support: display and allow to call your voicemail when you have new messages (if supported by your VoIP provider and properly configured in your account params).
|
||||
- CCMP support: if you configure a CCMP server URL in your accounts params, it will be used when scheduling meetings & to fetch list of meetings you've organized/been invited to.
|
||||
- Devices list: check on which device your sip.linphone.org account is connected and the last connection date & time (like on subscribe.linphone.org).
|
||||
|
||||
### Changed
|
||||
- Separated threads: Contrary to previous versions, our SDK is now running in it's own thread, meaning it won't freeze the UI anymore in case of heavy work, thus reducing the number of ANR and greatly increasing the fluidity of the app.
|
||||
- Asymmetrical video : you no longer need to send your own camera feed to receive the one from the remote end of the call, and vice versa.
|
||||
- Call transfer: Blind & Attended call transfer have been merged into one: during a call, if you initiate a transfer action, either pick another call to do the attended transfer or select a contact from the list (you can input a SIP URI not already in the suggestions list) to start a blind transfer.
|
||||
- Settings: a lot of them are gone, the one that are still there have been reworked to increase user friendliness.
|
||||
- Default screen (between contacts, call history, conversations & meetings list) will change depending on where you were when the app was paused or killed, and you will return to that last visited screen on the next startup.
|
||||
- Minimum supported Qt version is now 6.5.3
|
||||
- Some settings have changed name and/or section in linphonerc file.
|
||||
|
|
@ -93,6 +93,12 @@
|
|||
#include "tool/request/RequestDialog.hpp"
|
||||
#include "tool/thread/Thread.hpp"
|
||||
|
||||
#if defined(Q_OS_MACOS)
|
||||
#include "core/event-count-notifier/EventCountNotifierMacOs.hpp"
|
||||
#else
|
||||
#include "core/event-count-notifier/EventCountNotifierSystemTrayIcon.hpp"
|
||||
#endif // if defined(Q_OS_MACOS)
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(App)
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
|
|
@ -259,10 +265,11 @@ void App::setAutoStart(bool enabled) {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
App::App(int &argc, char *argv[])
|
||||
: SingleApplication(argc, argv, true, Mode::User | Mode::ExcludeAppPath | Mode::ExcludeAppVersion) {
|
||||
: SingleApplication(argc, argv, true, Mode::User | Mode::ExcludeAppPath | Mode::ExcludeAppVersion) {
|
||||
// Do not use APPLICATION_NAME here.
|
||||
// The EXECUTABLE_NAME will be used in qt standard paths. It's our goal.
|
||||
QThread::currentThread()->setPriority(QThread::HighPriority);
|
||||
qDebug() << "app thread is" << QThread::currentThread();
|
||||
QCoreApplication::setApplicationName(EXECUTABLE_NAME);
|
||||
QApplication::setOrganizationDomain(EXECUTABLE_NAME);
|
||||
QCoreApplication::setApplicationVersion(APPLICATION_SEMVER);
|
||||
|
|
@ -291,6 +298,7 @@ App::App(int &argc, char *argv[])
|
|||
emit currentDateChanged();
|
||||
}
|
||||
});
|
||||
mEventCountNotifier = new EventCountNotifier(this);
|
||||
mDateUpdateTimer.start();
|
||||
}
|
||||
|
||||
|
|
@ -355,6 +363,50 @@ void App::setSelf(QSharedPointer<App>(me)) {
|
|||
auto state = CoreModel::getInstance()->getCore()->getGlobalState();
|
||||
mCoreModelConnection->invokeToCore([this, state] { setCoreStarted(state == linphone::GlobalState::On); });
|
||||
});
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::accountAdded,
|
||||
[this](const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
qDebug() << "account added";
|
||||
if (CoreModel::getInstance()->mConfigStatus == linphone::ConfiguringState::Successful) {
|
||||
qDebug() << "remote prov finished";
|
||||
bool accountConnected = account && account->getState() == linphone::RegistrationState::Ok;
|
||||
mCoreModelConnection->invokeToCore([this, accountConnected]() {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
// There is an account added by a remote provisioning, force switching to main page
|
||||
// because the account may not be connected already
|
||||
QMetaObject::invokeMethod(mMainWindow, "openMainPage", Qt::DirectConnection,
|
||||
Q_ARG(QVariant, accountConnected));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::unreadNotificationsChanged, [this] {
|
||||
int n = mEventCountNotifier->getCurrentEventCount();
|
||||
mCoreModelConnection->invokeToCore([this, n] { mEventCountNotifier->notifyEventCount(n); });
|
||||
});
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::defaultAccountChanged, [this] {
|
||||
int n = mEventCountNotifier->getCurrentEventCount();
|
||||
mCoreModelConnection->invokeToCore([this, n] { mEventCountNotifier->notifyEventCount(n); });
|
||||
});
|
||||
|
||||
// Config error message
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::configuringStatus, [this](const std::shared_ptr<linphone::Core> &core,
|
||||
linphone::ConfiguringState status, const std::string &message) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
if (status == linphone::ConfiguringState::Failed) {
|
||||
mCoreModelConnection->invokeToCore([this, message]() {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
//: Error
|
||||
Utils::showInformationPopup(
|
||||
tr("info_popup_error_title"),
|
||||
tr("info_popup_configuration_failed_message").arg(Utils::coreStringToAppString(message)),
|
||||
false);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mCliModelConnection = SafeConnection<App, CliModel>::create(me, CliModel::getInstance());
|
||||
mCliModelConnection->makeConnectToCore(&App::receivedMessage, [this](int, const QByteArray &byteArray) {
|
||||
|
|
@ -383,6 +435,15 @@ QThread *App::getLinphoneThread() {
|
|||
Notifier *App::getNotifier() const {
|
||||
return mNotifier;
|
||||
}
|
||||
|
||||
EventCountNotifier *App::getEventCountNotifier() {
|
||||
return mEventCountNotifier;
|
||||
}
|
||||
|
||||
int App::getEventCount() const {
|
||||
return mEventCountNotifier ? mEventCountNotifier->getEventCount() : 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// Initializations
|
||||
//-----------------------------------------------------------
|
||||
|
|
@ -426,6 +487,7 @@ void App::initCore() {
|
|||
CoreModel::create("", mLinphoneThread);
|
||||
if (mParser->isSet("verbose")) QtLogger::enableVerbose(true);
|
||||
if (mParser->isSet("qt-logs-only")) QtLogger::enableQtOnly(true);
|
||||
|
||||
QMetaObject::invokeMethod(
|
||||
mLinphoneThread->getThreadId(),
|
||||
[this, settings = mSettings]() mutable {
|
||||
|
|
@ -522,7 +584,7 @@ void App::initCore() {
|
|||
setLocale(settings->getConfigLocale());
|
||||
setAutoStart(settings->getAutoStart());
|
||||
setQuitOnLastWindowClosed(settings->getExitOnClose());
|
||||
}
|
||||
}
|
||||
const QUrl url("qrc:/qt/qml/Linphone/view/Page/Window/Main/MainWindow.qml");
|
||||
QObject::connect(
|
||||
mEngine, &QQmlApplicationEngine::objectCreated, this,
|
||||
|
|
@ -546,6 +608,20 @@ void App::initCore() {
|
|||
window->show();
|
||||
} else lInfo() << log().arg("Stay minimized");
|
||||
firstOpen = false;
|
||||
lInfo() << log().arg("Checking remote provisioning");
|
||||
if (CoreModel::getInstance()->mConfigStatus == linphone::ConfiguringState::Failed) {
|
||||
QMetaObject::invokeMethod(thread(), [this]() {
|
||||
auto message = CoreModel::getInstance()->mConfigMessage;
|
||||
//: not reachable
|
||||
if (message.isEmpty()) message = tr("configuration_error_detail");
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
//: Error
|
||||
Utils::showInformationPopup(
|
||||
tr("info_popup_error_title"),
|
||||
//: Remote provisioning failed : %1
|
||||
tr("info_popup_configuration_failed_message").arg(message), false);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
|
@ -565,7 +641,6 @@ static inline bool installLocale(App &app, QTranslator &translator, const QLocal
|
|||
}
|
||||
|
||||
void App::initLocale() {
|
||||
|
||||
// Try to use preferred locale.
|
||||
QString locale;
|
||||
|
||||
|
|
@ -573,28 +648,28 @@ void App::initLocale() {
|
|||
mLocale = QLocale(QLocale::English);
|
||||
if (!installLocale(*this, *mDefaultTranslatorCore, mLocale)) qFatal("Unable to install default translator.");
|
||||
|
||||
// if (installLocale(*this, *mTranslatorCore, getLocale())) {
|
||||
// qDebug() << "installed locale" << getLocale().name();
|
||||
// return;
|
||||
// }
|
||||
// if (installLocale(*this, *mTranslatorCore, getLocale())) {
|
||||
// qDebug() << "installed locale" << getLocale().name();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Try to use system locale.
|
||||
// #ifdef Q_OS_MACOS
|
||||
// Use this workaround if there is still an issue about detecting wrong language from system on Mac. Qt doesn't use
|
||||
// the current system language on QLocale::system(). So we need to get it from user settings and overwrite its
|
||||
// Locale.
|
||||
// QSettings settings;
|
||||
// QString preferredLanguage = settings.value("AppleLanguages").toStringList().first();
|
||||
// QStringList qtLocale = QLocale::system().name().split('_');
|
||||
// if(qtLocale[0] != preferredLanguage){
|
||||
// qInfo() << "Override Qt language from " << qtLocale[0] << " to the preferred language : " <<
|
||||
// preferredLanguage; qtLocale[0] = preferredLanguage;
|
||||
// }
|
||||
// QLocale sysLocale = QLocale(qtLocale.join('_'));
|
||||
// #else
|
||||
QLocale sysLocale(QLocale::system().name()); // Use Locale from name because Qt has a bug where it didn't use the
|
||||
// QLocale::language (aka : translator.language != locale.language) on
|
||||
// Mac. #endif
|
||||
// Try to use system locale.
|
||||
// #ifdef Q_OS_MACOS
|
||||
// Use this workaround if there is still an issue about detecting wrong language from system on Mac. Qt doesn't
|
||||
// use the current system language on QLocale::system(). So we need to get it from user settings and overwrite
|
||||
// its Locale.
|
||||
// QSettings settings;
|
||||
// QString preferredLanguage = settings.value("AppleLanguages").toStringList().first();
|
||||
// QStringList qtLocale = QLocale::system().name().split('_');
|
||||
// if(qtLocale[0] != preferredLanguage){
|
||||
// qInfo() << "Override Qt language from " << qtLocale[0] << " to the preferred language : " <<
|
||||
// preferredLanguage; qtLocale[0] = preferredLanguage;
|
||||
// }
|
||||
// QLocale sysLocale = QLocale(qtLocale.join('_'));
|
||||
// #else
|
||||
QLocale sysLocale(QLocale::system().name()); // Use Locale from name because Qt has a bug where it didn't use
|
||||
// the QLocale::language (aka : translator.language !=
|
||||
// locale.language) on Mac. #endif
|
||||
if (installLocale(*this, *mTranslatorCore, sysLocale)) {
|
||||
qDebug() << "installed sys locale" << sysLocale.name();
|
||||
setLocale(sysLocale.name());
|
||||
|
|
@ -775,34 +850,37 @@ void App::createCommandParser() {
|
|||
//: "A free and open source SIP video-phone."
|
||||
mParser->setApplicationDescription(tr("application_description"));
|
||||
//: "Send an order to the application towards a command line"
|
||||
mParser->addPositionalArgument("command", tr("command_line_arg_order").replace("%1", APPLICATION_NAME), "[command]");
|
||||
mParser->addPositionalArgument("command", tr("command_line_arg_order").replace("%1", APPLICATION_NAME),
|
||||
"[command]");
|
||||
mParser->addOptions({
|
||||
//: "Show this help"
|
||||
{{"h", "help"}, tr("command_line_option_show_help")},
|
||||
//: "Show this help"
|
||||
{{"h", "help"}, tr("command_line_option_show_help")},
|
||||
|
||||
//{"cli-help", tr("commandLineOptionCliHelp").replace("%1", APPLICATION_NAME)},
|
||||
|
||||
//:"Show app version"
|
||||
{{"v", "version"}, tr("command_line_option_show_app_version")},
|
||||
//:"Show app version"
|
||||
{{"v", "version"}, tr("command_line_option_show_app_version")},
|
||||
|
||||
//{"config", tr("command_line_option_config").replace("%1", EXECUTABLE_NAME), tr("command_line_option_config_arg")},
|
||||
//{"config", tr("command_line_option_config").replace("%1", EXECUTABLE_NAME),
|
||||
// tr("command_line_option_config_arg")},
|
||||
|
||||
{"fetch-config",
|
||||
//: "Specify the linphone configuration file to be fetched. It will be merged with the current configuration."
|
||||
tr("command_line_option_config_to_fetch")
|
||||
.replace("%1", EXECUTABLE_NAME),
|
||||
//: "URL, path or file"
|
||||
tr("command_line_option_config_to_fetch_arg")},
|
||||
//: "Specify the linphone configuration file to be fetched. It will be merged with the current
|
||||
//: configuration."
|
||||
tr("command_line_option_config_to_fetch").replace("%1", EXECUTABLE_NAME),
|
||||
//: "URL, path or file"
|
||||
tr("command_line_option_config_to_fetch_arg")},
|
||||
|
||||
//{{"c", "call"}, tr("command_line_option_call").replace("%1", EXECUTABLE_NAME), tr("command_line_option_call_arg")},
|
||||
//{{"c", "call"}, tr("command_line_option_call").replace("%1", EXECUTABLE_NAME),
|
||||
// tr("command_line_option_call_arg")},
|
||||
|
||||
{"minimized", tr("command_line_option_minimized")},
|
||||
{"minimized", tr("command_line_option_minimized")},
|
||||
|
||||
//: "Log to stdout some debug information while running"
|
||||
{{"V", "verbose"}, tr("command_line_option_log_to_stdout")},
|
||||
//: "Log to stdout some debug information while running"
|
||||
{{"V", "verbose"}, tr("command_line_option_log_to_stdout")},
|
||||
|
||||
//: "Print only logs from the application"
|
||||
{"qt-logs-only", tr("command_line_option_print_app_logs_only")},
|
||||
//: "Print only logs from the application"
|
||||
{"qt-logs-only", tr("command_line_option_print_app_logs_only")},
|
||||
});
|
||||
}
|
||||
// Should be call only at first start
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ public:
|
|||
static QThread *getLinphoneThread();
|
||||
Notifier *getNotifier() const;
|
||||
|
||||
EventCountNotifier *getEventCountNotifier();
|
||||
int getEventCount() const;
|
||||
|
||||
// App::postModelAsync(<lambda>) => run lambda in model thread and continue.
|
||||
// App::postModelSync(<lambda>) => run lambda in current thread and block connection.
|
||||
template <typename Func, typename... Args>
|
||||
|
|
@ -119,6 +122,10 @@ public:
|
|||
void restart();
|
||||
bool autoStartEnabled();
|
||||
void setSysTrayIcon();
|
||||
QSystemTrayIcon *getSystemTrayIcon() const {
|
||||
return mSystemTrayIcon;
|
||||
}
|
||||
void updateSysTrayCount(int n);
|
||||
QLocale getLocale();
|
||||
|
||||
void onLoggerInitialized();
|
||||
|
|
@ -184,6 +191,7 @@ private:
|
|||
QCommandLineParser *mParser = nullptr;
|
||||
Thread *mLinphoneThread = nullptr;
|
||||
Notifier *mNotifier = nullptr;
|
||||
EventCountNotifier *mEventCountNotifier = nullptr;
|
||||
QSystemTrayIcon *mSystemTrayIcon = nullptr;
|
||||
QQuickWindow *mMainWindow = nullptr;
|
||||
QQuickWindow *mCallsWindow = nullptr;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
core/camera/CameraGui.cpp
|
||||
core/camera/CameraDummy.cpp
|
||||
core/camera/PreviewManager.cpp
|
||||
core/event-count-notifier/AbstractEventCountNotifier.cpp
|
||||
core/fps-counter/FPSCounter.cpp
|
||||
core/friend/FriendCore.cpp
|
||||
core/friend/FriendGui.cpp
|
||||
|
|
@ -99,5 +100,9 @@ else() # Use QDBus for Linux
|
|||
core/singleapplication/SingleApplicationDBusPrivate.hpp
|
||||
core/singleapplication/SingleApplicationDBus.cpp)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND _LINPHONEAPP_SOURCES core/event-count-notifier/EventCountNotifierMacOs.m)
|
||||
else()
|
||||
list(APPEND _LINPHONEAPP_SOURCES core/event-count-notifier/EventCountNotifierSystemTrayIcon.cpp)
|
||||
endif()
|
||||
set(_LINPHONEAPP_SOURCES ${_LINPHONEAPP_SOURCES} PARENT_SCOPE)
|
||||
|
|
|
|||
|
|
@ -83,8 +83,19 @@ void AccountDeviceList::refreshDevices() {
|
|||
auto requestDeviceList = [this] {
|
||||
if (!mAccountManagerServicesModelConnection) return;
|
||||
mAccountManagerServicesModelConnection->invokeToModel([this]() {
|
||||
auto connectedAccounts = CoreModel::getInstance()->getCore()->getAccountList();
|
||||
auto identityAddress = mAccountCore->getModel()->getMonitor()->getParams()->getIdentityAddress();
|
||||
auto authinfo = mAccountCore->getModel()->getMonitor()->findAuthInfo();
|
||||
auto found = std::find_if(connectedAccounts.begin(), connectedAccounts.end(),
|
||||
[identityAddress](std::shared_ptr<linphone::Account> account) {
|
||||
return account && account->getParams()->getIdentityAddress()->weakEqual(
|
||||
identityAddress);
|
||||
});
|
||||
if (found == connectedAccounts.end()) {
|
||||
qDebug() << "[AccountDeviceList] account" << identityAddress->asStringUriOnly()
|
||||
<< "not connected anymore, return";
|
||||
return;
|
||||
}
|
||||
// auto authinfo = mAccountCore->getModel()->getMonitor()->findAuthInfo();
|
||||
qDebug() << "[AccountDeviceList] request devices for address" << identityAddress->asStringUriOnly();
|
||||
mAccountManagerServicesModel->getDeviceList(identityAddress);
|
||||
});
|
||||
|
|
@ -150,14 +161,14 @@ void AccountDeviceList::setSelf(QSharedPointer<AccountDeviceList> me) {
|
|||
&AccountManagerServicesModel::requestError,
|
||||
[this](const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request, int statusCode,
|
||||
const std::string &errorMessage,
|
||||
const std::shared_ptr<const linphone::Dictionary> ¶meterErrors) {
|
||||
lDebug() << "REQUEST ERROR" << errorMessage << "/" << int(request->getType());
|
||||
QString message = QString::fromStdString(errorMessage);
|
||||
if (request->getType() == linphone::AccountManagerServicesRequest::Type::GetDevicesList) {
|
||||
//: "Erreur lors de la récupération des appareils"
|
||||
message = tr("manage_account_no_device_found_error_message");
|
||||
}
|
||||
emit requestError(message);
|
||||
const std::shared_ptr<const linphone::Dictionary> ¶meterErrors) {
|
||||
lDebug() << "REQUEST ERROR" << errorMessage << "/" << int(request->getType());
|
||||
QString message = QString::fromStdString(errorMessage);
|
||||
if (request->getType() == linphone::AccountManagerServicesRequest::Type::GetDevicesList) {
|
||||
//: "Erreur lors de la récupération des appareils"
|
||||
message = tr("manage_account_no_device_found_error_message");
|
||||
}
|
||||
emit requestError(message);
|
||||
});
|
||||
mAccountManagerServicesModelConnection->makeConnectToModel(
|
||||
&AccountManagerServicesModel::devicesListFetched,
|
||||
|
|
|
|||
|
|
@ -107,8 +107,6 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
|
|||
mCallModel->setSelf(mCallModel);
|
||||
mDuration = call->getDuration();
|
||||
mIsStarted = mDuration > 0;
|
||||
mMicrophoneMuted = call->getMicrophoneMuted();
|
||||
mSpeakerMuted = call->getSpeakerMuted();
|
||||
auto videoDirection = call->getParams()->getVideoDirection();
|
||||
mLocalVideoEnabled =
|
||||
videoDirection == linphone::MediaDirection::SendOnly || videoDirection == linphone::MediaDirection::SendRecv;
|
||||
|
|
@ -158,6 +156,8 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
|
|||
if (mIsConference) {
|
||||
mConference = ConferenceCore::create(conference);
|
||||
}
|
||||
mMicrophoneMuted = conference ? conference->getMicrophoneMuted() : call->getMicrophoneMuted();
|
||||
mSpeakerMuted = call->getSpeakerMuted();
|
||||
mPaused = mState == LinphoneEnums::CallState::Pausing || mState == LinphoneEnums::CallState::Paused ||
|
||||
mState == LinphoneEnums::CallState::PausedByRemote;
|
||||
|
||||
|
|
@ -208,10 +208,11 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
mCallModelConnection->invokeToCore([this, recording]() {
|
||||
setRecording(recording);
|
||||
if (recording == false) {
|
||||
//: "Enregistrement terminé"
|
||||
Utils::showInformationPopup(tr("call_record_end_message"),
|
||||
//: "L'appel a été enregistré dans le fichier : %1"
|
||||
tr("call_record_saved_in_file_message").arg(QString::fromStdString(mCallModel->getRecordFile())),
|
||||
//: "Enregistrement terminé"
|
||||
Utils::showInformationPopup(tr("call_record_end_message"),
|
||||
//: "L'appel a été enregistré dans le fichier : %1"
|
||||
tr("call_record_saved_in_file_message")
|
||||
.arg(QString::fromStdString(mCallModel->getRecordFile())),
|
||||
true, App::getInstance()->getCallsWindow());
|
||||
}
|
||||
});
|
||||
|
|
@ -308,8 +309,8 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
[this, call, encryption, tokenVerified, localToken, remoteTokens, isCaseMismatch]() {
|
||||
setLocalToken(localToken);
|
||||
setRemoteTokens(remoteTokens);
|
||||
setIsMismatch(isCaseMismatch);
|
||||
setTokenVerified(tokenVerified);
|
||||
setIsMismatch(isCaseMismatch);
|
||||
setTokenVerified(tokenVerified);
|
||||
setEncryption(encryption);
|
||||
});
|
||||
auto mediaEncryption = call->getParams()->getMediaEncryption();
|
||||
|
|
@ -321,7 +322,7 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
zrtpStats.mHashAlgorithm = Utils::coreStringToAppString(stats->getZrtpHashAlgo());
|
||||
zrtpStats.mAuthenticationAlgorithm = Utils::coreStringToAppString(stats->getZrtpAuthTagAlgo());
|
||||
zrtpStats.mSasAlgorithm = Utils::coreStringToAppString(stats->getZrtpSasAlgo());
|
||||
zrtpStats.mIsPostQuantum = stats->isZrtpKeyAgreementAlgoPostQuantum();
|
||||
zrtpStats.mIsPostQuantum = stats->isZrtpKeyAgreementAlgoPostQuantum();
|
||||
mCallModelConnection->invokeToCore([this, zrtpStats]() { setZrtpStats(zrtpStats); });
|
||||
}
|
||||
});
|
||||
|
|
@ -388,23 +389,23 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
auto codecType = playloadType ? playloadType->getMimeType() : "";
|
||||
auto codecRate = playloadType ? playloadType->getClockRate() / 1000 : 0;
|
||||
audioStats.mCodec =
|
||||
//: "Codec: %1 / %2 kHz"
|
||||
tr("call_stats_codec_label").arg(Utils::coreStringToAppString(codecType)).arg(codecRate);
|
||||
//: "Codec: %1 / %2 kHz"
|
||||
tr("call_stats_codec_label").arg(Utils::coreStringToAppString(codecType)).arg(codecRate);
|
||||
auto linAudioStats = call->getAudioStats();
|
||||
if (linAudioStats) {
|
||||
//: "Bande passante : %1 %2 kbits/s %3 %4 kbits/s"
|
||||
audioStats.mBandwidth = tr("call_stats_bandwidth_label")
|
||||
//: "Bande passante : %1 %2 kbits/s %3 %4 kbits/s"
|
||||
audioStats.mBandwidth = tr("call_stats_bandwidth_label")
|
||||
.arg("↑")
|
||||
.arg(round(linAudioStats->getUploadBandwidth()))
|
||||
.arg("↓")
|
||||
.arg(round(linAudioStats->getDownloadBandwidth()));
|
||||
//: "Taux de perte: %1% %2%"
|
||||
audioStats.mLossRate = tr("call_stats_loss_rate_label")
|
||||
//: "Taux de perte: %1% %2%"
|
||||
audioStats.mLossRate = tr("call_stats_loss_rate_label")
|
||||
.arg(linAudioStats->getSenderLossRate())
|
||||
.arg(linAudioStats->getReceiverLossRate());
|
||||
//: "Tampon de gigue: %1 ms"
|
||||
audioStats.mJitterBufferSize =
|
||||
tr("call_stats_jitter_buffer_label").arg(linAudioStats->getJitterBufferSizeMs());
|
||||
//: "Tampon de gigue: %1 ms"
|
||||
audioStats.mJitterBufferSize =
|
||||
tr("call_stats_jitter_buffer_label").arg(linAudioStats->getJitterBufferSizeMs());
|
||||
}
|
||||
setAudioStats(audioStats);
|
||||
} else if (stats->getType() == linphone::StreamType::Video) {
|
||||
|
|
@ -414,15 +415,15 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
auto codecType = playloadType ? playloadType->getMimeType() : "";
|
||||
auto codecRate = playloadType ? playloadType->getClockRate() / 1000 : 0;
|
||||
videoStats.mCodec =
|
||||
tr("call_stats_codec_label").arg(Utils::coreStringToAppString(codecType)).arg(codecRate);
|
||||
tr("call_stats_codec_label").arg(Utils::coreStringToAppString(codecType)).arg(codecRate);
|
||||
auto linVideoStats = call->getVideoStats();
|
||||
if (stats) {
|
||||
videoStats.mBandwidth = tr("call_stats_bandwidth_label")
|
||||
videoStats.mBandwidth = tr("call_stats_bandwidth_label")
|
||||
.arg("↑")
|
||||
.arg(round(linVideoStats->getUploadBandwidth()))
|
||||
.arg("↓")
|
||||
.arg(round(linVideoStats->getDownloadBandwidth()));
|
||||
videoStats.mLossRate = tr("call_stats_loss_rate_label")
|
||||
videoStats.mLossRate = tr("call_stats_loss_rate_label")
|
||||
.arg(linVideoStats->getSenderLossRate())
|
||||
.arg(linVideoStats->getReceiverLossRate());
|
||||
}
|
||||
|
|
@ -430,14 +431,14 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
params->getSentVideoDefinition() ? params->getSentVideoDefinition()->getName() : "";
|
||||
auto receivedResolution =
|
||||
params->getReceivedVideoDefinition() ? params->getReceivedVideoDefinition()->getName() : "";
|
||||
//: "Définition vidéo : %1 %2 %3 %4"
|
||||
videoStats.mResolution = tr("call_stats_resolution_label")
|
||||
//: "Définition vidéo : %1 %2 %3 %4"
|
||||
videoStats.mResolution = tr("call_stats_resolution_label")
|
||||
.arg("↑", Utils::coreStringToAppString(sentResolution), "↓",
|
||||
Utils::coreStringToAppString(receivedResolution));
|
||||
auto sentFps = params->getSentFramerate();
|
||||
auto receivedFps = params->getReceivedFramerate();
|
||||
//: "FPS : %1 %2 %3 %4"
|
||||
videoStats.mFps = tr("call_stats_fps_label").arg("↑").arg(sentFps).arg("↓").arg(receivedFps);
|
||||
//: "FPS : %1 %2 %3 %4"
|
||||
videoStats.mFps = tr("call_stats_fps_label").arg("↑").arg(sentFps).arg("↓").arg(receivedFps);
|
||||
setVideoStats(videoStats);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -198,15 +198,6 @@ void ConferenceInfoCore::setSelf(QSharedPointer<ConferenceInfoCore> me) {
|
|||
uri] {
|
||||
setConferenceSchedulerState(state);
|
||||
setConferenceInfoState(infoState);
|
||||
if (state == LinphoneEnums::ConferenceSchedulerState::Ready) {
|
||||
setUri(uri);
|
||||
mConfInfoModelConnection->invokeToModel([this, uri, infoState] {
|
||||
if (infoState == LinphoneEnums::ConferenceInfoState::New)
|
||||
emit CoreModel::getInstance()->conferenceInfoCreated(
|
||||
mConferenceInfoModel->getConferenceInfo());
|
||||
});
|
||||
}
|
||||
setConferenceSchedulerState(state);
|
||||
});
|
||||
});
|
||||
mConfInfoModelConnection->makeConnectToModel(
|
||||
|
|
|
|||
|
|
@ -99,9 +99,6 @@ void ConferenceInfoList::setSelf(QSharedPointer<ConferenceInfoList> me) {
|
|||
// conference (which must hidden)
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::defaultAccountChanged, [this]() { emit lUpdate(true); });
|
||||
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::conferenceInfoCreated,
|
||||
[this](const std::shared_ptr<linphone::ConferenceInfo> &confInfo) { addConference(confInfo); });
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::conferenceInfoReceived,
|
||||
[this](const std::shared_ptr<linphone::Core> &core,
|
||||
|
|
@ -236,7 +233,9 @@ QVariant ConferenceInfoList::data(const QModelIndex &index, int role) const {
|
|||
if (role == Qt::DisplayRole) {
|
||||
return QVariant::fromValue(new ConferenceInfoGui(mList[row].objectCast<ConferenceInfoCore>()));
|
||||
} else if (role == Qt::DisplayRole + 1) {
|
||||
return Utils::toDateMonthString(mList[row].objectCast<ConferenceInfoCore>()->getDateTimeUtc());
|
||||
auto date = mList[row].objectCast<ConferenceInfoCore>()->getDateTimeUtc();
|
||||
if (date.date().year() != QDate::currentDate().year()) return Utils::toDateMonthAndYearString(date);
|
||||
else return Utils::toDateMonthString(date);
|
||||
}
|
||||
} else { // Dummy date
|
||||
if (role == Qt::DisplayRole) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/App.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "model/setting/SettingsModel.hpp"
|
||||
|
||||
#include "AbstractEventCountNotifier.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
using namespace std;
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(AbstractEventCountNotifier)
|
||||
|
||||
AbstractEventCountNotifier::AbstractEventCountNotifier(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
int AbstractEventCountNotifier::getEventCount() const {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
auto coreModel = CoreModel::getInstance();
|
||||
int count = coreModel->getCore()->getMissedCallsCount();
|
||||
return count;
|
||||
}
|
||||
|
||||
int AbstractEventCountNotifier::getCurrentEventCount() const {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
// auto coreModel = CoreModel::getInstance();
|
||||
// int count = coreModel->getCore()->getMissedCallsCount();
|
||||
// bool filtered = SettingsModel::getInstance()->isSystrayNotificationFiltered();
|
||||
// bool global = SettingsModel::getInstance()->isSystrayNotificationGlobal();
|
||||
// if (global && !filtered)
|
||||
return getEventCount();
|
||||
// else {
|
||||
// auto currentAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
|
||||
// if (currentAccount) {
|
||||
// auto linphoneChatRooms = currentAccount->filterChatRooms("");
|
||||
// for (const auto &chatRoom : linphoneChatRooms) {
|
||||
// count += chatRoom->getUnreadMessagesCount();
|
||||
// }
|
||||
// }
|
||||
// return count;
|
||||
// }
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ABSTRACT_EVENT_COUNT_NOTIFIER_H_
|
||||
#define ABSTRACT_EVENT_COUNT_NOTIFIER_H_
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace linphone {
|
||||
class ChatMessage;
|
||||
}
|
||||
|
||||
class CallModel;
|
||||
class ChatRoomModel;
|
||||
class HistoryModel;
|
||||
|
||||
class AbstractEventCountNotifier : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AbstractEventCountNotifier(QObject *parent = Q_NULLPTR);
|
||||
|
||||
int getEventCount() const; // global
|
||||
int getCurrentEventCount() const; // Current account
|
||||
|
||||
protected:
|
||||
virtual void notifyEventCount(int n) = 0;
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif // ABSTRACT_EVENT_COUNT_NOTIFIER_H_
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EVENT_COUNT_NOTIFIER_MAC_OS_H_
|
||||
#define EVENT_COUNT_NOTIFIER_MAC_OS_H_
|
||||
|
||||
#include "AbstractEventCountNotifier.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
extern "C" void notifyEventCountMacOs(int n);
|
||||
|
||||
class EventCountNotifier : public AbstractEventCountNotifier {
|
||||
public:
|
||||
EventCountNotifier(QObject *parent = Q_NULLPTR) : AbstractEventCountNotifier(parent) {
|
||||
}
|
||||
|
||||
void notifyEventCount(int n) override {
|
||||
notifyEventCountMacOs(n);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EVENT_COUNT_NOTIFIER_MAC_OS_H_
|
||||
30
Linphone/core/event-count-notifier/EventCountNotifierMacOs.m
Normal file
30
Linphone/core/event-count-notifier/EventCountNotifierMacOs.m
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* EventCountNotifierMacOs.m
|
||||
* Copyright (C) 2017-2018 Belledonne Communications, Grenoble, France
|
||||
*
|
||||
* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Created on: June 30, 2017
|
||||
* Author: Ghislain MARY
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
void notifyEventCountMacOs (int n) {
|
||||
NSString *badgeStr = (n > 0) ? [NSString stringWithFormat:@"%d", n] : @"";
|
||||
[[NSApp dockTile] setBadgeLabel:badgeStr];
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QIcon>
|
||||
#include <QPainter>
|
||||
#include <QSvgRenderer>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QTimer>
|
||||
#include <QWindow>
|
||||
|
||||
#include "core/App.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "model/setting/SettingsModel.hpp"
|
||||
#include "tool/Constants.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
#include "EventCountNotifierSystemTrayIcon.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace {
|
||||
constexpr int IconWidth = 256;
|
||||
constexpr int IconHeight = 256;
|
||||
|
||||
constexpr int IconCounterBackgroundRadius = 100;
|
||||
constexpr int IconCounterBlinkInterval = 1000;
|
||||
constexpr int IconCounterTextPixelSize = 144;
|
||||
} // namespace
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(EventCountNotifier)
|
||||
|
||||
QSharedPointer<EventCountNotifier> EventCountNotifier::create(QObject *parent) {
|
||||
auto sharedPointer = QSharedPointer<EventCountNotifier>(new EventCountNotifier(parent), &QObject::deleteLater);
|
||||
sharedPointer->setSelf(sharedPointer);
|
||||
sharedPointer->moveToThread(App::getInstance()->thread());
|
||||
return sharedPointer;
|
||||
}
|
||||
|
||||
EventCountNotifier::EventCountNotifier(QObject *parent) : AbstractEventCountNotifier(parent) {
|
||||
QSvgRenderer renderer((QString(Constants::WindowIconPath)));
|
||||
if (!renderer.isValid()) qFatal("Invalid SVG Image.");
|
||||
|
||||
QPixmap buf(IconWidth, IconHeight);
|
||||
buf.fill(QColor(Qt::transparent));
|
||||
|
||||
QPainter painter(&buf);
|
||||
renderer.render(&painter);
|
||||
|
||||
mBuf = new QPixmap(buf);
|
||||
mBufWithCounter = new QPixmap();
|
||||
|
||||
mBlinkTimer = new QTimer(this);
|
||||
mBlinkTimer->setInterval(IconCounterBlinkInterval);
|
||||
connect(mBlinkTimer, &QTimer::timeout, this, &EventCountNotifier::update);
|
||||
}
|
||||
|
||||
void EventCountNotifier::setSelf(QSharedPointer<EventCountNotifier> me) {
|
||||
}
|
||||
|
||||
EventCountNotifier::~EventCountNotifier() {
|
||||
delete mBuf;
|
||||
delete mBufWithCounter;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void EventCountNotifier::notifyEventCount(int n) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
n = n > 99 ? 99 : n;
|
||||
QSystemTrayIcon *sysTrayIcon = App::getInstance()->getSystemTrayIcon();
|
||||
if (!sysTrayIcon) return;
|
||||
|
||||
if (!n) {
|
||||
mBlinkTimer->stop();
|
||||
sysTrayIcon->setIcon(QIcon(*mBuf));
|
||||
return;
|
||||
}
|
||||
|
||||
*mBufWithCounter = *mBuf;
|
||||
QPainter p(mBufWithCounter);
|
||||
|
||||
const int width = mBufWithCounter->width();
|
||||
const int height = mBufWithCounter->height();
|
||||
|
||||
// Draw background.
|
||||
{
|
||||
p.setBrush(QColor(Utils::getDefaultStyleColor("main1_100")));
|
||||
p.drawEllipse(QPointF(width / 2, height / 2), IconCounterBackgroundRadius, IconCounterBackgroundRadius);
|
||||
}
|
||||
|
||||
// Draw text.
|
||||
{
|
||||
QFont font = p.font();
|
||||
font.setPixelSize(IconCounterTextPixelSize);
|
||||
|
||||
p.setFont(font);
|
||||
p.setPen(QPen(QColor(Utils::getDefaultStyleColor("main1_500_main"))));
|
||||
p.drawText(QRect(0, 0, width, height), Qt::AlignCenter, QString::number(n));
|
||||
}
|
||||
|
||||
// Change counter.
|
||||
mBlinkTimer->stop();
|
||||
auto coreModel = CoreModel::getInstance();
|
||||
if (!coreModel->isInitialized() || SettingsModel::getInstance()->isSystrayNotificationBlinkEnabled())
|
||||
mBlinkTimer->start();
|
||||
mDisplayCounter = true;
|
||||
update();
|
||||
}
|
||||
|
||||
void EventCountNotifier::update() {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
QSystemTrayIcon *sysTrayIcon = App::getInstance()->getSystemTrayIcon();
|
||||
if (sysTrayIcon) {
|
||||
sysTrayIcon->setIcon(QIcon(mDisplayCounter ? *mBufWithCounter : *mBuf));
|
||||
}
|
||||
mDisplayCounter = !mDisplayCounter;
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EVENT_COUNT_NOTIFIER_SYSTEM_TRAY_ICON_H_
|
||||
#define EVENT_COUNT_NOTIFIER_SYSTEM_TRAY_ICON_H_
|
||||
|
||||
#include "AbstractEventCountNotifier.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class QTimer;
|
||||
|
||||
class EventCountNotifier : public AbstractEventCountNotifier {
|
||||
public:
|
||||
static QSharedPointer<EventCountNotifier> create(QObject *parent = Q_NULLPTR);
|
||||
EventCountNotifier(QObject *parent = Q_NULLPTR);
|
||||
void setSelf(QSharedPointer<EventCountNotifier> me);
|
||||
~EventCountNotifier();
|
||||
|
||||
void notifyEventCount(int n) override;
|
||||
|
||||
private:
|
||||
const QPixmap *mBuf = nullptr;
|
||||
QPixmap *mBufWithCounter = nullptr;
|
||||
QTimer *mBlinkTimer = nullptr;
|
||||
bool mDisplayCounter = false;
|
||||
QSharedPointer<SafeConnection<EventCountNotifier, CoreModel>> mCoreModelConnection;
|
||||
void update();
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif // EVENT_COUNT_NOTIFIER_SYSTEM_TRAY_ICON_H_
|
||||
|
|
@ -445,8 +445,9 @@ QList<QVariant> FriendCore::getAllAddresses() const {
|
|||
auto phoneNumbers = mPhoneNumberList;
|
||||
while (addressIt != mAddressList.end()) {
|
||||
auto username = Utils::getUsername(addressIt->toMap()["address"].toString());
|
||||
std::remove_if(phoneNumbers.begin(), phoneNumbers.end(),
|
||||
[username](const QVariant &data) { return data.toMap()["address"].toString() == username; });
|
||||
phoneNumbers.erase(std::remove_if(phoneNumbers.begin(), phoneNumbers.end(),
|
||||
[username](const QVariant &data) { return data.toMap()["address"].toString() == username; })
|
||||
, phoneNumbers.end());
|
||||
++addressIt;
|
||||
}
|
||||
addresses << phoneNumbers;
|
||||
|
|
|
|||
|
|
@ -171,28 +171,24 @@ bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap d
|
|||
// window->setProperty(it.key().toLatin1(), it.value());
|
||||
const int timeout = Notifications[type].getTimeout() * 1000;
|
||||
auto updateNotificationCoordinates = [this, window, screen](int width, int height) {
|
||||
int *screenHeightOffset = &mScreenHeightOffset[screen->name()]; // Access optimization
|
||||
auto screenHeightOffset =
|
||||
screen ? mScreenHeightOffset.value(screen->name()) : 0; // Access optimization
|
||||
QRect availableGeometry = screen->availableGeometry();
|
||||
int heightOffset = availableGeometry.y() +
|
||||
(availableGeometry.height() -
|
||||
height); //*screen->devicePixelRatio(); when using manual scaler
|
||||
|
||||
window->setX(availableGeometry.x() +
|
||||
(availableGeometry.width() -
|
||||
width)); //*screen->devicePixelRatio()); when using manual scaler
|
||||
window->setY(heightOffset - (*screenHeightOffset % heightOffset));
|
||||
window->setY(availableGeometry.y() + availableGeometry.height() - screenHeightOffset -
|
||||
height);
|
||||
};
|
||||
QObject::connect(window, &QQuickWindow::widthChanged,
|
||||
[window, updateNotificationCoordinates](int w) {
|
||||
updateNotificationCoordinates(w, window->height());
|
||||
});
|
||||
QObject::connect(window, &QQuickWindow::heightChanged,
|
||||
[window, updateNotificationCoordinates](int h) {
|
||||
updateNotificationCoordinates(window->width(), h);
|
||||
});
|
||||
updateNotificationCoordinates(window->width(), window->height());
|
||||
QObject::connect(window, &QQuickWindow::closing, window,
|
||||
[this, window] { deleteNotification(QVariant::fromValue(window)); });
|
||||
auto screenHeightOffset =
|
||||
screen ? mScreenHeightOffset.take(screen->name()) : 0; // Access optimization
|
||||
mScreenHeightOffset.insert(screen->name(), screenHeightOffset + window->height());
|
||||
QObject::connect(window, &QQuickWindow::closing, window, [this, window] {
|
||||
qDebug() << "closing notification";
|
||||
deleteNotification(QVariant::fromValue(window));
|
||||
});
|
||||
showNotification(window, timeout);
|
||||
lInfo() << QStringLiteral("Create notification:") << QVariant::fromValue(window);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -115,10 +115,13 @@ void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
|
|||
splitted.removeFirst();
|
||||
contact->setFamilyName(splitted.join(" "));
|
||||
} else {
|
||||
contact->setGivenName(Utils::coreStringToAppString(address->getUsername()));
|
||||
contact->setGivenName(displayName.isEmpty()
|
||||
? Utils::coreStringToAppString(address->getUsername())
|
||||
: displayName);
|
||||
}
|
||||
contact->setDefaultFullAddress(Utils::coreStringToAppString(
|
||||
address->asString())); // linphone Friend object remove specific address.
|
||||
contact->setDefaultAddress(Utils::coreStringToAppString(address->asString()));
|
||||
contacts->append(contact);
|
||||
} else if (!it->getPhoneNumber().empty()) {
|
||||
auto phoneNumber = it->getPhoneNumber();
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ SettingsCore::SettingsCore(QObject *parent) : QObject(parent) {
|
|||
INIT_CORE_MEMBER(AssistantDisableQrCode, settingsModel)
|
||||
|
||||
INIT_CORE_MEMBER(AssistantHideThirdPartyAccount, settingsModel)
|
||||
INIT_CORE_MEMBER(OnlyDisplaySipUriUsername, settingsModel)
|
||||
INIT_CORE_MEMBER(HideSipAddresses, settingsModel)
|
||||
INIT_CORE_MEMBER(DarkModeAllowed, settingsModel)
|
||||
INIT_CORE_MEMBER(MaxAccount, settingsModel)
|
||||
INIT_CORE_MEMBER(AssistantGoDirectlyToThirdPartySipAccountLogin, settingsModel)
|
||||
|
|
@ -179,7 +179,7 @@ SettingsCore::SettingsCore(const SettingsCore &settingsCore) {
|
|||
mAssistantDisableQrCode = settingsCore.mAssistantDisableQrCode;
|
||||
|
||||
mAssistantHideThirdPartyAccount = settingsCore.mAssistantHideThirdPartyAccount;
|
||||
mOnlyDisplaySipUriUsername = settingsCore.mOnlyDisplaySipUriUsername;
|
||||
mHideSipAddresses = settingsCore.mHideSipAddresses;
|
||||
mDarkModeAllowed = settingsCore.mDarkModeAllowed;
|
||||
mMaxAccount = settingsCore.mMaxAccount;
|
||||
mAssistantGoDirectlyToThirdPartySipAccountLogin = settingsCore.mAssistantGoDirectlyToThirdPartySipAccountLogin;
|
||||
|
|
@ -206,6 +206,13 @@ void SettingsCore::setSelf(QSharedPointer<SettingsCore> me) {
|
|||
mustBeInLinphoneThread(getClassName());
|
||||
mSettingsModelConnection = SafeConnection<SettingsCore, SettingsModel>::create(me, SettingsModel::getInstance());
|
||||
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::captureGraphRunningChanged, [this](bool running) {
|
||||
mSettingsModelConnection->invokeToCore([this, running] {
|
||||
mCaptureGraphRunning = running;
|
||||
emit captureGraphRunningChanged(running);
|
||||
});
|
||||
});
|
||||
|
||||
// VFS
|
||||
mSettingsModelConnection->makeConnectToModel(&SettingsModel::vfsEnabledChanged, [this](const bool enabled) {
|
||||
mSettingsModelConnection->invokeToCore([this, enabled]() { setVfsEnabled(enabled); });
|
||||
|
|
@ -379,7 +386,7 @@ void SettingsCore::setSelf(QSharedPointer<SettingsCore> me) {
|
|||
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
|
||||
assistantHideThirdPartyAccount, AssistantHideThirdPartyAccount)
|
||||
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
|
||||
onlyDisplaySipUriUsername, OnlyDisplaySipUriUsername)
|
||||
hideSipAddresses, HideSipAddresses)
|
||||
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
|
||||
darkModeAllowed, DarkModeAllowed)
|
||||
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, int, maxAccount,
|
||||
|
|
@ -487,7 +494,7 @@ void SettingsCore::reset(const SettingsCore &settingsCore) {
|
|||
setAssistantDisableQrCode(settingsCore.mAssistantDisableQrCode);
|
||||
|
||||
setAssistantHideThirdPartyAccount(settingsCore.mAssistantHideThirdPartyAccount);
|
||||
setOnlyDisplaySipUriUsername(settingsCore.mOnlyDisplaySipUriUsername);
|
||||
setHideSipAddresses(settingsCore.mHideSipAddresses);
|
||||
setDarkModeAllowed(settingsCore.mDarkModeAllowed);
|
||||
setMaxAccount(settingsCore.mMaxAccount);
|
||||
setAssistantGoDirectlyToThirdPartySipAccountLogin(settingsCore.mAssistantGoDirectlyToThirdPartySipAccountLogin);
|
||||
|
|
@ -560,7 +567,7 @@ QVariantList SettingsCore::getPlaybackDevices() const {
|
|||
|
||||
void SettingsCore::setPlaybackDevices(QVariantList devices) {
|
||||
mPlaybackDevices = devices;
|
||||
emit captureDevicesChanged(devices);
|
||||
emit playbackDevicesChanged(devices);
|
||||
}
|
||||
|
||||
QVariantList SettingsCore::getRingerDevices() const {
|
||||
|
|
@ -958,7 +965,7 @@ void SettingsCore::writeIntoModel(std::shared_ptr<SettingsModel> model) const {
|
|||
model->setAssistantDisableQrCode(mAssistantDisableQrCode);
|
||||
|
||||
model->setAssistantHideThirdPartyAccount(mAssistantHideThirdPartyAccount);
|
||||
model->setOnlyDisplaySipUriUsername(mOnlyDisplaySipUriUsername);
|
||||
model->setHideSipAddresses(mHideSipAddresses);
|
||||
model->setDarkModeAllowed(mDarkModeAllowed);
|
||||
model->setMaxAccount(mMaxAccount);
|
||||
model->setAssistantGoDirectlyToThirdPartySipAccountLogin(mAssistantGoDirectlyToThirdPartySipAccountLogin);
|
||||
|
|
@ -1024,7 +1031,7 @@ void SettingsCore::writeFromModel(const std::shared_ptr<SettingsModel> &model) {
|
|||
mAssistantDisableQrCode = model->getAssistantDisableQrCode();
|
||||
|
||||
mAssistantHideThirdPartyAccount = model->getAssistantHideThirdPartyAccount();
|
||||
mOnlyDisplaySipUriUsername = model->getOnlyDisplaySipUriUsername();
|
||||
mHideSipAddresses = model->getHideSipAddresses();
|
||||
mDarkModeAllowed = model->getDarkModeAllowed();
|
||||
mMaxAccount = model->getMaxAccount();
|
||||
mAssistantGoDirectlyToThirdPartySipAccountLogin = model->getAssistantGoDirectlyToThirdPartySipAccountLogin();
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ public:
|
|||
DECLARE_CORE_GETSET_MEMBER(bool, assistantHideCreateAccount, AssistantHideCreateAccount)
|
||||
DECLARE_CORE_GETSET_MEMBER(bool, assistantDisableQrCode, AssistantDisableQrCode)
|
||||
DECLARE_CORE_GETSET_MEMBER(bool, assistantHideThirdPartyAccount, AssistantHideThirdPartyAccount)
|
||||
DECLARE_CORE_GETSET_MEMBER(bool, onlyDisplaySipUriUsername, OnlyDisplaySipUriUsername)
|
||||
DECLARE_CORE_GETSET_MEMBER(bool, hideSipAddresses, HideSipAddresses)
|
||||
DECLARE_CORE_GETSET_MEMBER(bool, darkModeAllowed, DarkModeAllowed)
|
||||
DECLARE_CORE_GETSET_MEMBER(int, maxAccount, MaxAccount)
|
||||
DECLARE_CORE_GETSET_MEMBER(bool,
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M13.75 20C13.75 20.1989 13.671 20.3897 13.5303 20.5303C13.3897 20.671 13.1989 20.75 13 20.75H7.00002C6.80111 20.75 6.61034 20.671 6.46969 20.5303C6.32904 20.3897 6.25002 20.1989 6.25002 20C6.25002 19.8011 6.32904 19.6103 6.46969 19.4697C6.61034 19.329 6.80111 19.25 7.00002 19.25H13C13.1989 19.25 13.3897 19.329 13.5303 19.4697C13.671 19.6103 13.75 19.8011 13.75 20ZM19.3178 4.65499C18.4749 3.00748 17.2092 1.61364 15.6503 0.616239C15.567 0.563035 15.4741 0.526817 15.3767 0.509668C15.2794 0.492519 15.1796 0.494776 15.0832 0.516311C14.9867 0.537846 14.8955 0.578233 14.8147 0.635151C14.7339 0.692069 14.6651 0.764396 14.6124 0.847973C14.5596 0.931549 14.5239 1.02473 14.5073 1.12215C14.4906 1.21958 14.4934 1.31933 14.5155 1.41567C14.5376 1.51201 14.5784 1.60304 14.6358 1.68353C14.6931 1.76402 14.7658 1.83238 14.8497 1.88468C16.1871 2.73546 17.2707 3.93076 17.9866 5.34499C18.0812 5.51593 18.2388 5.64321 18.4258 5.69974C18.6128 5.75628 18.8145 5.73761 18.9879 5.6477C19.1614 5.5578 19.2929 5.40376 19.3545 5.21836C19.4161 5.03296 19.403 4.83083 19.3178 4.65499ZM1.34783 5.74999C1.48523 5.74993 1.61998 5.71213 1.73736 5.64071C1.85474 5.56929 1.95025 5.46699 2.01346 5.34499C2.72933 3.93076 3.81291 2.73546 5.15033 1.88468C5.23419 1.83238 5.30689 1.76402 5.36424 1.68353C5.4216 1.60304 5.46248 1.51201 5.48454 1.41567C5.50659 1.31933 5.50939 1.21958 5.49277 1.12215C5.47615 1.02473 5.44043 0.931549 5.38768 0.847973C5.33493 0.764396 5.26617 0.692069 5.18538 0.635151C5.10458 0.578233 5.01333 0.537846 4.91687 0.516311C4.82041 0.494776 4.72065 0.492519 4.62331 0.509668C4.52598 0.526817 4.433 0.563035 4.34971 0.616239C2.79085 1.61364 1.52514 3.00748 0.682206 4.65499C0.622991 4.76929 0.594192 4.8969 0.598581 5.02556C0.602969 5.15421 0.640397 5.27957 0.707263 5.38957C0.774128 5.49956 0.868181 5.5905 0.980369 5.65363C1.09256 5.71675 1.2191 5.74994 1.34783 5.74999ZM18.7947 15.4944C18.9276 15.7222 18.998 15.9811 18.9989 16.2448C18.9998 16.5086 18.9312 16.7679 18.7999 16.9967C18.6686 17.2255 18.4793 17.4156 18.251 17.5478C18.0228 17.6801 17.7638 17.7498 17.5 17.75H2.50002C2.23641 17.7495 1.9776 17.6795 1.74965 17.5471C1.5217 17.4147 1.33266 17.2246 1.20158 16.9959C1.0705 16.7672 1.002 16.508 1.00299 16.2444C1.00398 15.9808 1.07441 15.7221 1.20721 15.4944C2.05189 14.0366 2.50002 11.9637 2.50002 9.49999C2.50002 7.51087 3.29019 5.60321 4.69672 4.19669C6.10324 2.79017 8.01089 1.99999 10 1.99999C11.9891 1.99999 13.8968 2.79017 15.3033 4.19669C16.7098 5.60321 17.5 7.51087 17.5 9.49999C17.5 11.9628 17.9481 14.0356 18.7947 15.4944ZM17.5 16.25C16.5025 14.5372 16 12.2666 16 9.49999C16 7.90869 15.3679 6.38257 14.2427 5.25735C13.1174 4.13213 11.5913 3.49999 10 3.49999C8.40872 3.49999 6.8826 4.13213 5.75738 5.25735C4.63216 6.38257 4.00002 7.90869 4.00002 9.49999C4.00002 12.2675 3.49564 14.5381 2.50002 16.25H17.5Z" fill="#000000"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB |
1
Linphone/data/image/bell-ringing.svg
Normal file
1
Linphone/data/image/bell-ringing.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M224,71.1a8,8,0,0,1-10.78-3.42,94.13,94.13,0,0,0-33.46-36.91,8,8,0,1,1,8.54-13.54,111.46,111.46,0,0,1,39.12,43.09A8,8,0,0,1,224,71.1ZM35.71,72a8,8,0,0,0,7.1-4.32A94.13,94.13,0,0,1,76.27,30.77a8,8,0,1,0-8.54-13.54A111.46,111.46,0,0,0,28.61,60.32,8,8,0,0,0,35.71,72Zm186.1,103.94A16,16,0,0,1,208,200H167.2a40,40,0,0,1-78.4,0H48a16,16,0,0,1-13.79-24.06C43.22,160.39,48,138.28,48,112a80,80,0,0,1,160,0C208,138.27,212.78,160.38,221.81,175.94ZM150.62,200H105.38a24,24,0,0,0,45.24,0ZM208,184c-10.64-18.27-16-42.49-16-72a64,64,0,0,0-128,0c0,29.52-5.38,53.74-16,72Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 680 B |
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M168,224a8,8,0,0,1-8,8H96a8,8,0,1,1,0-16h64A8,8,0,0,1,168,224Zm53.85-32A15.8,15.8,0,0,1,208,200H48a16,16,0,0,1-13.8-24.06C39.75,166.38,48,139.34,48,104a80,80,0,1,1,160,0c0,35.33,8.26,62.38,13.81,71.94A15.89,15.89,0,0,1,221.84,192ZM208,184c-7.73-13.27-16-43.95-16-80a64,64,0,1,0-128,0c0,36.06-8.28,66.74-16,80Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 433 B |
1
Linphone/data/image/bell.svg
Normal file
1
Linphone/data/image/bell.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M221.8,175.94C216.25,166.38,208,139.33,208,104a80,80,0,1,0-160,0c0,35.34-8.26,62.38-13.81,71.94A16,16,0,0,0,48,200H88.81a40,40,0,0,0,78.38,0H208a16,16,0,0,0,13.8-24.06ZM128,216a24,24,0,0,1-22.62-16h45.24A24,24,0,0,1,128,216ZM48,184c7.7-13.24,16-43.92,16-80a64,64,0,1,1,128,0c0,36.05,8.28,66.73,16,80Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 424 B |
5454
Linphone/data/languages/cs.ts
Normal file
5454
Linphone/data/languages/cs.ts
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
5436
Linphone/data/languages/eu.ts
Normal file
5436
Linphone/data/languages/eu.ts
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
5436
Linphone/data/languages/pt.ts
Normal file
5436
Linphone/data/languages/pt.ts
Normal file
File diff suppressed because it is too large
Load diff
5436
Linphone/data/languages/pt_BR.ts
Normal file
5436
Linphone/data/languages/pt_BR.ts
Normal file
File diff suppressed because it is too large
Load diff
5454
Linphone/data/languages/ru.ts
Normal file
5454
Linphone/data/languages/ru.ts
Normal file
File diff suppressed because it is too large
Load diff
5454
Linphone/data/languages/uk.ts
Normal file
5454
Linphone/data/languages/uk.ts
Normal file
File diff suppressed because it is too large
Load diff
5426
Linphone/data/languages/zh_Hans.ts
Normal file
5426
Linphone/data/languages/zh_Hans.ts
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -75,21 +75,41 @@ OIDCModel::OIDCModel(const std::shared_ptr<linphone::AuthInfo> &authInfo, QObjec
|
|||
qDebug() << "OIDC Client ID set to [" << clientid << "]";
|
||||
|
||||
// find an auth info from LinphoneCore where username = clientid
|
||||
auto clientSecret = CoreModel::getInstance()->getCore()->findAuthInfo("", clientid.toStdString(), "");
|
||||
if (clientSecret != nullptr) {
|
||||
qDebug() << "client secret found for client id [" << clientid << "]";
|
||||
mOidc.setClientIdentifierSharedKey(clientSecret->getPassword().c_str());
|
||||
std::shared_ptr<linphone::AuthInfo> clientSecret = nullptr;
|
||||
// search for auth info for this client id
|
||||
for (const auto &authInfo : CoreModel::getInstance()->getCore()->getAuthInfoList()) {
|
||||
if (authInfo->getClientId() == clientid.toStdString()) {
|
||||
qDebug() << "AuthInfo found for client id [" << clientid << "]";
|
||||
clientSecret = authInfo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString scope = OIDCScope;
|
||||
;
|
||||
if (clientSecret != nullptr) {
|
||||
qDebug() << "client secret found for client id [" << clientid << "]";
|
||||
mOidc.setClientIdentifierSharedKey(clientSecret->getClientSecret().c_str());
|
||||
}
|
||||
|
||||
QSet<QByteArray> scopeTokens;
|
||||
if (autorizationUrl.hasQuery()) {
|
||||
QUrlQuery query(autorizationUrl);
|
||||
if (query.hasQueryItem("scope")) {
|
||||
scope = query.queryItemValue("scope");
|
||||
auto scopeList = query.queryItemValue("scope").split(' ');
|
||||
for (const auto &scopeItem : scopeList) {
|
||||
scopeTokens.insert(scopeItem.toUtf8());
|
||||
}
|
||||
}
|
||||
}
|
||||
mOidc.setScope(scope);
|
||||
if (scopeTokens.isEmpty()) {
|
||||
scopeTokens.insert(OIDCScope);
|
||||
qDebug() << "No scope found in authorization URL, using default scope [" << OIDCScope << "]";
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
|
||||
mOidc.setRequestedScopeTokens(scopeTokens);
|
||||
#else
|
||||
mOidc.setScope(QStringList(scopeTokens.begin(), scopeTokens.end()).join(' '));
|
||||
#endif
|
||||
mTimeout.setInterval(1000 * 60 * 2); // 2minutes
|
||||
|
||||
connect(&mTimeout, &QTimer::timeout, [this]() {
|
||||
|
|
@ -189,10 +209,34 @@ OIDCModel::OIDCModel(const std::shared_ptr<linphone::AuthInfo> &authInfo, QObjec
|
|||
|
||||
connect(this, &OIDCModel::authenticated, this, &OIDCModel::setBearers);
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 9, 0)
|
||||
// Connect the signal to the tokensReceived handler to get id_token
|
||||
connect(mOidc.replyHandler(), &QOAuthHttpServerReplyHandler::tokensReceived, this,
|
||||
[this](const QVariantMap &tokens) {
|
||||
// for (auto it = tokens.cbegin(); it != tokens.cend(); ++it) {
|
||||
// qDebug() << "Token key:" << it.key() << ", value:" << it.value().toString();
|
||||
// }
|
||||
if (tokens.contains("id_token") &&
|
||||
CoreModel::getInstance()->getCore()->getConfig()->getBool("app", "oidc_use_id_token", false)) {
|
||||
auto idToken = tokens["id_token"].toString();
|
||||
qDebug() << "ID Token received:" << idToken.left(3) + "..." + idToken.right(3);
|
||||
mIdToken = idToken;
|
||||
} else if (tokens.contains("access_token")) {
|
||||
auto accessToken = tokens["access_token"].toString();
|
||||
qDebug() << "Access Token received:" << accessToken.left(3) + "..." + accessToken.right(3);
|
||||
mIdToken = accessToken;
|
||||
|
||||
} else {
|
||||
mIdToken.clear();
|
||||
qWarning() << "No ID Token or Access Token found in the tokens.";
|
||||
emit requestFailed(tr("oidc_authentication_no_token_found_error"));
|
||||
emit finished();
|
||||
}
|
||||
});
|
||||
#endif
|
||||
// in case we want to add parameters. Needed to override redirect_url
|
||||
mOidc.setModifyParametersFunction([&, username = Utils::coreStringToAppString(authInfo->getUsername())](
|
||||
QAbstractOAuth::Stage stage, QMultiMap<QString, QVariant> *parameters) {
|
||||
parameters->insert("login_hint", username);
|
||||
parameters->replace("application_type", "native");
|
||||
switch (stage) {
|
||||
case QAbstractOAuth::Stage::RequestingAccessToken: {
|
||||
|
|
@ -244,7 +288,11 @@ void OIDCModel::openIdConfigReceived() {
|
|||
return;
|
||||
}
|
||||
if (rootArray.contains("token_endpoint")) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
|
||||
mOidc.setTokenUrl(QUrl(rootArray["token_endpoint"].toString()));
|
||||
#else
|
||||
mOidc.setAccessTokenUrl(QUrl(rootArray["token_endpoint"].toString()));
|
||||
#endif
|
||||
mAuthInfo->setTokenEndpointUri(
|
||||
Utils::appStringToCoreString(QUrl(rootArray["token_endpoint"].toString()).toString()));
|
||||
} else {
|
||||
|
|
@ -262,13 +310,35 @@ void OIDCModel::setBearers() {
|
|||
auto expiration = QDateTime::currentDateTime().secsTo(mOidc.expirationAt());
|
||||
auto timeT = mOidc.expirationAt().toSecsSinceEpoch();
|
||||
qDebug() << "Authenticated for " << expiration << "s";
|
||||
auto refreshBearer =
|
||||
linphone::Factory::get()->createBearerToken(Utils::appStringToCoreString(mOidc.refreshToken()), timeT);
|
||||
|
||||
auto accessBearer = linphone::Factory::get()->createBearerToken(Utils::appStringToCoreString(mOidc.token()), timeT);
|
||||
mAuthInfo->setRefreshToken(refreshBearer);
|
||||
auto accessBearer = linphone::Factory::get()->createBearerToken(Utils::appStringToCoreString(idToken()), timeT);
|
||||
mAuthInfo->setAccessToken(accessBearer);
|
||||
|
||||
if (mOidc.refreshToken() != nullptr) {
|
||||
|
||||
auto refreshBearer =
|
||||
linphone::Factory::get()->createBearerToken(Utils::appStringToCoreString(mOidc.refreshToken()), timeT);
|
||||
mAuthInfo->setRefreshToken(refreshBearer);
|
||||
|
||||
} else {
|
||||
qWarning() << "No refresh token found";
|
||||
}
|
||||
CoreModel::getInstance()->getCore()->addAuthInfo(mAuthInfo);
|
||||
emit CoreModel::getInstance()->bearerAccountAdded();
|
||||
emit CoreModel::getInstance() -> bearerAccountAdded();
|
||||
emit finished();
|
||||
}
|
||||
QString OIDCModel::idToken() const {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 9, 0)
|
||||
if (CoreModel::getInstance()->getCore()->getConfig()->getBool("app", "oidc_use_id_token", false)) {
|
||||
if (!mOidc.idToken().isEmpty()) {
|
||||
return mOidc.idToken();
|
||||
} else {
|
||||
return mOidc.token();
|
||||
}
|
||||
} else {
|
||||
return mOidc.token();
|
||||
}
|
||||
#else
|
||||
return mIdToken;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -44,11 +44,26 @@ signals:
|
|||
void finished();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Retrieves the ID token.
|
||||
*
|
||||
* This function returns the ID token as a QString. The ID token is typically
|
||||
* used for authentication and authorization purposes in OpenID Connect (OIDC)
|
||||
* workflows. Implementation is specific to QT version
|
||||
*
|
||||
* @return The ID token as a QString.
|
||||
*/
|
||||
QString idToken() const;
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 9, 0)
|
||||
QString mIdToken;
|
||||
#endif
|
||||
QOAuth2AuthorizationCodeFlow mOidc;
|
||||
std::shared_ptr<linphone::AuthInfo> mAuthInfo;
|
||||
QTimer mTimeout;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -116,8 +116,10 @@ void CallModel::terminateAllCalls() {
|
|||
|
||||
void CallModel::setMicrophoneMuted(bool isMuted) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
mMonitor->setMicrophoneMuted(isMuted);
|
||||
emit microphoneMutedChanged(isMuted);
|
||||
if (mMonitor->getConference()) mMonitor->getConference()->setMicrophoneMuted(isMuted);
|
||||
else mMonitor->setMicrophoneMuted(isMuted);
|
||||
emit microphoneMutedChanged(mMonitor->getConference() ? mMonitor->getConference()->getMicrophoneMuted()
|
||||
: mMonitor->getMicrophoneMuted());
|
||||
}
|
||||
|
||||
void CallModel::setSpeakerMuted(bool isMuted) {
|
||||
|
|
@ -411,7 +413,7 @@ void CallModel::onStateChanged(const std::shared_ptr<linphone::Call> &call,
|
|||
emit localVideoEnabledChanged(videoDirection == linphone::MediaDirection::SendOnly ||
|
||||
videoDirection == linphone::MediaDirection::SendRecv);
|
||||
emit remoteVideoEnabledChanged(remoteVideoDirection == linphone::MediaDirection::SendOnly ||
|
||||
remoteVideoDirection == linphone::MediaDirection::SendRecv);
|
||||
remoteVideoDirection == linphone::MediaDirection::SendRecv);
|
||||
updateConferenceVideoLayout();
|
||||
} else if (state == linphone::Call::State::End || state == linphone::Call::State::Error) {
|
||||
mDurationTimer.stop();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@
|
|||
#include "model/tool/ToolModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
#if defined(Q_OS_MACOS)
|
||||
#include "core/event-count-notifier/EventCountNotifierMacOs.hpp"
|
||||
#else
|
||||
#include "core/event-count-notifier/EventCountNotifierSystemTrayIcon.hpp"
|
||||
#endif // if defined(Q_OS_MACOS)
|
||||
|
||||
// =============================================================================
|
||||
DEFINE_ABSTRACT_OBJECT(CoreModel)
|
||||
|
||||
|
|
@ -85,9 +91,9 @@ void CoreModel::start() {
|
|||
// Useful if the app was built without video support.
|
||||
// (The capture/display attributes are reset by the core in this case.)
|
||||
auto config = mCore->getConfig();
|
||||
if (mCore->videoSupported()) {
|
||||
config->setInt("video", "capture", 1);
|
||||
config->setInt("video", "display", 1);
|
||||
if (!mCore->videoSupported()) {
|
||||
config->setInt("video", "capture", 0);
|
||||
config->setInt("video", "display", 0);
|
||||
}
|
||||
|
||||
// TODO : set the real transport type when sdk will be updated
|
||||
|
|
@ -116,18 +122,27 @@ void CoreModel::start() {
|
|||
mCore->enableFriendListSubscription(true);
|
||||
if (mCore->getLogCollectionUploadServerUrl().empty())
|
||||
mCore->setLogCollectionUploadServerUrl(Constants::DefaultUploadLogsServer);
|
||||
|
||||
/// These 2 API should not be used as they manage internal gains insterad of those of the soundcard.
|
||||
// Use playback/capture gain from capture graph and call only
|
||||
mCore->setMicGainDb(0.0);
|
||||
mCore->setPlaybackGainDb(0.0);
|
||||
mIterateTimer->start();
|
||||
|
||||
auto linphoneSearch = mCore->createMagicSearch();
|
||||
linphoneSearch->setLimitedSearch(true);
|
||||
mMagicSearch = Utils::makeQObject_ptr<MagicSearchModel>(linphoneSearch);
|
||||
mMagicSearch->setSelf(mMagicSearch);
|
||||
connect(mMagicSearch.get(), &MagicSearchModel::searchResultsReceived, this, [this] {
|
||||
emit magicSearchResultReceived(mMagicSearch->mLastSearch);
|
||||
});
|
||||
connect(mMagicSearch.get(), &MagicSearchModel::searchResultsReceived, this,
|
||||
[this] { emit magicSearchResultReceived(mMagicSearch->mLastSearch); });
|
||||
mStarted = true;
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
bool CoreModel::isInitialized() const {
|
||||
return mStarted;
|
||||
}
|
||||
|
||||
std::shared_ptr<CoreModel> CoreModel::getInstance() {
|
||||
return gCoreModel;
|
||||
}
|
||||
|
|
@ -352,10 +367,11 @@ void CoreModel::migrate() {
|
|||
config->setInt(SettingsModel::UiSection, Constants::RcVersionName, Constants::RcVersionCurrent);
|
||||
}
|
||||
|
||||
void CoreModel::searchInMagicSearch(QString filter, int sourceFlags,
|
||||
LinphoneEnums::MagicSearchAggregation aggregation,
|
||||
int maxResults) {
|
||||
mMagicSearch->search(filter, sourceFlags, aggregation, maxResults);
|
||||
void CoreModel::searchInMagicSearch(QString filter,
|
||||
int sourceFlags,
|
||||
LinphoneEnums::MagicSearchAggregation aggregation,
|
||||
int maxResults) {
|
||||
mMagicSearch->search(filter, sourceFlags, aggregation, maxResults);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------------
|
||||
|
|
@ -446,6 +462,8 @@ void CoreModel::onConferenceStateChanged(const std::shared_ptr<linphone::Core> &
|
|||
void CoreModel::onConfiguringStatus(const std::shared_ptr<linphone::Core> &core,
|
||||
linphone::ConfiguringState status,
|
||||
const std::string &message) {
|
||||
mConfigStatus = status;
|
||||
mConfigMessage = Utils::coreStringToAppString(message);
|
||||
emit configuringStatus(core, status, message);
|
||||
}
|
||||
void CoreModel::onDefaultAccountChanged(const std::shared_ptr<linphone::Core> &core,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
|
@ -34,11 +35,14 @@
|
|||
#include "model/cli/CliModel.hpp"
|
||||
#include "model/listener/Listener.hpp"
|
||||
#include "model/logger/LoggerModel.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "model/search/MagicSearchModel.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class AbstractEventCountNotifier;
|
||||
class EventCountNotifier;
|
||||
|
||||
class CoreModel : public ::Listener<linphone::Core, linphone::CoreListener>,
|
||||
public linphone::CoreListener,
|
||||
public AbstractObject {
|
||||
|
|
@ -52,6 +56,8 @@ public:
|
|||
std::shared_ptr<linphone::Core> getCore();
|
||||
std::shared_ptr<LoggerModel> getLogger();
|
||||
|
||||
bool isInitialized() const;
|
||||
|
||||
void start();
|
||||
void setConfigPath(QString path);
|
||||
|
||||
|
|
@ -61,11 +67,13 @@ public:
|
|||
void migrate();
|
||||
|
||||
void searchInMagicSearch(QString filter,
|
||||
int sourceFlags,
|
||||
LinphoneEnums::MagicSearchAggregation aggregation,
|
||||
int maxResults);
|
||||
int sourceFlags,
|
||||
LinphoneEnums::MagicSearchAggregation aggregation,
|
||||
int maxResults);
|
||||
|
||||
bool mEnd = false;
|
||||
linphone::ConfiguringState mConfigStatus;
|
||||
QString mConfigMessage;
|
||||
|
||||
std::shared_ptr<linphone::Core> mCore;
|
||||
std::shared_ptr<LoggerModel> mLogger;
|
||||
|
|
@ -76,7 +84,6 @@ signals:
|
|||
void friendRemoved(const std::shared_ptr<linphone::Friend> &f);
|
||||
void friendUpdated(const std::shared_ptr<linphone::Friend> &f);
|
||||
void bearerAccountAdded();
|
||||
void conferenceInfoCreated(const std::shared_ptr<linphone::ConferenceInfo> &confInfo);
|
||||
void unreadNotificationsChanged();
|
||||
void requestFetchConfig(QString path);
|
||||
void requestRestart();
|
||||
|
|
@ -88,6 +95,7 @@ private:
|
|||
QTimer *mIterateTimer = nullptr;
|
||||
QMap<QString, OIDCModel *> mOpenIdConnections;
|
||||
std::shared_ptr<MagicSearchModel> mMagicSearch;
|
||||
bool mStarted = false;
|
||||
|
||||
void setPathBeforeCreation();
|
||||
void setPathsAfterCreation();
|
||||
|
|
|
|||
|
|
@ -83,14 +83,19 @@ void MagicSearchModel::onSearchResultsReceived(const std::shared_ptr<linphone::M
|
|||
auto ldapFriends = ToolModel::getLdapFriendList();
|
||||
emit searchResultsReceived(results);
|
||||
for (auto result : results) {
|
||||
if (!result) continue;
|
||||
auto f = result->getFriend();
|
||||
auto friendsManager = FriendsManager::getInstance();
|
||||
if (f) {
|
||||
qDebug() << "friend exists, append to unknown map";
|
||||
auto friendAddress = f->getAddress();
|
||||
friendsManager->appendUnknownFriend(friendAddress->clone(), f);
|
||||
if (friendsManager->isInOtherAddresses(Utils::coreStringToAppString(friendAddress->asStringUriOnly()))) {
|
||||
friendsManager->removeOtherAddress(Utils::coreStringToAppString(friendAddress->asStringUriOnly()));
|
||||
auto friendAddress = f->getAddress() ? f->getAddress()->clone() : nullptr;
|
||||
if (friendAddress) {
|
||||
friendAddress->clean();
|
||||
friendsManager->appendUnknownFriend(friendAddress, f);
|
||||
if (friendsManager->isInOtherAddresses(
|
||||
Utils::coreStringToAppString(friendAddress->asStringUriOnly()))) {
|
||||
friendsManager->removeOtherAddress(Utils::coreStringToAppString(friendAddress->asStringUriOnly()));
|
||||
}
|
||||
}
|
||||
}
|
||||
auto fList = f ? f->getFriendList() : nullptr;
|
||||
|
|
@ -127,7 +132,7 @@ void MagicSearchModel::updateFriendListWithFriend(const std::shared_ptr<linphone
|
|||
if (ToolModel::friendIsInFriendList(friendList, linphoneFriend))
|
||||
return; // Already exist. We don't need to manipulate list.
|
||||
for (auto address : linphoneFriend->getAddresses()) {
|
||||
auto existingFriend = friendList->findFriendByAddress(address);
|
||||
auto existingFriend = friendList ? friendList->findFriendByAddress(address) : nullptr;
|
||||
if (existingFriend) {
|
||||
friendList->removeFriend(existingFriend);
|
||||
friendList->addFriend(linphoneFriend);
|
||||
|
|
@ -135,7 +140,7 @@ void MagicSearchModel::updateFriendListWithFriend(const std::shared_ptr<linphone
|
|||
}
|
||||
}
|
||||
for (auto number : linphoneFriend->getPhoneNumbers()) {
|
||||
auto existingFriend = friendList->findFriendByPhoneNumber(number);
|
||||
auto existingFriend = friendList ? friendList->findFriendByPhoneNumber(number) : nullptr;
|
||||
if (existingFriend) {
|
||||
friendList->removeFriend(existingFriend);
|
||||
friendList->addFriend(linphoneFriend);
|
||||
|
|
@ -143,6 +148,6 @@ void MagicSearchModel::updateFriendListWithFriend(const std::shared_ptr<linphone
|
|||
}
|
||||
}
|
||||
qInfo() << log().arg("Adding Friend:") << linphoneFriend.get();
|
||||
friendList->addFriend(linphoneFriend);
|
||||
if (friendList) friendList->addFriend(linphoneFriend);
|
||||
emit CoreModel::getInstance()->friendCreated(linphoneFriend);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,6 +172,7 @@ void SettingsModel::stopCaptureGraph() {
|
|||
void SettingsModel::accessCallSettings() {
|
||||
// Audio
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
startCaptureGraph();
|
||||
CoreModel::getInstance()->getCore()->reloadSoundDevices();
|
||||
emit captureDevicesChanged(getCaptureDevices());
|
||||
emit playbackDevicesChanged(getPlaybackDevices());
|
||||
|
|
@ -182,7 +183,6 @@ void SettingsModel::accessCallSettings() {
|
|||
emit playbackGainChanged(getPlaybackGain());
|
||||
emit captureGainChanged(getCaptureGain());
|
||||
|
||||
startCaptureGraph();
|
||||
// Video
|
||||
CoreModel::getInstance()->getCore()->reloadVideoDevices();
|
||||
emit videoDevicesChanged(getVideoDevices());
|
||||
|
|
@ -202,13 +202,12 @@ bool SettingsModel::getCaptureGraphRunning() {
|
|||
float SettingsModel::getMicVolume() {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
float v = 0.0;
|
||||
|
||||
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
|
||||
v = mSimpleCaptureGraph->getCaptureVolume();
|
||||
} else {
|
||||
auto call = CoreModel::getInstance()->getCore()->getCurrentCall();
|
||||
if (call) {
|
||||
v = MediastreamerUtils::computeVu(call->getRecordVolume());
|
||||
v = call->getRecordVolume();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -218,33 +217,49 @@ float SettingsModel::getMicVolume() {
|
|||
|
||||
float SettingsModel::getPlaybackGain() const {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
float dbGain = CoreModel::getInstance()->getCore()->getPlaybackGainDb();
|
||||
return MediastreamerUtils::dbToLinear(dbGain);
|
||||
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
|
||||
return mSimpleCaptureGraph->getPlaybackGain();
|
||||
} else {
|
||||
auto call = CoreModel::getInstance()->getCore()->getCurrentCall();
|
||||
if (call) return call->getSpeakerVolumeGain();
|
||||
else return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsModel::setPlaybackGain(float gain) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
float oldGain = getPlaybackGain();
|
||||
CoreModel::getInstance()->getCore()->setPlaybackGainDb(MediastreamerUtils::linearToDb(gain));
|
||||
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
|
||||
mSimpleCaptureGraph->setPlaybackGain(gain);
|
||||
}
|
||||
auto currentCall = CoreModel::getInstance()->getCore()->getCurrentCall();
|
||||
if (currentCall) {
|
||||
currentCall->setSpeakerVolumeGain(gain);
|
||||
}
|
||||
if ((int)(oldGain * 1000) != (int)(gain * 1000)) emit playbackGainChanged(gain);
|
||||
}
|
||||
|
||||
float SettingsModel::getCaptureGain() const {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
float dbGain = CoreModel::getInstance()->getCore()->getMicGainDb();
|
||||
return MediastreamerUtils::dbToLinear(dbGain);
|
||||
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
|
||||
return mSimpleCaptureGraph->getCaptureGain();
|
||||
} else {
|
||||
auto call = CoreModel::getInstance()->getCore()->getCurrentCall();
|
||||
if (call) return call->getMicrophoneVolumeGain();
|
||||
else return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsModel::setCaptureGain(float gain) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
float oldGain = getCaptureGain();
|
||||
CoreModel::getInstance()->getCore()->setMicGainDb(MediastreamerUtils::linearToDb(gain));
|
||||
if (mSimpleCaptureGraph && mSimpleCaptureGraph->isRunning()) {
|
||||
mSimpleCaptureGraph->setCaptureGain(gain);
|
||||
}
|
||||
auto currentCall = CoreModel::getInstance()->getCore()->getCurrentCall();
|
||||
if (currentCall) {
|
||||
currentCall->setMicrophoneVolumeGain(gain);
|
||||
}
|
||||
if ((int)(oldGain * 1000) != (int)(gain * 1000)) emit captureGainChanged(gain);
|
||||
}
|
||||
|
||||
|
|
@ -256,6 +271,8 @@ QVariantList SettingsModel::getCaptureDevices() const {
|
|||
for (const auto &device : core->getExtendedAudioDevices()) {
|
||||
if (device->hasCapability(linphone::AudioDevice::Capabilities::CapabilityRecord)) {
|
||||
list << ToolModel::createVariant(device);
|
||||
} else if (device->hasCapability(linphone::AudioDevice::Capabilities::CapabilityAll)) {
|
||||
list << ToolModel::createVariant(device);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
|
|
@ -267,8 +284,11 @@ QVariantList SettingsModel::getPlaybackDevices() const {
|
|||
QVariantList list;
|
||||
|
||||
for (const auto &device : core->getExtendedAudioDevices()) {
|
||||
if (device->hasCapability(linphone::AudioDevice::Capabilities::CapabilityPlay))
|
||||
if (device->hasCapability(linphone::AudioDevice::Capabilities::CapabilityPlay)) {
|
||||
list << ToolModel::createVariant(device);
|
||||
} else if (device->hasCapability(linphone::AudioDevice::Capabilities::CapabilityAll)) {
|
||||
list << ToolModel::createVariant(device);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
|
|
@ -706,6 +726,20 @@ QString SettingsModel::getDefaultDomain() const {
|
|||
mConfig->getString(SettingsModel::AppSection, "default_domain", "sip.linphone.org"));
|
||||
}
|
||||
|
||||
bool SettingsModel::isSystrayNotificationBlinkEnabled() const {
|
||||
return !!mConfig->getInt(UiSection, "systray_notification_blink", 1);
|
||||
}
|
||||
|
||||
bool SettingsModel::isSystrayNotificationGlobal() const {
|
||||
return !!mConfig->getInt(UiSection, "systray_notification_global", 1);
|
||||
}
|
||||
|
||||
bool SettingsModel::isSystrayNotificationFiltered() const {
|
||||
return !!mConfig->getInt(UiSection, "systray_notification_filtered", 0);
|
||||
}
|
||||
bool SettingsModel::getLimeIsSupported() const {
|
||||
return CoreModel::getInstance()->getCore()->limeX3DhAvailable();
|
||||
}
|
||||
// clang-format off
|
||||
void SettingsModel::notifyConfigReady(){
|
||||
DEFINE_NOTIFY_CONFIG_READY(disableChatFeature, DisableChatFeature)
|
||||
|
|
@ -717,7 +751,7 @@ void SettingsModel::notifyConfigReady(){
|
|||
DEFINE_NOTIFY_CONFIG_READY(assistantHideCreateAccount, AssistantHideCreateAccount)
|
||||
DEFINE_NOTIFY_CONFIG_READY(assistantDisableQrCode, AssistantDisableQrCode)
|
||||
DEFINE_NOTIFY_CONFIG_READY(assistantHideThirdPartyAccount, AssistantHideThirdPartyAccount)
|
||||
DEFINE_NOTIFY_CONFIG_READY(onlyDisplaySipUriUsername, OnlyDisplaySipUriUsername)
|
||||
DEFINE_NOTIFY_CONFIG_READY(hideSipAddresses, HideSipAddresses)
|
||||
DEFINE_NOTIFY_CONFIG_READY(darkModeAllowed, DarkModeAllowed)
|
||||
DEFINE_NOTIFY_CONFIG_READY(assistantGoDirectlyToThirdPartySipAccountLogin,
|
||||
AssistantGoDirectlyToThirdPartySipAccountLogin)
|
||||
|
|
@ -779,9 +813,9 @@ DEFINE_GETSET_CONFIG(SettingsModel,
|
|||
DEFINE_GETSET_CONFIG(SettingsModel,
|
||||
bool,
|
||||
Bool,
|
||||
onlyDisplaySipUriUsername,
|
||||
OnlyDisplaySipUriUsername,
|
||||
"only_display_sip_uri_username",
|
||||
hideSipAddresses,
|
||||
HideSipAddresses,
|
||||
"hide_sip_addresses",
|
||||
false)
|
||||
DEFINE_GETSET_CONFIG(SettingsModel,
|
||||
bool,
|
||||
|
|
|
|||
|
|
@ -157,6 +157,11 @@ public:
|
|||
|
||||
static bool clearLocalLdapFriendsUponStartup(const std::shared_ptr<linphone::Config> &config);
|
||||
|
||||
bool isSystrayNotificationBlinkEnabled() const;
|
||||
bool isSystrayNotificationGlobal() const;
|
||||
bool isSystrayNotificationFiltered() const;
|
||||
bool getLimeIsSupported() const;
|
||||
|
||||
// UI
|
||||
DECLARE_GETSET(bool, disableChatFeature, DisableChatFeature)
|
||||
DECLARE_GETSET(bool, disableMeetingsFeature, DisableMeetingsFeature)
|
||||
|
|
@ -168,7 +173,7 @@ public:
|
|||
DECLARE_GETSET(bool, assistantHideCreateAccount, AssistantHideCreateAccount)
|
||||
DECLARE_GETSET(bool, assistantDisableQrCode, AssistantDisableQrCode)
|
||||
DECLARE_GETSET(bool, assistantHideThirdPartyAccount, AssistantHideThirdPartyAccount)
|
||||
DECLARE_GETSET(bool, onlyDisplaySipUriUsername, OnlyDisplaySipUriUsername)
|
||||
DECLARE_GETSET(bool, hideSipAddresses, HideSipAddresses)
|
||||
DECLARE_GETSET(bool, darkModeAllowed, DarkModeAllowed)
|
||||
DECLARE_GETSET(int, maxAccount, MaxAccount)
|
||||
DECLARE_GETSET(bool, assistantGoDirectlyToThirdPartySipAccountLogin, AssistantGoDirectlyToThirdPartySipAccountLogin)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "ToolModel.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/conference/ConferenceInfoCore.hpp"
|
||||
#include "core/path/Paths.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "model/friend/FriendsManager.hpp"
|
||||
|
|
@ -120,20 +121,18 @@ std::shared_ptr<linphone::Friend> ToolModel::findFriendByAddress(const QString &
|
|||
auto defaultFriendList = CoreModel::getInstance()->getCore()->getDefaultFriendList();
|
||||
if (!defaultFriendList) return nullptr;
|
||||
auto linphoneAddr = ToolModel::interpretUrl(address);
|
||||
if (linphoneAddr)
|
||||
return ToolModel::findFriendByAddress(linphoneAddr);
|
||||
else
|
||||
return nullptr;
|
||||
if (linphoneAddr) return ToolModel::findFriendByAddress(linphoneAddr);
|
||||
else return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<linphone::Friend> ToolModel::findFriendByAddress(std::shared_ptr<linphone::Address> linphoneAddr) {
|
||||
auto friendsManager = FriendsManager::getInstance();
|
||||
QString key = Utils::coreStringToAppString(linphoneAddr->asStringUriOnly());
|
||||
if (friendsManager->isInKnownFriends(key)) {
|
||||
// qDebug() << key << "have been found in known friend, return it";
|
||||
// qDebug() << key << "have been found in known friend, return it";
|
||||
return friendsManager->getKnownFriendAtKey(key);
|
||||
} else if (friendsManager->isInUnknownFriends(key)) {
|
||||
// qDebug() << key << "have been found in unknown friend, return it";
|
||||
} else if (friendsManager->isInUnknownFriends(key)) {
|
||||
// qDebug() << key << "have been found in unknown friend, return it";
|
||||
return friendsManager->getUnknownFriendAtKey(key);
|
||||
}
|
||||
auto f = CoreModel::getInstance()->getCore()->findFriend(linphoneAddr);
|
||||
|
|
@ -141,20 +140,21 @@ std::shared_ptr<linphone::Friend> ToolModel::findFriendByAddress(std::shared_ptr
|
|||
if (friendsManager->isInUnknownFriends(key)) {
|
||||
friendsManager->removeUnknownFriend(key);
|
||||
}
|
||||
// qDebug() << "found friend, add to known map";
|
||||
// qDebug() << "found friend, add to known map";
|
||||
friendsManager->appendKnownFriend(linphoneAddr, f);
|
||||
}
|
||||
if (!f) {
|
||||
if (friendsManager->isInOtherAddresses(key)) {
|
||||
// qDebug() << "A magic search has already be done for address" << key << "and nothing was found, return";
|
||||
// qDebug() << "A magic search has already be done for address" << key << "and nothing was found,
|
||||
// return";
|
||||
return nullptr;
|
||||
}
|
||||
friendsManager->appendOtherAddress(key);
|
||||
// qDebug() << "Couldn't find friend" << linphoneAddr->asStringUriOnly() << "in core, use magic search";
|
||||
// qDebug() << "Couldn't find friend" << linphoneAddr->asStringUriOnly() << "in core, use magic search";
|
||||
CoreModel::getInstance()->searchInMagicSearch(Utils::coreStringToAppString(linphoneAddr->asStringUriOnly()),
|
||||
(int)linphone::MagicSearch::Source::LdapServers
|
||||
| (int)linphone::MagicSearch::Source::RemoteCardDAV
|
||||
, LinphoneEnums::MagicSearchAggregation::Friend, 50);
|
||||
(int)linphone::MagicSearch::Source::LdapServers |
|
||||
(int)linphone::MagicSearch::Source::RemoteCardDAV,
|
||||
LinphoneEnums::MagicSearchAggregation::Friend, 50);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
|
@ -378,6 +378,7 @@ std::shared_ptr<linphone::FriendList> ToolModel::getLdapFriendList() {
|
|||
|
||||
bool ToolModel::friendIsInFriendList(const std::shared_ptr<linphone::FriendList> &friendList,
|
||||
const std::shared_ptr<linphone::Friend> &f) {
|
||||
if (!friendList) return false;
|
||||
auto friends = friendList->getFriends();
|
||||
auto it = std::find_if(friends.begin(), friends.end(),
|
||||
[f](std::shared_ptr<linphone::Friend> linFriend) { return linFriend == f; });
|
||||
|
|
|
|||
|
|
@ -36,10 +36,13 @@
|
|||
#include <limits.h>
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QColor>
|
||||
#include <QCryptographicHash>
|
||||
#include <QDesktopServices>
|
||||
#include <QHostAddress>
|
||||
#include <QImageReader>
|
||||
#include <QQmlComponent>
|
||||
#include <QQmlProperty>
|
||||
#include <QQuickWindow>
|
||||
#include <QRandomGenerator>
|
||||
#include <QRegularExpression>
|
||||
|
|
@ -425,6 +428,25 @@ VariantObject *Utils::findFriendByAddress(const QString &address) {
|
|||
return data;
|
||||
}
|
||||
|
||||
VariantObject *Utils::getFriendSecurityLevel(const QString &address) {
|
||||
VariantObject *data = new VariantObject("getFriendAddressSecurityLevel");
|
||||
if (!data) return nullptr;
|
||||
data->makeRequest([address]() {
|
||||
auto defaultFriendList = ToolModel::getAppFriendList();
|
||||
if (!defaultFriendList) return QVariant();
|
||||
auto linphoneAddr = ToolModel::interpretUrl(address);
|
||||
auto linFriend = CoreModel::getInstance()->getCore()->findFriend(linphoneAddr);
|
||||
if (!linFriend) return QVariant();
|
||||
auto linAddr = ToolModel::interpretUrl(address);
|
||||
if (!linAddr) return QVariant();
|
||||
auto devices = linFriend->getDevicesForAddress(linphoneAddr);
|
||||
int verified = 0;
|
||||
return QVariant::fromValue(LinphoneEnums::fromLinphone(linFriend->getSecurityLevel()));
|
||||
});
|
||||
data->requestValue();
|
||||
return data;
|
||||
}
|
||||
|
||||
VariantObject *Utils::getFriendAddressSecurityLevel(const QString &address) {
|
||||
VariantObject *data = new VariantObject("getFriendAddressSecurityLevel");
|
||||
if (!data) return nullptr;
|
||||
|
|
@ -532,6 +554,16 @@ QString Utils::getOsProduct() {
|
|||
return product + "/" + version;
|
||||
}
|
||||
|
||||
QColor Utils::getDefaultStyleColor(const QString &colorName) {
|
||||
mustBeInMainThread(sLog().arg(Q_FUNC_INFO));
|
||||
static QObject *defaultStyleSingleton = nullptr;
|
||||
if (!defaultStyleSingleton) {
|
||||
QQmlComponent component(App::getInstance()->mEngine, QUrl("qrc:/qt/qml/Linphone/view/Style/DefaultStyle.qml"));
|
||||
defaultStyleSingleton = component.create();
|
||||
}
|
||||
return QQmlProperty::read(defaultStyleSingleton, colorName).value<QColor>();
|
||||
}
|
||||
|
||||
QString Utils::getCountryName(const QLocale::Territory &p_country) {
|
||||
QString countryName;
|
||||
switch (p_country) {
|
||||
|
|
@ -1440,7 +1472,7 @@ QList<QVariant> Utils::append(const QList<QVariant> a, const QList<QVariant> b)
|
|||
|
||||
QString Utils::getAddressToDisplay(QVariantList addressList, QString filter, QString defaultAddress) {
|
||||
if (filter.isEmpty()) return defaultAddress;
|
||||
for (auto& item: addressList) {
|
||||
for (auto &item : addressList) {
|
||||
QString address = item.toMap()["address"].toString();
|
||||
if (address.contains(filter)) return address;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ public:
|
|||
Q_INVOKABLE static VariantObject *findAvatarByAddress(const QString &address);
|
||||
Q_INVOKABLE static VariantObject *findFriendByAddress(const QString &address);
|
||||
Q_INVOKABLE static VariantObject *getFriendAddressSecurityLevel(const QString &address);
|
||||
Q_INVOKABLE static VariantObject *getFriendSecurityLevel(const QString &address);
|
||||
static QString generateSavedFilename(const QString &from, const QString &to);
|
||||
Q_INVOKABLE static VariantObject *isMe(const QString &address);
|
||||
Q_INVOKABLE static VariantObject *isLocal(const QString &address);
|
||||
|
|
@ -145,6 +146,8 @@ public:
|
|||
static QString getApplicationProduct();
|
||||
static QString getOsProduct();
|
||||
|
||||
static QColor getDefaultStyleColor(const QString &colorName);
|
||||
|
||||
static QList<QSharedPointer<DownloadablePayloadTypeCore>> getDownloadableVideoPayloadTypes();
|
||||
static void checkDownloadedCodecsUpdates();
|
||||
|
||||
|
|
|
|||
|
|
@ -155,6 +155,10 @@ Button {
|
|||
if (y < mainItem.height && y + popupHeight > 0) {
|
||||
x += mainItem.width
|
||||
}
|
||||
var globalPos = mapToItem(mainItem.Window.contentItem, x, y)
|
||||
if (globalPos.x + popupWidth >= mainItem.Window.width) {
|
||||
x = -popupWidth
|
||||
}
|
||||
}
|
||||
|
||||
onHeightChanged: Qt.callLater(updatePosition)
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ ColumnLayout {
|
|||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: mainItem.specificAddress != ""
|
||||
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(mainItem.specificAddress) : mainItem.specificAddress
|
||||
text: SettingsCpp.hideSipAddresses ? UtilsCpp.getUsername(mainItem.specificAddress) : mainItem.specificAddress
|
||||
elide: Text.ElideMiddle
|
||||
maximumLineCount: 1
|
||||
font {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ Control.TabBar {
|
|||
|
||||
contentItem: Text {
|
||||
id: tabText
|
||||
width: Math.min(implicitWidth, mainItem.width / mainItem.model.length)
|
||||
width: implicitWidth
|
||||
font.weight: mainItem.textWeight
|
||||
color: mainItem.currentIndex === index ? DefaultStyle.main2_600 : DefaultStyle.main2_400
|
||||
font.family: DefaultStyle.defaultFont
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ ListView {
|
|||
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
|
||||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||
_address: modelData.core.remoteAddress
|
||||
secured: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
isConference: modelData.core.isConference
|
||||
shadowEnabled: false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ Flickable {
|
|||
flickableDirection: Flickable.VerticalFlick
|
||||
|
||||
property bool showInitials: true // Display Initials of Display name.
|
||||
property bool showDefaultAddress: true // Display address below display name.
|
||||
property bool showActions: false // Display actions layout (call buttons)
|
||||
property bool showContactMenu: true // Display the dot menu for contacts.
|
||||
property bool showFavorites: true // Display the favorites in the header
|
||||
|
|
@ -269,7 +268,7 @@ Flickable {
|
|||
showActions: mainItem.showActions
|
||||
showInitials: mainItem.showInitials
|
||||
showContactMenu: mainItem.showContactMenu
|
||||
showDefaultAddress: mainItem.showDefaultAddress
|
||||
showDefaultAddress: false
|
||||
selectionEnabled: mainItem.selectionEnabled
|
||||
multiSelectionEnabled: mainItem.multiSelectionEnabled
|
||||
selectedContacts: mainItem.selectedContacts
|
||||
|
|
@ -315,7 +314,7 @@ Flickable {
|
|||
showActions: mainItem.showActions
|
||||
showInitials: mainItem.showInitials
|
||||
showContactMenu: mainItem.showContactMenu
|
||||
showDefaultAddress: mainItem.showDefaultAddress
|
||||
showDefaultAddress: false
|
||||
selectionEnabled: mainItem.selectionEnabled
|
||||
multiSelectionEnabled: mainItem.multiSelectionEnabled
|
||||
selectedContacts: mainItem.selectedContacts
|
||||
|
|
@ -368,7 +367,8 @@ Flickable {
|
|||
highlightText: mainItem.highlightText
|
||||
showActions: mainItem.showActions
|
||||
showContactMenu: mainItem.showContactMenu
|
||||
showDefaultAddress: mainItem.showDefaultAddress
|
||||
showDefaultAddress: true
|
||||
showDisplayName: false
|
||||
selectionEnabled: mainItem.selectionEnabled
|
||||
multiSelectionEnabled: mainItem.multiSelectionEnabled
|
||||
selectedContacts: mainItem.selectedContacts
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ Loader{
|
|||
: contact
|
||||
? contact.core.defaultAddress
|
||||
: ''
|
||||
readonly property string address: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_address) : _address
|
||||
readonly property string address: SettingsCpp.hideSipAddresses ? UtilsCpp.getUsername(_address) : _address
|
||||
property var displayNameObj: UtilsCpp.getDisplayName(_address)
|
||||
property string displayNameVal: account && account.core.displayName
|
||||
? account.core.displayName
|
||||
|
|
@ -40,6 +40,11 @@ Loader{
|
|||
: computedAvatarUri.length != 0
|
||||
property var avatarObj: UtilsCpp.findAvatarByAddress(_address)
|
||||
property string computedAvatarUri: avatarObj ? avatarObj.value : ''
|
||||
|
||||
// To get the secured property for a friend using an address to find it,
|
||||
// override it as secured: friendSecurityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
property var friendSecurityLevelObj: UtilsCpp.getFriendSecurityLevel(_address)
|
||||
property var friendSecurityLevel: friendSecurityLevelObj ? securityLevelObj.value : LinphoneEnums.SecurityLevel.None
|
||||
|
||||
// To get the secured property for a specific address,
|
||||
// override it as secured: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ FocusScope {
|
|||
property var searchResultItem
|
||||
property bool showInitials: true // Display Initials of Display name.
|
||||
property bool showDefaultAddress: true // Display address below display name.
|
||||
property bool showDisplayName: true // Display name above address.
|
||||
property bool showActions: false // Display actions layout (call buttons)
|
||||
property bool showContactMenu: true // Display the dot menu for contacts.
|
||||
property string highlightText
|
||||
|
|
@ -34,8 +35,7 @@ FocusScope {
|
|||
property real itemsRightMargin: Math.round(39 * DefaultStyle.dp)
|
||||
|
||||
property var displayName: searchResultItem.core.fullName
|
||||
property string initial: displayName ? displayName[0].toLocaleLowerCase(
|
||||
ConstantsCpp.DefaultLocale) : ''
|
||||
property var initial: displayName ? displayName[0].toLocaleLowerCase(ConstantsCpp.DefaultLocale) : ''
|
||||
|
||||
signal clicked(var mouse)
|
||||
signal contactDeletionRequested(FriendGui contact)
|
||||
|
|
@ -50,7 +50,7 @@ FocusScope {
|
|||
verticalAlignment: Text.AlignVCenter
|
||||
width: Math.round(20 * DefaultStyle.dp)
|
||||
opacity: previousInitial != mainItem.initial ? 1 : 0
|
||||
text: mainItem.initial
|
||||
text: mainItem.initial || ""
|
||||
color: DefaultStyle.main2_400
|
||||
font {
|
||||
pixelSize: Math.round(20 * DefaultStyle.dp)
|
||||
|
|
@ -77,6 +77,10 @@ FocusScope {
|
|||
ColumnLayout {
|
||||
spacing: 0
|
||||
Text {
|
||||
id: displayNameText
|
||||
visible: mainItem.showDisplayName
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: visible ? implicitHeight: 0
|
||||
text: UtilsCpp.boldTextPart(mainItem.displayName,
|
||||
mainItem.highlightText)
|
||||
font {
|
||||
|
|
@ -85,13 +89,13 @@ FocusScope {
|
|||
weight: mainItem.showDefaultAddress ? Typography.h4.weight : Typography.p1.weight
|
||||
}
|
||||
maximumLineCount: 1
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text {
|
||||
Layout.topMargin: Math.round(2 * DefaultStyle.dp)
|
||||
Layout.topMargin: displayNameText.visible ? Math.round(2 * DefaultStyle.dp) : 0
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: visible ? implicitHeight: 0
|
||||
visible: mainItem.showDefaultAddress
|
||||
property string address: SettingsCpp.onlyDisplaySipUriUsername
|
||||
property string address: SettingsCpp.hideSipAddresses
|
||||
? UtilsCpp.getUsername(mainItem.addressFromFilter)
|
||||
: mainItem.addressFromFilter
|
||||
text: UtilsCpp.boldTextPart(address, mainItem.highlightText)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ ListView {
|
|||
property string title
|
||||
property bool showInitials: true // Display Initials of Display name.
|
||||
property bool showDefaultAddress: true // Display address below display name.
|
||||
property bool showDisplayName: true // Display name above address.
|
||||
property bool showActions: false // Display actions layout (call buttons)
|
||||
property bool showContactMenu: true // Display the dot menu for contacts.
|
||||
property bool showFavorites: true // Display the favorites in the header
|
||||
|
|
@ -195,6 +196,7 @@ ListView {
|
|||
searchResultItem: $modelData
|
||||
showInitials: mainItem.showInitials && isStored
|
||||
showDefaultAddress: mainItem.showDefaultAddress
|
||||
showDisplayName: mainItem.showDisplayName
|
||||
showActions: mainItem.showActions
|
||||
showContactMenu: mainItem.showContactMenu && searchResultItem.core.isStored
|
||||
highlightText: mainItem.highlightText
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ Rectangle{
|
|||
EffectImage {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Math.round(1.5 * DefaultStyle.dp) * scaleFactor
|
||||
imageSource: AppIcons.bellMwi
|
||||
imageSource: AppIcons.bell
|
||||
colorizationColor: DefaultStyle.grey_0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ ListView {
|
|||
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
|
||||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||
_address: modelData.core.address
|
||||
secured: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
shadowEnabled: false
|
||||
}
|
||||
Text {
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ ListView {
|
|||
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
|
||||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||
_address: modelData.core.sipAddress
|
||||
secured: friendSecurityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
shadowEnabled: false
|
||||
}
|
||||
Text {
|
||||
|
|
|
|||
|
|
@ -59,8 +59,10 @@ Item {
|
|||
Text {
|
||||
anchors.margins: 25
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: titleText
|
||||
maximumLineCount: 1
|
||||
font: Typography.h4
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ Item {
|
|||
call: !mainItem.previewEnabled ? mainItem.call : null
|
||||
displayNameVal: mainItem.displayName
|
||||
securityBreach: mainItem.securityBreach ? mainItem.securityBreach : securityLevel === LinphoneEnums.SecurityLevel.Unsafe
|
||||
secured: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
}
|
||||
ColumnLayout{
|
||||
id: joiningView
|
||||
|
|
@ -183,7 +184,7 @@ Item {
|
|||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
property string _text: mainItem.call && mainItem.call.core.remoteAddress
|
||||
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_text) : _text
|
||||
text: SettingsCpp.hideSipAddresses ? UtilsCpp.getUsername(_text) : _text
|
||||
color: DefaultStyle.grey_0
|
||||
font {
|
||||
pixelSize: Math.round(14 * DefaultStyle.dp)
|
||||
|
|
@ -260,7 +261,7 @@ Item {
|
|||
: mainItem.account && mainItem.identityAddress
|
||||
? mainItem.identityAddress.value
|
||||
: ""
|
||||
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_text) : _text
|
||||
text: SettingsCpp.hideSipAddresses ? UtilsCpp.getUsername(_text) : _text
|
||||
color: DefaultStyle.grey_0
|
||||
font {
|
||||
pixelSize: Math.round(14 * DefaultStyle.dp)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ Quick.Text {
|
|||
family: DefaultStyle.defaultFont
|
||||
pixelSize: Math.round(10 * DefaultStyle.dp)
|
||||
weight: Typography.p1.weight
|
||||
bold: true
|
||||
}
|
||||
color: DefaultStyle.main2_600
|
||||
wrapMode: Quick.Text.Wrap
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ import Qt.labs.platform
|
|||
property bool isFrameLess : false;
|
||||
property bool showAsTool : false
|
||||
// Don't use Popup for flags : it could lead to error in geometry. On Mac, Using Tool ensure to have the Window on Top and fullscreen independant
|
||||
flags: Qt.BypassWindowManagerHint | (showAsTool?Qt.Tool:Qt.WindowStaysOnTopHint) | Qt.Window | Qt.FramelessWindowHint;
|
||||
// flags: Qt.WindowDoesNotAcceptFocus | Qt.BypassWindowManagerHint | (showAsTool?Qt.Tool:Qt.WindowStaysOnTopHint) | Qt.Window | Qt.FramelessWindowHint;
|
||||
flags: Qt.Popup | Qt.Dialog | Qt.WindowDoesNotAcceptFocus | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint
|
||||
opacity: 1.0
|
||||
height: _content[0] != null ? _content[0].height : 0
|
||||
width: _content[0] != null ? _content[0].width : 0
|
||||
|
|
|
|||
|
|
@ -72,7 +72,6 @@ Dialog {
|
|||
id: passwordEdit
|
||||
hidden: true
|
||||
isError: passwordItem.errorTextVisible
|
||||
KeyNavigation.up: usernameEdit
|
||||
KeyNavigation.down: cancelButton
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ Notification {
|
|||
Layout.preferredHeight: Math.round(60 * DefaultStyle.dp)
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
call: mainItem.call
|
||||
secured: securityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
isConference: mainItem.call && mainItem.call.core.isConference
|
||||
}
|
||||
ColumnLayout {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ ColumnLayout{
|
|||
id: mainItem
|
||||
property AccountGui account: null
|
||||
property string topText: account ? account.core.displayName : ""
|
||||
property string bottomText: account ? SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(account.core.identityAddress) : account.core.identityAddress : ""
|
||||
property string bottomText: account ? SettingsCpp.hideSipAddresses ? UtilsCpp.getUsername(account.core.identityAddress) : account.core.identityAddress : ""
|
||||
spacing: 0
|
||||
width: topTextItem.implicitWidth
|
||||
Text {
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ MainRightPanel {
|
|||
if (text.length != 0) mainItem.contact.core.setAddressAt(index, label, text)
|
||||
}
|
||||
property string _initialText: modelData.address
|
||||
initialText: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_initialText) : _initialText
|
||||
initialText: SettingsCpp.hideSipAddresses ? UtilsCpp.getUsername(_initialText) : _initialText
|
||||
backgroundColor: DefaultStyle.grey_0
|
||||
focus: true
|
||||
KeyNavigation.right: removeAddressButton
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ FocusScope{
|
|||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||
_address: modelData
|
||||
shadowEnabled: false
|
||||
secured: friendSecurityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
}
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@ FocusScope {
|
|||
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
|
||||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||
_address: modelData.address
|
||||
secured: friendSecurityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
shadowEnabled: false
|
||||
}
|
||||
Text {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ AbstractMainPage {
|
|||
text: titleText
|
||||
color: DefaultStyle.main2_700
|
||||
font: Typography.h3
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -67,6 +68,7 @@ AbstractMainPage {
|
|||
|
||||
delegate: SettingsMenuItem {
|
||||
titleText: modelData.title
|
||||
width: familiesList.width
|
||||
visible: modelData.visible != undefined ? modelData.visible : true
|
||||
isSelected: familiesList.selectedIndex == index
|
||||
focus: index == 0
|
||||
|
|
|
|||
|
|
@ -19,8 +19,10 @@ AbstractSettingsMenu {
|
|||
{title: qsTr("settings_contacts_title"), layout: "ContactsSettingsLayout"},
|
||||
//: "Réunions"
|
||||
{title: qsTr("settings_meetings_title"), layout: "MeetingsSettingsLayout", visible: !SettingsCpp.disableMeetingsFeature},
|
||||
//: "Affichage"
|
||||
////: "Affichage"
|
||||
//{title: qsTr("settings_user_interface_title"), layout: "DisplaySettingsLayout"},
|
||||
//: "Security"
|
||||
{title: qsTr("settings_security_title"), layout: "SecuritySettingsLayout"},
|
||||
//: "Réseau"
|
||||
{title: qsTr("settings_network_title"), layout: "NetworkSettingsLayout"},
|
||||
//: "Paramètres avancés"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,3 @@
|
|||
|
||||
|
||||
/**
|
||||
* Qml template used for welcome and login/register pages
|
||||
**/
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
|
|
@ -99,10 +94,16 @@ Item {
|
|||
x: mainItem.width / 2 - width / 2
|
||||
y: contentItem.height / 2
|
||||
property var currentCall: callsModel.currentCall ? callsModel.currentCall : null
|
||||
property var conference: currentCall ? currentCall.core.conference : null
|
||||
property string remoteName: currentCall ? currentCall.core.remoteName : ""
|
||||
property string subject: conference ? conference.core.subject : ''
|
||||
contentItem: MediumButton {
|
||||
style: ButtonStyle.toast
|
||||
text: currentCallNotif.currentCall ? currentCallNotif.currentCall.core.conference ? ("Réunion en cours : ") + currentCallNotif.currentCall.core.conference.core.subject : (("Appel en cours : ") + currentCallNotif.remoteName) : "appel en cours"
|
||||
text: currentCallNotif.currentCall
|
||||
? currentCallNotif.conference
|
||||
? ("Réunion en cours : ") + currentCallNotif.subject
|
||||
: (("Appel en cours : ") + currentCallNotif.remoteName)
|
||||
: "appel en cours"
|
||||
onClicked: {
|
||||
var callsWindow = UtilsCpp.getCallsWindow(
|
||||
currentCallNotif.currentCall)
|
||||
|
|
@ -178,6 +179,7 @@ Item {
|
|||
}
|
||||
initButtons()
|
||||
currentIndex = SettingsCpp.getLastActiveTabIndex()
|
||||
if (currentIndex === -1) currentIndex = 0
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
|
|
@ -267,7 +269,6 @@ Item {
|
|||
showActions: true
|
||||
showFavorites: false
|
||||
selectionEnabled: false
|
||||
showDefaultAddress: true
|
||||
searchOnEmpty: false
|
||||
|
||||
sectionsPixelSize: Typography.p2.pixelSize
|
||||
|
|
@ -459,8 +460,7 @@ Item {
|
|||
icon.height: Math.round(32 * DefaultStyle.dp)
|
||||
text: qsTr("settings_title")
|
||||
icon.source: AppIcons.settings
|
||||
onClicked: openContextualMenuComponent(
|
||||
settingsPageComponent)
|
||||
onClicked: openContextualMenuComponent(settingsPageComponent)
|
||||
KeyNavigation.up: visibleChildren.length
|
||||
!= 0 ? settingsMenuButton.getPreviousItem(
|
||||
2) : null
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import QtQuick.Layouts
|
|||
import QtQuick.Controls.Basic as Control
|
||||
import SettingsCpp 1.0
|
||||
import Linphone
|
||||
import UtilsCpp
|
||||
|
||||
AbstractSettingsLayout {
|
||||
width: parent?.width
|
||||
|
|
|
|||
|
|
@ -290,7 +290,6 @@ FriendGui{
|
|||
Layout.rightMargin: Math.round(8 * DefaultStyle.dp)
|
||||
searchBarText: searchBar.text
|
||||
hideSuggestions: true
|
||||
showDefaultAddress: false
|
||||
sourceFlags: LinphoneEnums.MagicSearchSource.Friends
|
||||
| LinphoneEnums.MagicSearchSource.FavoriteFriends
|
||||
| LinphoneEnums.MagicSearchSource.LdapServers
|
||||
|
|
@ -536,7 +535,7 @@ FriendGui{
|
|||
Text {
|
||||
Layout.fillWidth: true
|
||||
property string _text: listViewModelData.address
|
||||
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(_text) : _text
|
||||
text: SettingsCpp.hideSipAddresses ? UtilsCpp.getUsername(_text) : _text
|
||||
font {
|
||||
pixelSize: Typography.p1.pixelSize
|
||||
weight: Typography.p1.weight
|
||||
|
|
|
|||
|
|
@ -764,6 +764,7 @@ AbstractMainPage {
|
|||
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
|
||||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||
_address: mainItem.selectedConference && mainItem.selectedConference.core ? mainItem.selectedConference.core.organizerAddress : ""
|
||||
secured: friendSecurityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
}
|
||||
Text {
|
||||
text: mainItem.selectedConference && mainItem.selectedConference.core ? mainItem.selectedConference.core.organizerName : ""
|
||||
|
|
@ -801,6 +802,7 @@ AbstractMainPage {
|
|||
Layout.preferredWidth: Math.round(45 * DefaultStyle.dp)
|
||||
Layout.preferredHeight: Math.round(45 * DefaultStyle.dp)
|
||||
_address: modelData.address
|
||||
secured: friendSecurityLevel === LinphoneEnums.SecurityLevel.EndToEndEncryptedAndVerified
|
||||
shadowEnabled: false
|
||||
}
|
||||
Text {
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ ApplicationWindow {
|
|||
}
|
||||
Text {
|
||||
Layout.leftMargin: Math.round(5 * DefaultStyle.dp)
|
||||
text: SettingsCpp.onlyDisplaySipUriUsername ? UtilsCpp.getUsername(modelData.address) : modelData.address
|
||||
text: SettingsCpp.hideSipAddresses ? UtilsCpp.getUsername(modelData.address) : modelData.address
|
||||
font {
|
||||
pixelSize: Typography.p1.pixelSize
|
||||
weight: Typography.p1.weight
|
||||
|
|
|
|||
|
|
@ -84,8 +84,6 @@ QtObject {
|
|||
property string mediaEncryptionZrtpPq: "image://internal/media_encryption_zrtp_pq.svg"
|
||||
property string pencil: "image://internal/pencil-simple.svg"
|
||||
property string shareNetwork: "image://internal/share-network.svg"
|
||||
property string bell: "image://internal/bell-simple.svg"
|
||||
property string bellSlash: "image://internal/bell-slash.svg"
|
||||
property string question: "image://internal/question.svg"
|
||||
property string settings: "image://internal/gear.svg"
|
||||
property string clock: "image://internal/clock.svg"
|
||||
|
|
@ -117,11 +115,12 @@ QtObject {
|
|||
property string mobile: "image://internal/device-mobile-camera.svg"
|
||||
property string desktop: "image://internal/desktop.svg"
|
||||
property string calendar: "image://internal/calendar-blank.svg"
|
||||
property string bell: "image://internal/bell.svg"
|
||||
property string bellSlash: "image://internal/bell-slash.svg"
|
||||
property string bellDnd: "image://internal/bell-dnd.svg"
|
||||
property string bellRinger: "image://internal/bell-ringer.svg"
|
||||
property string bellRinger: "image://internal/bell-ringing.svg"
|
||||
property string voicemail: "image://internal/voicemail.svg"
|
||||
property string power: "image://internal/power.svg"
|
||||
property string resourcePackage: "image://internal/package.svg"
|
||||
property string appWindow: "image://internal/app-window.svg"
|
||||
property string bellMwi: "image://internal/bell-simple.svg"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ else
|
|||
if [ -f "${WORK_DIR}/AppBin/appimagetool-x86_64.AppImage" ]; then
|
||||
echo "appimagetool-x86_64.AppImage exists"
|
||||
else
|
||||
wget -P "${WORK_DIR}/AppBin" https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
wget -P "${WORK_DIR}/AppBin" https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
chmod +x "${WORK_DIR}/AppBin/appimagetool-x86_64.AppImage"
|
||||
fi
|
||||
./${WORK_DIR}/AppBin/linuxdeploy-x86_64.AppImage --appimage-extract-and-run --appdir=${WORK_DIR}/AppDir -e ${WORK_DIR}/AppDir/usr/bin/${APP_NAME} --desktop-file=${WORK_DIR}/AppDir/usr/share/applications/${APP_NAME}.desktop -i ${WORK_DIR}/AppDir/usr/share/icons/hicolor/scalable/apps/${APP_NAME}.svg --plugin qt
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ ARG QT6_VERSION=6.8.0
|
|||
#Do not use it. It seems that it cannot be used from python command.
|
||||
#ARG QT_MODULES=qtnetworkauth qtquick3d qtmultimedia
|
||||
|
||||
MAINTAINER Gaelle Braud <gaelle.braud@belledonne-communications.com>
|
||||
LABEL Gaelle Braud <gaelle.braud@belledonne-communications.com>
|
||||
|
||||
# Use a Swiss mirror
|
||||
RUN sed -i -E 's/(archive|security)\.ubuntu\.com/ch.archive.ubuntu.com/' /etc/apt/sources.list
|
||||
|
|
|
|||
100
docker-files/bc-dev-ubuntu-22-04-lts
Normal file
100
docker-files/bc-dev-ubuntu-22-04-lts
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
###############################################################################
|
||||
# Dockerfile used to make gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-20-04-lts:20231024_add_multimedia
|
||||
###############################################################################
|
||||
|
||||
FROM ubuntu:22.04
|
||||
|
||||
# Qt on Ubuntu 22.04 is too old. Use a downloader.
|
||||
ARG QT_VERSION=5.15.2
|
||||
ARG QT6_VERSION=6.9.1
|
||||
#Do not use it. It seems that it cannot be used from python command.
|
||||
#ARG QT_MODULES=qtnetworkauth qtquick3d qtmultimedia qt5compat qtshadertools
|
||||
|
||||
LABEL Gaelle Braud <gaelle.braud@belledonne-communications.com>
|
||||
|
||||
# Use a Swiss mirror
|
||||
RUN sed -i -E 's/(archive|security)\.ubuntu\.com/ch.archive.ubuntu.com/' /etc/apt/sources.list
|
||||
|
||||
# add fallbacks for timeout connections.
|
||||
|
||||
#France
|
||||
RUN echo "deb http://fr.archive.ubuntu.com/ubuntu/ jammy main restricted" >> /etc/apt/sources.list
|
||||
RUN echo "deb http://security.ubuntu.com/ubuntu jammy-security main restricted" >> /etc/apt/sources.list
|
||||
RUN echo "deb http://ch.archive.ubuntu.com/ubuntu/ jammy-updates main restricted" >> /etc/apt/sources.list
|
||||
#Belgium
|
||||
RUN echo "deb http://be.archive.ubuntu.com/ubuntu/ jammy main restricted" >> /etc/apt/sources.list
|
||||
RUN echo "deb http://security.ubuntu.com/ubuntu jammy-security main restricted" >> /etc/apt/sources.list
|
||||
RUN echo "deb http://be.archive.ubuntu.com/ubuntu/ jammy-updates main restricted" >> /etc/apt/sources.list
|
||||
#International
|
||||
RUN echo "deb http://archive.ubuntu.com/ubuntu/ jammy main restricted" >> /etc/apt/sources.list
|
||||
RUN echo "deb http://security.ubuntu.com/ubuntu jammy-security main restricted" >> /etc/apt/sources.list
|
||||
RUN echo "deb http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted" >> /etc/apt/sources.list
|
||||
|
||||
# Configure locale
|
||||
RUN apt-get update && \
|
||||
apt-get install -y locales && \
|
||||
apt-get clean && \
|
||||
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && \
|
||||
locale-gen
|
||||
ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8'
|
||||
ENV TZ=Europe/Paris
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
ENV SHELL=/bin/bash
|
||||
#ENV PS1='\[\e[33m\]\u@bc-dev-ubuntu-20-04>\[\e[0m\] '
|
||||
|
||||
# Install common general tools
|
||||
RUN apt-get update && \
|
||||
apt-get install -y nano sudo vim && \
|
||||
apt-get clean
|
||||
|
||||
# Install development tools
|
||||
RUN apt-get update && \
|
||||
apt-get install -y alien at autoconf bison ccache clang doxygen elfutils g++ gdb git graphviz intltool libtool lsb-release make ninja-build openssh-client patch perl python3-pip python3-pystache python3-six python3-jsonschema python3-jinja2 meson yasm && \
|
||||
apt-get clean
|
||||
|
||||
# Install linphone & flexisip dependencies development packages
|
||||
RUN apt-get update && \
|
||||
apt-get install -y libasound2-dev libavcodec-dev libavutil-dev libbsd-dev libegl1-mesa-dev libglew-dev libgsm1-dev libjansson-dev libmariadb-dev-compat libmbedtls-dev libopus-dev libpq-dev libprotobuf-dev libpulse-dev libqt5svg5-dev libsnmp-dev libspeex-dev libspeexdsp-dev libsqlite3-dev libsrtp2-dev libssl-dev libswscale-dev libturbojpeg0-dev libv4l-dev libvpx-dev libxerces-c-dev libxml2-dev libxv-dev libxinerama-dev protobuf-compiler qttools5-dev qttools5-dev-tools xsdcxx cmake nasm && \
|
||||
apt-get clean
|
||||
|
||||
# Install signing tools
|
||||
RUN sudo apt-get install -y gnupg2
|
||||
|
||||
# Install configuration tools
|
||||
RUN sudo apt-get install -y wget
|
||||
|
||||
# Configure user bc
|
||||
RUN useradd -ms /bin/bash bc && \
|
||||
echo 'bc:cotcot' | chpasswd && \
|
||||
echo 'bc ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
||||
|
||||
########### QT
|
||||
|
||||
RUN sudo apt-get update && sudo apt-get install -y libxkbcommon* flite1-dev libspeechd-dev speech-dispatcher libfontconfig1-dev libfreetype6-dev libx11-dev libxext-dev libxfixes-dev libxi-dev libxrender-dev libx11-xcb* libxcb* qdbus-qt5 libqt5dbus5 libdbus-1-dev libdbus-glib-1-dev libatspi2.0-0 libatspi2.0-dev
|
||||
RUN sudo apt-get update && sudo apt-get install -y libxcb-keysyms1-dev libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync0-dev libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-render-util0-dev
|
||||
|
||||
USER bc
|
||||
WORKDIR /home/bc
|
||||
|
||||
# RUN sudo apt install python3-pip --upgrade -y
|
||||
RUN sudo apt install --upgrade -y python3-importlib-metadata
|
||||
RUN sudo apt install --upgrade -y python3-setuptools
|
||||
# RUN sudo apt install python3-ez_setup
|
||||
|
||||
## Install Qt download tool
|
||||
# installation is split because there is a way where some modules are not downloaded in the first attempt.
|
||||
RUN sudo apt install -y python3-py7zr
|
||||
RUN sudo pip3 install --upgrade aqtinstall
|
||||
RUN sudo python3 -m aqt install-qt linux desktop $QT_VERSION -O /opt/Qt
|
||||
RUN sudo python3 -m aqt install-qt linux desktop $QT_VERSION -O /opt/Qt --noarchives -m qtnetworkauth qtquick3d
|
||||
RUN sudo python3 -m aqt install-qt linux desktop $QT6_VERSION -O /opt/Qt
|
||||
RUN sudo python3 -m aqt install-qt linux desktop $QT6_VERSION -O /opt/Qt --noarchives -m qtnetworkauth qtquick3d qtmultimedia qt5compat qtshadertools
|
||||
|
||||
RUN sudo chown -R bc:bc /opt/Qt/
|
||||
|
||||
RUN qtchooser -install $QT_VERSION /opt/Qt/$QT_VERSION/gcc_64/bin/qmake
|
||||
RUN qtchooser -install $QT6_VERSION /opt/Qt/$QT6_VERSION/gcc_64/bin/qmake
|
||||
|
||||
CMD bash
|
||||
2
external/linphone-sdk
vendored
2
external/linphone-sdk
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 96a6385bfdb3e6c0ed85df42bda99467e8f6fc5f
|
||||
Subproject commit 52fa0abf7e60d1f7614b8ee8e8dbbee52f3f5f88
|
||||
Loading…
Add table
Reference in a new issue