Compare commits

..

20 commits

Author SHA1 Message Date
Peio Rigaux
1156bd78c0 Reduce rights of uploaded files 2026-01-15 12:19:56 +01:00
Ghislain MARY
befa4a2635 Add support of Jabra headsets via the hidapi library. 2026-01-06 17:27:11 +01:00
Christophe Deschamps
0cf3938dc3 Move Call Forward under the save scope in settings 2025-12-17 18:49:47 +01:00
Christophe Deschamps
c3b160ec3e Move Codecs under the save scope in settings 2025-12-17 18:49:41 +01:00
Christophe Deschamps
dc1ec216e8 Move FPS under the save scope in settings + fix the save popup showing when not saved 2025-12-17 18:49:35 +01:00
Christophe Deschamps
0bfa29dc55 Move AutoStart under the save scope in settings 2025-12-17 18:49:30 +01:00
Christophe Deschamps
0df7065b5e Move IPV6 under the save scope in settings 2025-12-17 18:49:23 +01:00
Gaelle Braud
6d9b5efcc5 hide current call in transfer call list #LINQT-2256 2025-12-15 15:58:22 +01:00
Christophe Deschamps
50ec67298e Update unread count when unread incoming message is retracted 2025-12-12 11:04:00 +01:00
Christophe Deschamps
1bae93aab5 Chat message edition 2025-12-11 15:41:40 +01:00
Christophe Deschamps
d40045d5bb Chat message retraction 2025-12-10 19:20:16 +00:00
Christophe Deschamps
13ec790648 Fix - when accessing and existing settings making no changes do not show Save? popup 2025-12-10 09:52:32 +01:00
gaelle
528dc1e2bd fix macos ci (use flat runner for SDK 5.5) 2025-12-09 14:28:09 +01:00
Julien Wadel
31726b46cd Fix unfound Microsoft runtimes while installing by removing the set on MSVC_VERSION that should be already set. 2025-12-09 12:48:55 +01:00
Sylvain Berfini
876fdbe619 Updated version code in CMakeLists to fix build since 6.2.0-alpha tag 2025-12-04 18:26:07 +01:00
Christophe Deschamps
e849891548 Update sdk 2025-12-04 16:16:06 +01:00
Christophe Deschamps
c672762b63 Option to set CCMP server URL in account settings 2025-12-04 15:41:59 +01:00
Christophe Deschamps
e23a49fbd3 Replace core.removeAccount by core.removeAccountWithData() 2025-12-04 15:40:41 +01:00
Christophe Deschamps
a9a1249ecd Add button to export ICS of meeting in meetings and chat views 2025-12-04 15:36:42 +01:00
Christophe Deschamps
ed57ec1ea5 Enable e2e encryption in scheduled conf chat rooms 2025-12-04 15:32:47 +01:00
56 changed files with 993 additions and 188 deletions

View file

@ -30,10 +30,10 @@
rm -f file.key
.deploy_linux: &deploy_linux |
rsync -rlv --ignore-existing build/OUTPUT/Packages/*.AppImage $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM/$APP_FOLDER
rsync -rlv --chmod=Fu=rw,Fg=r,Fo=r --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
rsync -rlv --chmod=Fu=rw,Fg=r,Fo=r build/OUTPUT/Packages/RELEASE $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM
rsync -rlv --chmod=Fu=rw,Fg=r,Fo=r build/OUTPUT/Packages/RELEASE $MAIN_DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM
fi
.linux-desktop:

View file

@ -26,7 +26,7 @@
.macosx-desktop:
stage: build
tags: [ "macmini-m1-xcode15" ]
tags: [ "macmini-m1-xcode15-flat" ]
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $DOCKER_UPDATE == null && $SKIP_MACOSX == null
- if: $CI_PIPELINE_SOURCE == "schedule" && $DOCKER_UPDATE == null && $SKIP_MACOSX == null
@ -93,7 +93,7 @@ macosx-ninja-novideo:
# WAIT for QT6 for arm64
macosx-ninja-package:
stage: package
tags: [ "macmini-m1-xcode15" ]
tags: [ "macmini-m1-xcode15-flat" ]
needs: []
rules:
- !reference [.rules-merge-request-manual, rules]
@ -117,7 +117,7 @@ macosx-ninja-package:
macosx-codesigning:
stage: signing
tags: [ "macmini-m1-xcode15" ]
tags: [ "macmini-m1-xcode15-flat" ]
needs:
- macosx-ninja-package
rules:
@ -142,7 +142,7 @@ macosx-codesigning:
macosx-deploy:
stage: deploy
tags: [ "macmini-m1-xcode15" ]
tags: [ "macmini-m1-xcode15-flat" ]
needs:
- macosx-codesigning
only:
@ -160,7 +160,7 @@ macosx-deploy:
macosx-makefile-plugins-deploy:
stage: deploy
tags: [ "macmini-m1-xcode15" ]
tags: [ "macmini-m1-xcode15-flat" ]
needs:
- macosx-makefile
only:

View file

@ -238,9 +238,9 @@ win64-codesigning:
- if: $DEPLOY_WINDOWS
script:
- scp -pr build-desktop/OUTPUT/Packages/*.exe ${DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/${APP_FOLDER}
- if ($MAKE_RELEASE_FILE_URL) { scp -pr build-desktop/OUTPUT/Packages/RELEASE ${DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/ }
- if ($MAKE_RELEASE_FILE_URL) { scp -pr build-desktop/OUTPUT/Packages/RELEASE ${MAIN_DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/ }
- rsync --perms --chmod=Fu=rw,Fg=r,Fo=r build-desktop/OUTPUT/Packages/*.exe ${DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/${APP_FOLDER}
- if ($MAKE_RELEASE_FILE_URL) { rsync --perms --chmod=Fu=rw,Fg=r,Fo=r build-desktop/OUTPUT/Packages/RELEASE ${DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/ }
- if ($MAKE_RELEASE_FILE_URL) { rsync --perms --chmod=Fu=rw,Fg=r,Fo=r build-desktop/OUTPUT/Packages/RELEASE ${MAIN_DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/ }
win64-ninja-vs2022-upload:
extends:

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16)
project(Linphone VERSION 6.1.0 LANGUAGES CXX)
project(Linphone VERSION 6.2.0 LANGUAGES CXX)
################################################################
# PACKAGES

View file

@ -84,6 +84,7 @@ AccountCore::AccountCore(const std::shared_ptr<linphone::Account> &account) : QO
? Utils::coreStringToAppString(params->getAudioVideoConferenceFactoryAddress()->asString())
: "";
mLimeServerUrl = Utils::coreStringToAppString(params->getLimeServerUrl());
mCcmpServerUrl = Utils::coreStringToAppString(params->getCcmpServerUrl());
// Add listener
mAccountModel = Utils::makeQObject_ptr<AccountModel>(account); // OK
@ -148,6 +149,7 @@ AccountCore::AccountCore(const AccountCore &accountCore) {
mConferenceFactoryAddress = accountCore.mConferenceFactoryAddress;
mAudioVideoConferenceFactoryAddress = accountCore.mAudioVideoConferenceFactoryAddress;
mLimeServerUrl = accountCore.mLimeServerUrl;
mCcmpServerUrl = accountCore.mCcmpServerUrl;
}
void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
@ -236,6 +238,10 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
mAccountModelConnection->makeConnectToModel(&AccountModel::limeServerUrlChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { onLimeServerUrlChanged(value); });
});
mAccountModelConnection->makeConnectToModel(&AccountModel::ccmpServerUrlChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { onCcmpServerUrlChanged(value); });
});
mAccountModelConnection->makeConnectToModel(
&AccountModel::removed, [this]() { mAccountModelConnection->invokeToCore([this]() { emit removed(); }); });
@ -327,6 +333,7 @@ void AccountCore::reset(const AccountCore &accountCore) {
setConferenceFactoryAddress(accountCore.mConferenceFactoryAddress);
setAudioVideoConferenceFactoryAddress(accountCore.mAudioVideoConferenceFactoryAddress);
setLimeServerUrl(accountCore.mLimeServerUrl);
setCcmpServerUrl(accountCore.mCcmpServerUrl);
}
const std::shared_ptr<AccountModel> &AccountCore::getModel() const {
@ -574,6 +581,10 @@ QString AccountCore::getLimeServerUrl() {
return mLimeServerUrl;
}
QString AccountCore::getCcmpServerUrl() {
return mCcmpServerUrl;
}
void AccountCore::setMwiServerAddress(QString value) {
if (mMwiServerAddress != value) {
mMwiServerAddress = value;
@ -678,6 +689,14 @@ void AccountCore::setLimeServerUrl(QString value) {
}
}
void AccountCore::setCcmpServerUrl(QString value) {
if (mCcmpServerUrl != value) {
mCcmpServerUrl = value;
emit ccmpServerUrlChanged();
setIsSaved(false);
}
}
bool AccountCore::isSaved() const {
return mIsSaved;
}
@ -790,6 +809,13 @@ void AccountCore::onLimeServerUrlChanged(QString value) {
}
}
void AccountCore::onCcmpServerUrlChanged(QString value) {
if (value != mCcmpServerUrl) {
mCcmpServerUrl = value;
emit ccmpServerUrlChanged();
}
}
void AccountCore::writeIntoModel(std::shared_ptr<AccountModel> model) const {
mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO);
model->setMwiServerAddress(mMwiServerAddress);
@ -806,6 +832,7 @@ void AccountCore::writeIntoModel(std::shared_ptr<AccountModel> model) const {
model->setConferenceFactoryAddress(mConferenceFactoryAddress);
model->setAudioVideoConferenceFactoryAddress(mAudioVideoConferenceFactoryAddress);
model->setLimeServerUrl(mLimeServerUrl);
model->setCcmpServerUrl(mCcmpServerUrl);
model->setVoicemailAddress(mVoicemailAddress);
}
@ -825,6 +852,7 @@ void AccountCore::writeFromModel(const std::shared_ptr<AccountModel> &model) {
onConferenceFactoryAddressChanged(model->getConferenceFactoryAddress());
onAudioVideoConferenceFactoryAddressChanged(model->getAudioVideoConferenceFactoryAddress());
onLimeServerUrlChanged(model->getLimeServerUrl());
onCcmpServerUrlChanged(model->getCcmpServerUrl());
onVoicemailAddressChanged(model->getVoicemailAddress());
}

View file

@ -84,6 +84,7 @@ public:
Q_PROPERTY(LinphoneEnums::Presence explicitPresence MEMBER mExplicitPresence NOTIFY presenceChanged)
Q_PROPERTY(QString presenceNote READ getPresenceNote WRITE setPresenceNote NOTIFY presenceChanged)
Q_PROPERTY(int maxPresenceNoteSize MEMBER mMaxPresenceNoteSize CONSTANT)
Q_PROPERTY(QString ccmpServerUrl READ getCcmpServerUrl WRITE setCcmpServerUrl NOTIFY ccmpServerUrlChanged)
DECLARE_CORE_GET(int, voicemailCount, VoicemailCount)
static QSharedPointer<AccountCore> create(const std::shared_ptr<linphone::Account> &account);
@ -143,6 +144,7 @@ public:
QString getAudioVideoConferenceFactoryAddress();
QString getLimeServerUrl();
QString getVoicemailAddress();
QString getCcmpServerUrl();
void setMwiServerAddress(QString value);
void setTransport(QString value);
@ -157,6 +159,7 @@ public:
void setAudioVideoConferenceFactoryAddress(QString value);
void setLimeServerUrl(QString value);
void setVoicemailAddress(QString value);
void setCcmpServerUrl(QString value);
bool isSaved() const;
void setIsSaved(bool saved);
@ -175,6 +178,7 @@ public:
void onConferenceFactoryAddressChanged(QString value);
void onAudioVideoConferenceFactoryAddressChanged(QString value);
void onLimeServerUrlChanged(QString value);
void onCcmpServerUrlChanged(QString value);
DECLARE_CORE_GET(bool, showMwi, ShowMwi)
@ -220,6 +224,7 @@ signals:
void isSavedChanged();
void voicemailAddressChanged();
void presenceChanged();
void ccmpServerUrlChanged();
void setValueFailed(const QString &error);
@ -268,6 +273,7 @@ private:
QString mAudioVideoConferenceFactoryAddress;
QString mLimeServerUrl;
QString mVoicemailAddress;
QString mCcmpServerUrl;
LinphoneEnums::Presence mPresence = LinphoneEnums::Presence::Undefined;
LinphoneEnums::Presence mExplicitPresence;
QString mPresenceNote;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
* Copyright (c) 2010-2026 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
@ -28,6 +28,8 @@
#include "tool/Utils.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <QQuickWindow>
DEFINE_ABSTRACT_OBJECT(CallCore)
/***********************************************************************/
@ -449,6 +451,44 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
setVideoStats(videoStats);
}
});
mCallModelConnection->makeConnectToModel(&CallModel::headsetAnswerCallRequested, [this]() {
mCallModelConnection->invokeToCore([this]() {
const auto callList = App::getInstance()->getCallList();
const auto currentPendingCall = callList->getFirstIncommingPendingCall();
if (!currentPendingCall.isNull()) {
const auto gui = new CallGui(currentPendingCall);
Utils::openCallsWindow(gui);
currentPendingCall->lAccept(false);
}
});
});
mCallModelConnection->makeConnectToModel(&CallModel::headsetEndCallRequested, [this]() {
mCallModelConnection->invokeToCore([this]() {
const auto window = Utils::getOrCreateCallsWindow();
window->setProperty("callTerminatedByUser", true);
lTerminate();
});
});
mCallModelConnection->makeConnectToModel(&CallModel::headsetHoldCallRequested, [this]() {
mCallModelConnection->invokeToCore([this]() { lSetPaused(true); });
});
mCallModelConnection->makeConnectToModel(&CallModel::headsetMicrophoneMuteToggled, [this](bool mute) {
mCallModelConnection->invokeToCore([this, mute]() { lSetMicrophoneMuted(mute); });
});
mCallModelConnection->makeConnectToModel(&CallModel::headsetRejectCallRequested, [this]() {
mCallModelConnection->invokeToCore([this]() {
const auto callList = App::getInstance()->getCallList();
const auto currentPendingCall = callList->getFirstIncommingPendingCall();
if (!currentPendingCall.isNull()) {
currentPendingCall->lDecline();
}
});
});
mCallModelConnection->makeConnectToModel(&CallModel::headsetResumeCallRequested, [this]() {
mCallModelConnection->invokeToCore([this]() { lSetPaused(false); });
});
if (mShouldFindRemoteFriend) findRemoteFriend(me);
}

View file

@ -25,20 +25,32 @@
DEFINE_ABSTRACT_OBJECT(CallProxy)
CallProxy::CallProxy(QObject *parent) : LimitProxy(parent) {
CallProxy::CallProxy() : SortFilterProxy() {
mShowCurrentCall = true;
}
CallProxy::~CallProxy() {
}
CallGui *CallProxy::getCurrentCall() {
auto model = getListModel<CallList>();
auto model = qobject_cast<CallList *>(sourceModel());
if (!mCurrentCall && model) mCurrentCall = model->getCurrentCall();
return mCurrentCall;
}
void CallProxy::setShowCurrentCall(bool show) {
if (mShowCurrentCall != show) {
mShowCurrentCall = show;
emit showCurrentCallChanged();
}
}
bool CallProxy::showCurrentCall() const {
return mShowCurrentCall;
}
void CallProxy::setCurrentCall(CallGui *call) {
getListModel<CallList>()->setCurrentCall(call);
qobject_cast<CallList *>(sourceModel())->setCurrentCall(call);
}
// Reset the default account to let UI build its new object if needed.
@ -48,12 +60,12 @@ void CallProxy::resetCurrentCall() {
}
bool CallProxy::getHaveCall() const {
auto model = getListModel<CallList>();
auto model = qobject_cast<CallList *>(sourceModel());
return model ? model->getHaveCall() : false;
}
void CallProxy::setSourceModel(QAbstractItemModel *model) {
auto oldCallList = getListModel<CallList>();
auto oldCallList = qobject_cast<CallList *>(sourceModel());
if (oldCallList) {
disconnect(oldCallList);
}
@ -63,24 +75,24 @@ void CallProxy::setSourceModel(QAbstractItemModel *model) {
connect(newCallList, &CallList::haveCallChanged, this, &CallProxy::haveCallChanged, Qt::QueuedConnection);
connect(this, &CallProxy::lMergeAll, newCallList, &CallList::lMergeAll);
}
setSourceModels(new SortFilterList(model));
QSortFilterProxyModel::setSourceModel(model);
}
bool CallProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool CallProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool show = (mFilterText.isEmpty() || mFilterText == "*");
auto callList = qobject_cast<CallList *>(sourceModel());
auto call = callList->getAt<CallCore>(sourceRow);
if (!mShowCurrentCall && call == callList->getCurrentCallCore()) return false;
if (!show) {
QRegularExpression search(QRegularExpression::escape(mFilterText),
QRegularExpression::CaseInsensitiveOption |
QRegularExpression::UseUnicodePropertiesOption);
auto call = qobject_cast<CallList *>(sourceModel())->getAt<CallCore>(sourceRow);
show = call->getRemoteAddress().contains(search);
}
return show;
}
bool CallProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
bool CallProxy::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<CallList, CallCore>(sourceLeft.row());
auto r = getItemAtSource<CallList, CallCore>(sourceRight.row());

View file

@ -28,15 +28,14 @@
// =============================================================================
class CallProxy : public LimitProxy, public AbstractObject {
class CallProxy : public SortFilterProxy, public AbstractObject {
Q_OBJECT
Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged)
Q_PROPERTY(bool haveCall READ getHaveCall NOTIFY haveCallChanged)
Q_PROPERTY(bool showCurrentCall READ showCurrentCall WRITE setShowCurrentCall NOTIFY showCurrentCallChanged)
public:
DECLARE_SORTFILTER_CLASS()
CallProxy(QObject *parent = Q_NULLPTR);
CallProxy();
~CallProxy();
// Get a new object from List or give the stored one.
@ -48,15 +47,23 @@ public:
bool getHaveCall() const;
void setShowCurrentCall(bool show);
bool showCurrentCall() const;
void setSourceModel(QAbstractItemModel *sourceModel) override;
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override;
signals:
void lMergeAll();
void currentCallChanged();
void haveCallChanged();
void showCurrentCallChanged();
protected:
CallGui *mCurrentCall = nullptr; // When null, a new UI object is build from List
bool mShowCurrentCall = false;
DECLARE_ABSTRACT_OBJECT
};

View file

@ -394,6 +394,7 @@ void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
[this](std::shared_ptr<linphone::Friend> f) { updateInfo(f); });
mCoreModelConnection->makeConnectToModel(&CoreModel::friendRemoved,
[this](std::shared_ptr<linphone::Friend> f) { updateInfo(f, true); });
}
QDateTime ChatCore::getLastUpdatedTime() const {

View file

@ -115,11 +115,17 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &c
if (chatmessage) {
mChatMessageModel = Utils::makeQObject_ptr<ChatMessageModel>(chatmessage);
mChatMessageModel->setSelf(mChatMessageModel);
mText = ToolModel::getMessageFromContent(chatmessage->getContents());
mText = ToolModel::getMessageFromMessage(chatmessage);
mUtf8Text = mChatMessageModel->getUtf8Text();
mHasTextContent = mChatMessageModel->getHasTextContent();
mTimestamp = QDateTime::fromSecsSinceEpoch(chatmessage->getTime());
mIsOutgoing = chatmessage->isOutgoing();
mIsRetractable =
chatmessage->isOutgoing() && chatmessage->isRetractable() && !chatmessage->getChatRoom()->isReadOnly();
mIsRetracted = chatmessage->isRetracted();
mIsEditable =
chatmessage->isOutgoing() && chatmessage->isEditable() && !chatmessage->getChatRoom()->isReadOnly();
mIsEdited = chatmessage->isEdited();
mIsRemoteMessage = !chatmessage->isOutgoing();
mPeerAddress = Utils::coreStringToAppString(chatmessage->getPeerAddress()->asStringUriOnly());
mPeerName = ToolModel::getDisplayName(chatmessage->getPeerAddress());
@ -191,7 +197,7 @@ ChatMessageCore::ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &c
if (mIsReply) {
auto replymessage = chatmessage->getReplyMessage();
if (replymessage) {
mReplyText = ToolModel::getMessageFromContent(replymessage->getContents());
mReplyText = ToolModel::getMessageFromMessage(replymessage);
if (mIsFromChatGroup) mRepliedToName = ToolModel::getDisplayName(replymessage->getFromAddress());
}
}
@ -207,6 +213,9 @@ void ChatMessageCore::setSelf(QSharedPointer<ChatMessageCore> me) {
mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lDelete, [this] {
mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->deleteMessageFromChatRoom(true); });
});
mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lRetract, [this] {
mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->retractMessageFromChatRoom(); });
});
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::messageDeleted, [this](bool deletedByUser) {
mChatMessageModelConnection->invokeToCore([this, deletedByUser] {
//: Deleted
@ -350,6 +359,22 @@ void ChatMessageCore::setSelf(QSharedPointer<ChatMessageCore> me) {
int duration = now.secsTo(QDateTime::fromSecsSinceEpoch(expireTime));
mChatMessageModelConnection->invokeToCore([this, duration] { setEphemeralDuration(duration); });
});
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::retracted,
[this](const std::shared_ptr<linphone::ChatMessage> &message) {
QString text = ToolModel::getMessageFromMessage(message);
mChatMessageModelConnection->invokeToCore([this, text] {
setText(text);
setRetracted();
});
});
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::contentEdited,
[this](const std::shared_ptr<linphone::ChatMessage> &message) {
mChatMessageModelConnection->invokeToCore([this] {
mIsEdited = true;
emit edited();
});
});
}
QList<ImdnStatus> ChatMessageCore::computeDeliveryStatus(const std::shared_ptr<linphone::ChatMessage> &message) {
@ -472,6 +497,22 @@ void ChatMessageCore::setIsRead(bool read) {
}
}
void ChatMessageCore::setRetracted() {
if (!mIsRetracted) {
mIsRetracted = true;
emit isRetractedChanged();
emit messageStateChanged();
}
}
bool ChatMessageCore::isRetracted() const {
return mIsRetracted;
}
bool ChatMessageCore::isEdited() const {
return mIsEdited;
}
QString ChatMessageCore::getOwnReaction() const {
return mOwnReaction;
}
@ -650,4 +691,4 @@ std::shared_ptr<ChatMessageModel> ChatMessageCore::getModel() const {
ChatMessageContentGui *ChatMessageCore::getVoiceRecordingContent() const {
return new ChatMessageContentGui(mVoiceRecordingContent);
}
}

View file

@ -111,6 +111,11 @@ class ChatMessageCore : public QObject, public AbstractObject {
Q_PROPERTY(bool hasFileContent MEMBER mHasFileContent CONSTANT)
Q_PROPERTY(bool isVoiceRecording MEMBER mIsVoiceRecording CONSTANT)
Q_PROPERTY(bool isCalendarInvite MEMBER mIsCalendarInvite CONSTANT)
Q_PROPERTY(bool isOutgoing MEMBER mIsOutgoing CONSTANT)
Q_PROPERTY(bool isRetractable MEMBER mIsRetractable CONSTANT)
Q_PROPERTY(bool isRetracted READ isRetracted NOTIFY isRetractedChanged)
Q_PROPERTY(bool isEditable MEMBER mIsEditable CONSTANT)
Q_PROPERTY(bool isEdited READ isEdited NOTIFY edited)
public:
static QSharedPointer<ChatMessageCore> create(const std::shared_ptr<linphone::ChatMessage> &chatmessage);
@ -143,6 +148,10 @@ public:
bool isRead() const;
void setIsRead(bool read);
bool isRetracted() const;
void setRetracted();
bool isEdited() const;
QString getOwnReaction() const;
void setOwnReaction(const QString &reaction);
QString getTotalReactionsLabel() const;
@ -176,9 +185,12 @@ signals:
void messageReactionChanged();
void singletonReactionMapChanged();
void ephemeralDurationChanged(int duration);
void isRetractedChanged();
void edited();
void lDelete();
void deleted();
void lRetract();
void lMarkAsRead();
void readChanged();
void lSendReaction(const QString &reaction);
@ -214,6 +226,10 @@ private:
bool mIsVoiceRecording = false;
bool mIsEphemeral = false;
int mEphemeralDuration = 0;
bool mIsRetractable = false;
bool mIsRetracted = false;
bool mIsEditable = false;
bool mIsEdited = false;
bool mIsOutgoing = false;
QString mTotalReactionsLabel;

View file

@ -64,6 +64,8 @@ void EventLogList::disconnectItem(const QSharedPointer<EventLogCore> &item) {
if (message) {
disconnect(message.get(), &ChatMessageCore::isReadChanged, this, nullptr);
disconnect(message.get(), &ChatMessageCore::deleted, this, nullptr);
disconnect(message.get(), &ChatMessageCore::edited, this, nullptr);
disconnect(message.get(), &ChatMessageCore::isRetractedChanged, this, nullptr);
}
}
@ -77,6 +79,23 @@ void EventLogList::connectItem(const QSharedPointer<EventLogCore> &item) {
if (mChatCore) emit mChatCore->lUpdateLastMessage();
remove(item);
});
connect(message.get(), &ChatMessageCore::isRetractedChanged, this, [this, item] {
if (mChatCore) emit mChatCore->lUpdateUnreadCount();
});
connect(message.get(), &ChatMessageCore::edited, this, [this, item] {
auto eventLogModel = item->getModel();
mCoreModelConnection->invokeToModel([this, eventLogModel, item]() {
auto chatRoom = mChatCore->getModel()->getMonitor();
auto newEventLog = EventLogCore::create(eventLogModel->getEventLog(), chatRoom);
bool wasLastMessage =
mChatCore->getModel()->getLastChatMessage() == eventLogModel->getEventLog()->getChatMessage();
mCoreModelConnection->invokeToCore([this, newEventLog, wasLastMessage, item] {
connectItem(newEventLog);
replace(item, newEventLog);
if (wasLastMessage) mChatCore->setLastMessage(newEventLog->getChatMessageCore());
});
});
});
}
}

View file

@ -205,4 +205,4 @@ void EventLogProxy::findIndexCorrespondingToFilter(int startIndex, bool forward,
auto listIndex = mapToSource(index(startIndex, 0)).row();
eventLogList->findChatMessageWithFilter(filter, listIndex, forward, isFirstResearch);
}
}
}

View file

@ -21,12 +21,15 @@
#include "ConferenceInfoCore.hpp"
#include "core/App.hpp"
#include "core/path/Paths.hpp"
#include "core/proxy/ListProxy.hpp"
#include "model/object/VariantObject.hpp"
#include "model/tool/ToolModel.hpp"
#include "tool/Utils.hpp"
#include "tool/thread/SafeConnection.hpp"
#include <QDesktopServices>
DEFINE_ABSTRACT_OBJECT(ConferenceInfoCore)
QSharedPointer<ConferenceInfoCore>
@ -69,6 +72,7 @@ ConferenceInfoCore::ConferenceInfoCore(std::shared_ptr<linphone::ConferenceInfo>
mUri = address && address->isValid() && !address->getDomain().empty()
? Utils::coreStringToAppString(address->asStringUriOnly())
: "";
mIcalendarString = Utils::coreStringToAppString(conferenceInfo->getIcalendarString());
mDateTime = QDateTime::fromMSecsSinceEpoch(conferenceInfo->getDateTime() * 1000);
mDuration = conferenceInfo->getDuration();
mEndDateTime = mDateTime.addSecs(mDuration * 60);
@ -123,6 +127,7 @@ ConferenceInfoCore::ConferenceInfoCore(const ConferenceInfoCore &conferenceInfoC
mIsEnded = conferenceInfoCore.mIsEnded;
mInviteEnabled = conferenceInfoCore.mInviteEnabled;
mConferenceInfoState = conferenceInfoCore.mConferenceInfoState;
mIcalendarString = conferenceInfoCore.mIcalendarString;
}
ConferenceInfoCore::~ConferenceInfoCore() {
@ -601,6 +606,9 @@ void ConferenceInfoCore::save() {
} else lCritical() << "No default account";
// Add text capability for chat in conf
linphoneConf->setCapability(linphone::StreamType::Text, true);
if (SettingsModel::getInstance()->getCreateEndToEndEncryptedMeetingsAndGroupCalls())
linphoneConf->setSecurityLevel(linphone::Conference::SecurityLevel::EndToEnd);
else linphoneConf->setSecurityLevel(linphone::Conference::SecurityLevel::PointToPoint);
auto confInfoModel = Utils::makeQObject_ptr<ConferenceInfoModel>(linphoneConf);
auto confSchedulerModel = confInfoModel->getConferenceScheduler();
if (!confSchedulerModel) {
@ -650,3 +658,14 @@ bool ConferenceInfoCore::isAllDayConf() const {
return mDateTime.time().hour() == 0 && mDateTime.time().minute() == 0 && mEndDateTime.time().hour() == 23 &&
mEndDateTime.time().minute() == 59;
}
void ConferenceInfoCore::exportConferenceToICS() const {
QString filePath(Paths::getAppLocalDirPath() + "conference.ics");
QFile file(filePath);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream out(&file);
out << mIcalendarString;
file.close();
}
QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
}

View file

@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2022 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
@ -135,6 +135,8 @@ public:
Q_INVOKABLE bool isAllDayConf() const;
Q_INVOKABLE void exportConferenceToICS() const;
signals:
void dateTimeChanged();
void endDateTimeChanged();
@ -177,6 +179,7 @@ private:
QString mSubject;
QString mDescription;
QString mUri;
QString mIcalendarString;
QVariantList mParticipants;
QSharedPointer<TimeZoneModel> mTimeZoneModel;
LinphoneEnums::ConferenceSchedulerState mConferenceSchedulerState;

View file

@ -51,8 +51,25 @@ PayloadTypeCore::~PayloadTypeCore() {
void PayloadTypeCore::setSelf(QSharedPointer<PayloadTypeCore> me) {
mPayloadTypeModelConnection = SafeConnection<PayloadTypeCore, PayloadTypeModel>::create(me, mPayloadTypeModel);
DEFINE_CORE_GETSET_CONNECT(mPayloadTypeModelConnection, PayloadTypeCore, PayloadTypeModel, mPayloadTypeModel, bool,
enabled, Enabled)
mPayloadTypeModelConnection->makeConnectToCore(&PayloadTypeCore::setEnabled, [this](bool enabled) {
if (enabled != mEnabled) {
mChanged = true;
emit changed();
}
mEnabled = enabled;
});
mPayloadTypeModelConnection->makeConnectToModel(&PayloadTypeModel::enabledChanged, [this](bool enabled) {
mPayloadTypeModelConnection->invokeToCore([this, enabled]() {
if (mEnabled != enabled) {
mEnabled = enabled;
emit enabledChanged();
}
});
});
}
void PayloadTypeCore::save() {
if (mChanged) mPayloadTypeModelConnection->invokeToModel([this]() { mPayloadTypeModel->setEnabled(mEnabled); });
}
PayloadTypeCore::Family PayloadTypeCore::getFamily() {

View file

@ -43,7 +43,7 @@ public:
const std::shared_ptr<linphone::PayloadType> &payloadType);
PayloadTypeCore(Family family, const std::shared_ptr<linphone::PayloadType> &payloadType);
PayloadTypeCore(){};
PayloadTypeCore() {};
~PayloadTypeCore();
void setSelf(QSharedPointer<PayloadTypeCore> me);
@ -51,9 +51,15 @@ public:
bool isDownloadable();
QString getMimeType();
Q_INVOKABLE void save();
signals:
void changed();
protected:
Family mFamily;
bool mDownloadable = false;
bool mChanged = false;
DECLARE_CORE_GETSET_MEMBER(bool, enabled, Enabled)
DECLARE_CORE_MEMBER(QString, mimeType, MimeType)
DECLARE_CORE_MEMBER(QString, encoderDescription, EncoderDescription)

View file

@ -61,6 +61,13 @@ SettingsCore::SettingsCore(QObject *parent) : QObject(parent) {
mRingtoneFolder = mRingtonePath.left(mRingtonePath.lastIndexOf(QDir::separator()));
}
// Network
mIpv6Enabled = settingsModel->getIpv6Enabled();
// Advanced
mAutoStart = settingsModel->getAutoStart();
mHideFps = settingsModel->getHideFps();
// Audio
mCaptureDevices = settingsModel->getCaptureDevices();
mPlaybackDevices = settingsModel->getPlaybackDevices();
@ -116,7 +123,6 @@ SettingsCore::SettingsCore(QObject *parent) : QObject(parent) {
INIT_CORE_MEMBER(DisableBroadcastFeature, settingsModel)
INIT_CORE_MEMBER(HideSettings, settingsModel)
INIT_CORE_MEMBER(HideAccountSettings, settingsModel)
INIT_CORE_MEMBER(HideFps, settingsModel)
INIT_CORE_MEMBER(DisableCallRecordings, settingsModel)
INIT_CORE_MEMBER(AssistantHideCreateAccount, settingsModel)
INIT_CORE_MEMBER(AssistantHideCreateAccount, settingsModel)
@ -132,7 +138,6 @@ SettingsCore::SettingsCore(QObject *parent) : QObject(parent) {
INIT_CORE_MEMBER(AutoStart, settingsModel)
INIT_CORE_MEMBER(ExitOnClose, settingsModel)
INIT_CORE_MEMBER(SyncLdapContacts, settingsModel)
INIT_CORE_MEMBER(Ipv6Enabled, settingsModel)
INIT_CORE_MEMBER(ConfigLocale, settingsModel)
INIT_CORE_MEMBER(DownloadFolder, settingsModel)
@ -141,7 +146,6 @@ SettingsCore::SettingsCore(QObject *parent) : QObject(parent) {
INIT_CORE_MEMBER(CallToneIndicationsEnabled, settingsModel)
INIT_CORE_MEMBER(CommandLine, settingsModel)
INIT_CORE_MEMBER(DisableCommandLine, settingsModel)
INIT_CORE_MEMBER(DisableCallForward, settingsModel)
INIT_CORE_MEMBER(CallForwardToAddress, settingsModel)
INIT_CORE_MEMBER(ThemeMainColor, settingsModel)
@ -210,10 +214,10 @@ SettingsCore::SettingsCore(const SettingsCore &settingsCore) {
mAssistantGoDirectlyToThirdPartySipAccountLogin = settingsCore.mAssistantGoDirectlyToThirdPartySipAccountLogin;
mAssistantThirdPartySipAccountDomain = settingsCore.mAssistantThirdPartySipAccountDomain;
mAssistantThirdPartySipAccountTransport = settingsCore.mAssistantThirdPartySipAccountTransport;
mAutoStart = settingsCore.mAutoStart;
mExitOnClose = settingsCore.mExitOnClose;
mSyncLdapContacts = settingsCore.mSyncLdapContacts;
mIpv6Enabled = settingsCore.mIpv6Enabled;
mAutoStart = settingsCore.mAutoStart;
mConfigLocale = settingsCore.mConfigLocale;
mDownloadFolder = settingsCore.mDownloadFolder;
mShortcutCount = settingsCore.mShortcutCount;
@ -221,7 +225,7 @@ SettingsCore::SettingsCore(const SettingsCore &settingsCore) {
mCallToneIndicationsEnabled = settingsCore.mCallToneIndicationsEnabled;
mCommandLine = settingsCore.mCommandLine;
mDisableCommandLine = settingsCore.mDisableCommandLine;
mDisableCallForward = settingsCore.mDisableCallForward;
mCallForwardToAddress = settingsCore.mCallForwardToAddress;
mDefaultDomain = settingsCore.mDefaultDomain;
mShowAccountDevices = settingsCore.mShowAccountDevices;
@ -260,6 +264,31 @@ void SettingsCore::setSelf(QSharedPointer<SettingsCore> me) {
mSettingsModelConnection->invokeToCore([this, enabled]() { setEchoCancellationEnabled(enabled); });
});
// IPV6
mSettingsModelConnection->makeConnectToModel(&SettingsModel::ipv6EnabledChanged, [this](const bool enabled) {
mSettingsModelConnection->invokeToCore([this, enabled]() { setIpv6Enabled(enabled); });
});
// Call Forward
mSettingsModelConnection->makeConnectToModel(
&SettingsModel::callForwardToAddressChanged, [this](const QString address) {
mSettingsModelConnection->invokeToCore([this, address]() { setCallForwardToAddress(address); });
});
// Hide FPS
mSettingsModelConnection->makeConnectToModel(&SettingsModel::hideFpsChanged, [this](const bool hide) {
mSettingsModelConnection->invokeToCore([this, hide]() { setHideFps(hide); });
});
// AutoStart
mSettingsModelConnection->makeConnectToModel(&SettingsModel::autoStartChanged, [this](const bool enabled) {
mSettingsModelConnection->invokeToCore([this, enabled]() {
bool emitSignal = mAutoStart != enabled;
setAutoStart(enabled);
if (emitSignal) emit autoStartChanged();
});
});
// Auto download incoming files
mSettingsModelConnection->makeConnectToModel(
&SettingsModel::autoDownloadReceivedFilesChanged, [this](const bool enabled) {
@ -304,7 +333,7 @@ void SettingsCore::setSelf(QSharedPointer<SettingsCore> me) {
});
});
mSettingsModelConnection->makeConnectToModel(&SettingsModel::playbackGainChanged, [this](const float value) {
mSettingsModelConnection->invokeToCore([this, value]() { setPlaybackGain(value); });
mSettingsModelConnection->invokeToCore([this, value]() { setPlaybackGainFromModel(value); });
});
mSettingsModelConnection->makeConnectToCore(&SettingsCore::lSetCaptureGain, [this](const float value) {
@ -314,7 +343,7 @@ void SettingsCore::setSelf(QSharedPointer<SettingsCore> me) {
});
});
mSettingsModelConnection->makeConnectToModel(&SettingsModel::captureGainChanged, [this](const float value) {
mSettingsModelConnection->invokeToCore([this, value]() { setCaptureGain(value); });
mSettingsModelConnection->invokeToCore([this, value]() { setCaptureGainFromModel(value); });
});
mSettingsModelConnection->makeConnectToModel(&SettingsModel::micVolumeChanged, [this](const float value) {
@ -450,8 +479,6 @@ void SettingsCore::setSelf(QSharedPointer<SettingsCore> me) {
ExitOnClose)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
syncLdapContacts, SyncLdapContacts)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool, ipv6Enabled,
Ipv6Enabled)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QString,
configLocale, ConfigLocale)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QString,
@ -466,10 +493,6 @@ void SettingsCore::setSelf(QSharedPointer<SettingsCore> me) {
commandLine, CommandLine)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
disableCommandLine, DisableCommandLine)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, bool,
disableCallForward, DisableCallForward)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QString,
callForwardToAddress, CallForwardToAddress)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QString,
themeAboutPictureUrl, ThemeAboutPictureUrl)
DEFINE_CORE_GETSET_CONNECT(mSettingsModelConnection, SettingsCore, SettingsModel, settingsModel, QString,
@ -559,13 +582,14 @@ void SettingsCore::reset(const SettingsCore &settingsCore) {
setAssistantGoDirectlyToThirdPartySipAccountLogin(settingsCore.mAssistantGoDirectlyToThirdPartySipAccountLogin);
setAssistantThirdPartySipAccountDomain(settingsCore.mAssistantThirdPartySipAccountDomain);
setAssistantThirdPartySipAccountTransport(settingsCore.mAssistantThirdPartySipAccountTransport);
setAutoStart(settingsCore.mAutoStart);
setExitOnClose(settingsCore.mExitOnClose);
setSyncLdapContacts(settingsCore.mSyncLdapContacts);
setCardDAVMinCharForResearch(settingsCore.mCardDAVMinCharForResearch);
setIpv6Enabled(settingsCore.mIpv6Enabled);
setAutoStart(settingsCore.mAutoStart);
setConfigLocale(settingsCore.mConfigLocale);
setDownloadFolder(settingsCore.mDownloadFolder);
setCallForwardToAddress(settingsCore.mCallForwardToAddress);
}
QString SettingsCore::getConfigPath(const QCommandLineParser &parser) {
@ -624,6 +648,36 @@ void SettingsCore::setEchoCancellationEnabled(bool enabled) {
}
}
void SettingsCore::setIpv6Enabled(bool enabled) {
if (mIpv6Enabled != enabled) {
mIpv6Enabled = enabled;
emit ipv6EnabledChanged();
setIsSaved(false);
}
}
void SettingsCore::setAutoStart(bool enabled) {
if (mAutoStart != enabled) {
mAutoStart = enabled;
setIsSaved(false);
}
}
void SettingsCore::setCallForwardToAddress(QString address) {
if (mCallForwardToAddress != address) {
mCallForwardToAddress = address;
setIsSaved(false);
}
}
void SettingsCore::setHideFps(bool hide) {
if (mHideFps != hide) {
mHideFps = hide;
emit hideFpsChanged();
setIsSaved(false);
}
}
void SettingsCore::setAutoDownloadReceivedFiles(bool enabled) {
if (mAutoDownloadReceivedFiles != enabled) {
mAutoDownloadReceivedFiles = enabled;
@ -716,7 +770,7 @@ bool SettingsCore::isSaved() const {
void SettingsCore::setIsSaved(bool saved) {
if (mIsSaved != saved) {
mIsSaved = saved;
emit isSavedChanged();
emit isSavedChanged(saved);
}
}
@ -767,6 +821,13 @@ void SettingsCore::setCaptureGain(float gain) {
}
}
void SettingsCore::setCaptureGainFromModel(float gain) {
if (mCaptureGain != gain) {
mCaptureGain = gain;
emit captureGainChanged(gain);
}
}
QVariantMap SettingsCore::getConferenceLayout() const {
return mConferenceLayout;
}
@ -811,6 +872,13 @@ void SettingsCore::setPlaybackGain(float gain) {
}
}
void SettingsCore::setPlaybackGainFromModel(float gain) {
if (mPlaybackGain != gain) {
mPlaybackGain = gain;
emit playbackGainChanged(gain);
}
}
QVariantMap SettingsCore::getCaptureDevice() const {
return mCaptureDevice;
}
@ -1008,10 +1076,6 @@ void SettingsCore::setShowAccountDevices(bool show) {
}
}
bool SettingsCore::getAutoStart() const {
return mAutoStart;
}
bool SettingsCore::getExitOnClose() const {
return mExitOnClose;
}
@ -1099,12 +1163,13 @@ void SettingsCore::writeIntoModel(std::shared_ptr<SettingsModel> model) const {
model->setAssistantGoDirectlyToThirdPartySipAccountLogin(mAssistantGoDirectlyToThirdPartySipAccountLogin);
model->setAssistantThirdPartySipAccountDomain(mAssistantThirdPartySipAccountDomain);
model->setAssistantThirdPartySipAccountTransport(mAssistantThirdPartySipAccountTransport);
model->setAutoStart(mAutoStart);
model->setExitOnClose(mExitOnClose);
model->setSyncLdapContacts(mSyncLdapContacts);
model->setIpv6Enabled(mIpv6Enabled);
model->setAutoStart(mAutoStart);
model->setConfigLocale(mConfigLocale);
model->setDownloadFolder(mDownloadFolder);
model->setCallForwardToAddress(mCallForwardToAddress);
}
void SettingsCore::writeFromModel(const std::shared_ptr<SettingsModel> &model) {
@ -1123,6 +1188,9 @@ void SettingsCore::writeFromModel(const std::shared_ptr<SettingsModel> &model) {
mRingtoneFileName =
ringtone.exists() ? ringtone.fileName() : mRingtonePath.right(mRingtonePath.lastIndexOf(QDir::separator()));
// Advanced
mAutoStart = model->getAutoStart();
// Chat
mAutoDownloadReceivedFiles = model->getAutoDownloadReceivedFiles();
@ -1181,8 +1249,10 @@ void SettingsCore::writeFromModel(const std::shared_ptr<SettingsModel> &model) {
mSyncLdapContacts = model->getSyncLdapContacts();
mCardDAVMinCharForResearch = model->getCardDAVMinCharResearch();
mIpv6Enabled = model->getIpv6Enabled();
mAutoStart = model->getAutoStart();
mConfigLocale = model->getConfigLocale();
mDownloadFolder = model->getDownloadFolder();
mCallForwardToAddress = model->getCallForwardToAddress();
}
bool SettingsCore::isCheckForUpdateAvailable() const {
@ -1192,6 +1262,7 @@ bool SettingsCore::isCheckForUpdateAvailable() const {
void SettingsCore::save() {
mustBeInMainThread(getClassName() + Q_FUNC_INFO);
SettingsCore *thisCopy = new SettingsCore(*this);
emit autoStartChanged();
if (SettingsModel::getInstance()) {
mSettingsModelConnection->invokeToModel([this, thisCopy] {
mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO);

View file

@ -62,6 +62,17 @@ public:
Q_PROPERTY(QVariantMap playbackDevice READ getPlaybackDevice WRITE setPlaybackDevice NOTIFY playbackDeviceChanged)
Q_PROPERTY(QVariantMap ringerDevice READ getRingerDevice WRITE setRingerDevice NOTIFY ringerDeviceChanged)
// Call Forward
Q_PROPERTY(QString callForwardToAddress READ getCallForwardToAddress WRITE setCallForwardToAddress NOTIFY
callForwardToAddressChanged)
// Network
Q_PROPERTY(bool ipv6Enabled READ getIpv6Enabled WRITE setIpv6Enabled NOTIFY ipv6EnabledChanged)
Q_PROPERTY(bool hideFps READ getHideFps WRITE setHideFps NOTIFY hideFpsChanged)
// Advanced
Q_PROPERTY(bool autoStart READ getAutoStart WRITE setAutoStart NOTIFY autoStartChanged)
Q_PROPERTY(
QVariantMap conferenceLayout READ getConferenceLayout WRITE setConferenceLayout NOTIFY conferenceLayoutChanged)
Q_PROPERTY(
@ -144,9 +155,11 @@ public:
float getPlaybackGain() const;
void setPlaybackGain(float gain);
void setPlaybackGainFromModel(float gain);
float getCaptureGain() const;
void setCaptureGain(float gain);
void setCaptureGainFromModel(float gain);
QVariantList getCaptureDevices() const;
void setCaptureDevices(QVariantList devices);
@ -193,6 +206,32 @@ public:
Q_INVOKABLE void closeCallSettings();
Q_INVOKABLE void updateMicVolume() const;
// Call Forward. --------------------------------------------------------------------
QString getCallForwardToAddress() {
return mCallForwardToAddress;
}
void setCallForwardToAddress(QString address);
// Network. --------------------------------------------------------------------
bool getIpv6Enabled() {
return mIpv6Enabled;
}
void setIpv6Enabled(bool enabled);
// Advanced. --------------------------------------------------------------------
bool getAutoStart() {
return mAutoStart;
}
void setAutoStart(bool enabled);
bool getHideFps() {
return mHideFps;
}
void setHideFps(bool hide);
bool getLogsEnabled() const;
void setLogsEnabled(bool enabled);
@ -227,7 +266,6 @@ public:
DECLARE_CORE_GETSET_MEMBER(bool, disableBroadcastFeature, DisableBroadcastFeature)
DECLARE_CORE_GETSET_MEMBER(bool, hideSettings, HideSettings)
DECLARE_CORE_GETSET_MEMBER(bool, hideAccountSettings, HideAccountSettings)
DECLARE_CORE_GETSET_MEMBER(bool, hideFps, HideFps)
DECLARE_CORE_GETSET_MEMBER(bool, disableCallRecordings, DisableCallRecordings)
DECLARE_CORE_GETSET_MEMBER(bool, assistantHideCreateAccount, AssistantHideCreateAccount)
DECLARE_CORE_GETSET_MEMBER(bool, assistantDisableQrCode, AssistantDisableQrCode)
@ -240,10 +278,8 @@ public:
AssistantGoDirectlyToThirdPartySipAccountLogin)
DECLARE_CORE_GETSET_MEMBER(QString, assistantThirdPartySipAccountDomain, AssistantThirdPartySipAccountDomain)
DECLARE_CORE_GETSET_MEMBER(QString, assistantThirdPartySipAccountTransport, AssistantThirdPartySipAccountTransport)
DECLARE_CORE_GETSET(bool, autoStart, AutoStart)
DECLARE_CORE_GETSET(bool, exitOnClose, ExitOnClose)
DECLARE_CORE_GETSET(bool, syncLdapContacts, SyncLdapContacts)
DECLARE_CORE_GETSET_MEMBER(bool, ipv6Enabled, Ipv6Enabled)
DECLARE_CORE_GETSET(QString, configLocale, ConfigLocale)
DECLARE_CORE_GETSET(QString, downloadFolder, DownloadFolder)
// Read-only
@ -252,8 +288,6 @@ public:
DECLARE_CORE_GETSET_MEMBER(bool, callToneIndicationsEnabled, CallToneIndicationsEnabled)
DECLARE_CORE_GETSET_MEMBER(bool, disableCommandLine, DisableCommandLine)
DECLARE_CORE_GETSET_MEMBER(QString, commandLine, CommandLine)
DECLARE_CORE_GETSET_MEMBER(bool, disableCallForward, DisableCallForward)
DECLARE_CORE_GETSET_MEMBER(QString, callForwardToAddress, CallForwardToAddress)
DECLARE_CORE_GET_CONSTANT(QFont, emojiFont, EmojiFont)
DECLARE_CORE_GET_CONSTANT(QFont, textMessageFont, TextMessageFont)
// Theme
@ -283,6 +317,17 @@ signals:
void captureDevicesChanged(const QVariantList &devices);
void playbackDevicesChanged(const QVariantList &devices);
void ringerDevicesChanged(const QVariantList &devices);
// Network
void ipv6EnabledChanged();
// Call Forward
void callForwardToAddressChanged();
// Advanced
void autoStartChanged();
void hideFpsChanged();
void conferenceLayoutsChanged(const QVariantList &layouts);
void mediaEncryptionsChanged(const QVariantList &encryptions);
@ -303,7 +348,7 @@ signals:
void createEndToEndEncryptedMeetingsAndGroupCallsChanged(bool endtoend);
void isSavedChanged();
void isSavedChanged(bool saved);
void lSetPlaybackDevice(QVariantMap device);
void playbackDeviceChanged(const QVariantMap &device);
@ -381,6 +426,16 @@ private:
float mPlaybackGain;
int mEchoCancellationCalibration;
// Network
bool mIpv6Enabled;
// Call Forward
QString mCallForwardToAddress;
// Advanced
bool mAutoStart;
bool mHideFps;
// Debug logs
bool mLogsEnabled;
bool mFullLogsEnabled;

View 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="M208,32H184V24a8,8,0,0,0-16,0v8H88V24a8,8,0,0,0-16,0v8H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32ZM72,48v8a8,8,0,0,0,16,0V48h80v8a8,8,0,0,0,16,0V48h24V80H48V48ZM208,208H48V96H208V208Zm-48-56a8,8,0,0,1-8,8H136v16a8,8,0,0,1-16,0V160H104a8,8,0,0,1,0-16h16V128a8,8,0,0,1,16,0v16h16A8,8,0,0,1,160,152Z"></path></svg>

After

Width:  |  Height:  |  Size: 464 B

View file

@ -1078,49 +1078,49 @@
<context>
<name>CallListView</name>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="60"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="62"/>
<source>meeting</source>
<extracomment>&quot;Réunion</extracomment>
<translation>Besprechung</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="62"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="64"/>
<source>call</source>
<extracomment>&quot;Appel&quot;</extracomment>
<translation>Anruf</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="67"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="69"/>
<source>paused_call_or_meeting</source>
<extracomment>&quot;%1 en pause&quot;</extracomment>
<translation>%1 pausiert</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="69"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="71"/>
<source>ongoing_call_or_meeting</source>
<extracomment>&quot;%1 en cours&quot;</extracomment>
<translation>%1 laufend</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="89"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="91"/>
<source>transfer_call_name_accessible_name</source>
<extracomment>Transfer call %1</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="117"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="119"/>
<source>resume_call_name_accessible_name</source>
<extracomment>Resume %1 call</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="119"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="121"/>
<source>pause_call_name_accessible_name</source>
<extracomment>Pause %1 call</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="142"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="144"/>
<source>end_call_name_accessible_name</source>
<extracomment>End %1 call</extracomment>
<translation type="unfinished"></translation>
@ -2225,6 +2225,12 @@
<extracomment>&quot;Reception info&quot;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessage.qml" line="407"/>
<source>menu_edit_chat_message</source>
<extracomment>&quot;Edit&quot;</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessage.qml" line="419"/>
<source>chat_message_reply</source>
@ -4965,7 +4971,7 @@ Error</extracomment>
<context>
<name>NewCallForm</name>
<message>
<location filename="../../view/Page/Form/Call/NewCallForm.qml" line="24"/>
<location filename="../../view/Page/Form/Call/NewCallForm.qml" line="25"/>
<source>call_transfer_active_calls_label</source>
<extracomment>&quot;Appels en cours&quot;</extracomment>
<translation>Laufender Anruf</translation>

View file

@ -493,6 +493,12 @@
<extracomment>&quot;URL du serveur déchange de clés de chiffrement&quot;</extracomment>
<translation>Lime server URL</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/AccountSettingsParametersLayout.qml"/>
<source>account_settings_ccmp_server_url_title</source>
<extracomment>&quot;URL du serveur CCMP&quot;</extracomment>
<translation>CCMP server URL</translation>
</message>
</context>
<context>
<name>AddParticipantsForm</name>
@ -1083,49 +1089,49 @@
<context>
<name>CallListView</name>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="60"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="62"/>
<source>meeting</source>
<extracomment>&quot;Réunion</extracomment>
<translation>Meeting</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="62"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="64"/>
<source>call</source>
<extracomment>&quot;Appel&quot;</extracomment>
<translation>Call</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="67"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="69"/>
<source>paused_call_or_meeting</source>
<extracomment>&quot;%1 en pause&quot;</extracomment>
<translation>%1 paused</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="69"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="71"/>
<source>ongoing_call_or_meeting</source>
<extracomment>&quot;%1 en cours&quot;</extracomment>
<translation>Ongoing %1</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="89"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="91"/>
<source>transfer_call_name_accessible_name</source>
<extracomment>Transfer call %1</extracomment>
<translation>Transfer call %1</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="117"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="119"/>
<source>resume_call_name_accessible_name</source>
<extracomment>Resume %1 call</extracomment>
<translation>Resume %1 call</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="119"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="121"/>
<source>pause_call_name_accessible_name</source>
<extracomment>Pause %1 call</extracomment>
<translation>Pause %1 call</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="142"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="144"/>
<source>end_call_name_accessible_name</source>
<extracomment>End %1 call</extracomment>
<translation>End %1 call</translation>
@ -2212,6 +2218,12 @@
<extracomment>&quot;Reception info&quot;</extracomment>
<translation>Reception info</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessage.qml" line="407"/>
<source>menu_edit_chat_message</source>
<extracomment>&quot;Edit&quot;</extracomment>
<translation>Edit</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessage.qml" line="419"/>
<source>chat_message_reply</source>
@ -2230,6 +2242,12 @@
<extracomment>&quot;Delete&quot;</extracomment>
<translation>Delete</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessage.qml" line="469"/>
<source>conversation_message_edited_label</source>
<extracomment>&quot;Edited&quot;</extracomment>
<translation>Edited</translation>
</message>
</context>
<context>
<name>ChatMessageContentCore</name>
@ -2480,6 +2498,42 @@ Only your correspondent can decrypt them.</translation>
<extracomment>%1 is writing</extracomment>
<translation>%1 is writing</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="470"/>
<source>conversation_dialog_delete_chat_message_title</source>
<extracomment>&quot;Delete this message?&quot;</extracomment>
<translation>Delete this message?</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="471"/>
<source>conversation_dialog_delete_locally_label</source>
<extracomment>&quot;For me&quot;</extracomment>
<translation>For me</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="472"/>
<source>conversation_dialog_delete_for_everyone_label</source>
<extracomment>&quot;For everyone&quot;</extracomment>
<translation>For everyone</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="472"/>
<source>dialog_cancel</source>
<extracomment>&quot;Cancel&quot;</extracomment>
<translation>Cancel</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="472"/>
<source>info_toast_deleted_title</source>
<extracomment>Deleted</extracomment>
<translation>Deleted</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="472"/>
<source>info_toast_deleted_message</source>
<extracomment>The message has been deleted</extracomment>
<translation>The message has been deleted</translation>
</message>
</context>
<context>
<name>ChatPage</name>
@ -4887,7 +4941,7 @@ Expiration : %1</translation>
<context>
<name>NewCallForm</name>
<message>
<location filename="../../view/Page/Form/Call/NewCallForm.qml" line="24"/>
<location filename="../../view/Page/Form/Call/NewCallForm.qml" line="25"/>
<source>call_transfer_active_calls_label</source>
<extracomment>&quot;Appels en cours&quot;</extracomment>
<translation>Ongoing call</translation>
@ -5753,6 +5807,12 @@ To enable them in a commercial project, please contact us.</translation>
<extracomment>Reply to %1</extracomment>
<translation>Reply to %1</translation>
</message>
<message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="417"/>
<source>conversation_editing_message_title</source>
<extracomment>Message beeing edited</extracomment>
<translation>Message beeing edited</translation>
</message>
<message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="617"/>
<source>shared_medias_title</source>
@ -5941,6 +6001,18 @@ To enable them in a commercial project, please contact us.</translation>
<source>conference_invitation_updated</source>
<translation>Meeting modification</translation>
</message>
<message>
<location filename="../../model/tool/ToolModel.cpp" line="530"/>
<source>conversation_message_content_deleted_label</source>
<extracomment>&quot;&lt;i&gt;This message has been deleted&lt;/i&gt;&quot;</extracomment>
<translation>&lt;i&gt;This message has been deleted&lt;/i&gt;</translation>
</message>
<message>
<location filename="../../model/tool/ToolModel.cpp" line="530"/>
<source>conversation_message_content_deleted_by_us_label</source>
<extracomment>&quot;&lt;i&gt;You have deleted this message&lt;/i&gt;&quot;</extracomment>
<translation>&lt;i&gt;You have deleted this message&lt;/i&gt;</translation>
</message>
</context>
<context>
<name>Utils</name>
@ -5984,18 +6056,36 @@ To enable them in a commercial project, please contact us.</translation>
<extracomment>Cannot reply to invalid message</extracomment>
<translation>Cannot reply to invalid message</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="2123"/>
<source>chat_message_edit_error</source>
<extracomment>Cannot modify invalid message</extracomment>
<translation>Cannot modify invalid message</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="2129"/>
<source>info_popup_reply_message_error</source>
<extracomment>Could not send reply message : %1</extracomment>
<translation>Could not send reply message : %1</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="2129"/>
<source>info_popup_edited_message_error</source>
<extracomment>Could not send edited message : %1</extracomment>
<translation>Could not send edited message : %1</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="2156"/>
<source>info_popup_send_reply_message_error_message</source>
<extracomment>Failed to create reply message</extracomment>
<translation>Failed to create reply message</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="2156"/>
<source>info_popup_send_edited_message_error_message</source>
<extracomment>Failed to create edited message</extracomment>
<translation>Failed to create edited message</translation>
</message>
<message numerus="yes">
<location filename="../../tool/Utils.cpp" line="2278"/>
<source>nHour</source>

View file

@ -493,6 +493,12 @@
<extracomment>&quot;URL du serveur déchange de clés de chiffrement&quot;</extracomment>
<translation>URL du serveur déchange de clés de chiffrement</translation>
</message>
<message>
<location filename="../../view/Page/Layout/Settings/AccountSettingsParametersLayout.qml"/>
<source>account_settings_ccmp_server_url_title</source>
<extracomment>&quot;URL du serveur CCMP&quot;</extracomment>
<translation>URL du serveur CCMP</translation>
</message>
</context>
<context>
<name>AddParticipantsForm</name>
@ -1083,49 +1089,49 @@
<context>
<name>CallListView</name>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="60"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="62"/>
<source>meeting</source>
<extracomment>&quot;Réunion</extracomment>
<translation>Réunion</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="62"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="64"/>
<source>call</source>
<extracomment>&quot;Appel&quot;</extracomment>
<translation>Appel</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="67"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="69"/>
<source>paused_call_or_meeting</source>
<extracomment>&quot;%1 en pause&quot;</extracomment>
<translation>%1 en pause</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="69"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="71"/>
<source>ongoing_call_or_meeting</source>
<extracomment>&quot;%1 en cours&quot;</extracomment>
<translation>%1 en cours</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="89"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="91"/>
<source>transfer_call_name_accessible_name</source>
<extracomment>Transfer call %1</extracomment>
<translation>Transférer l&apos;appel %1</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="117"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="119"/>
<source>resume_call_name_accessible_name</source>
<extracomment>Resume %1 call</extracomment>
<translation>Reprendre l&apos;appel %1</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="119"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="121"/>
<source>pause_call_name_accessible_name</source>
<extracomment>Pause %1 call</extracomment>
<translation>Mettre l&apos;appel %1 en pause</translation>
</message>
<message>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="142"/>
<location filename="../../view/Control/Display/Call/CallListView.qml" line="144"/>
<source>end_call_name_accessible_name</source>
<extracomment>End %1 call</extracomment>
<translation>Terminer l&apos;appel %1</translation>
@ -2212,6 +2218,12 @@
<extracomment>&quot;Reception info&quot;</extracomment>
<translation>Info de réception</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessage.qml" line="407"/>
<source>menu_edit_chat_message</source>
<extracomment>&quot;Edit&quot;</extracomment>
<translation>Modifier</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessage.qml" line="419"/>
<source>chat_message_reply</source>
@ -2230,6 +2242,12 @@
<extracomment>&quot;Delete&quot;</extracomment>
<translation>Supprimer</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessage.qml" line="469"/>
<source>conversation_message_edited_label</source>
<extracomment>&quot;Edited&quot;</extracomment>
<translation>Modifié</translation>
</message>
</context>
<context>
<name>ChatMessageContentCore</name>
@ -2480,6 +2498,42 @@ en bout. Seul votre correspondant peut les déchiffrer.</translation>
<extracomment>%1 is writing</extracomment>
<translation>%1 est en train d&apos;écrire</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="470"/>
<source>conversation_dialog_delete_chat_message_title</source>
<extracomment>&quot;Delete this message?&quot;</extracomment>
<translation>Supprimer le message ?</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="471"/>
<source>conversation_dialog_delete_locally_label</source>
<extracomment>&quot;For me&quot;</extracomment>
<translation>Pour moi</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="472"/>
<source>conversation_dialog_delete_for_everyone_label</source>
<extracomment>&quot;For everyone&quot;</extracomment>
<translation>Pour tout le monde</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="472"/>
<source>dialog_cancel</source>
<extracomment>&quot;Cancel&quot;</extracomment>
<translation>Annuler</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="472"/>
<source>info_toast_deleted_title</source>
<extracomment>Deleted</extracomment>
<translation>Supprimé</translation>
</message>
<message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="472"/>
<source>info_toast_deleted_message</source>
<extracomment>The message has been deleted</extracomment>
<translation>Le message a é supprimé</translation>
</message>
</context>
<context>
<name>ChatPage</name>
@ -4887,7 +4941,7 @@ Expiration : %1</translation>
<context>
<name>NewCallForm</name>
<message>
<location filename="../../view/Page/Form/Call/NewCallForm.qml" line="24"/>
<location filename="../../view/Page/Form/Call/NewCallForm.qml" line="25"/>
<source>call_transfer_active_calls_label</source>
<extracomment>&quot;Appels en cours&quot;</extracomment>
<translation>Appels en cours</translation>
@ -5753,6 +5807,12 @@ Pour les activer dans un projet commercial, merci de nous contacter.</translatio
<extracomment>Reply to %1</extracomment>
<translation>Réponse à %1</translation>
</message>
<message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="417"/>
<source>conversation_editing_message_title</source>
<extracomment>Message beeing edited</extracomment>
<translation>Modification du message</translation>
</message>
<message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="617"/>
<source>shared_medias_title</source>
@ -5941,6 +6001,18 @@ Pour les activer dans un projet commercial, merci de nous contacter.</translatio
<source>conference_invitation_updated</source>
<translation>Modification d&apos;une réunion</translation>
</message>
<message>
<location filename="../../model/tool/ToolModel.cpp" line="530"/>
<source>conversation_message_content_deleted_label</source>
<extracomment>&quot;&lt;i&gt;This message has been deleted&lt;/i&gt;&quot;</extracomment>
<translation>&lt;i&gt;Le message a é supprimé&lt;/i&gt;</translation>
</message>
<message>
<location filename="../../model/tool/ToolModel.cpp" line="530"/>
<source>conversation_message_content_deleted_by_us_label</source>
<extracomment>&quot;&lt;i&gt;You have deleted this message&lt;/i&gt;&quot;</extracomment>
<translation>&lt;i&gt;Vous avez supprimé le message&lt;/i&gt;</translation>
</message>
</context>
<context>
<name>Utils</name>
@ -6156,18 +6228,36 @@ Failed to create 1-1 conversation with %1 !</extracomment>
<extracomment>Cannot reply to invalid message</extracomment>
<translation>Impossible de répondre : message invalide</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="2123"/>
<source>chat_message_edit_error</source>
<extracomment>Cannot modify invalid message</extracomment>
<translation>Impossible de modifier le message : message invalide</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="2129"/>
<source>info_popup_reply_message_error</source>
<extracomment>Could not send reply message : %1</extracomment>
<translation>Impossible d&apos;envoyer la réponse : %1</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="2129"/>
<source>info_popup_edited_message_error</source>
<extracomment>Could not send edited message : %1</extracomment>
<translation>Impossible d&apos;envoyer le message modifié : %1</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="2156"/>
<source>info_popup_send_reply_message_error_message</source>
<extracomment>Failed to create reply message</extracomment>
<translation>Impossible de créer le message</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="2156"/>
<source>info_popup_send_edited_message_error_message</source>
<extracomment>Failed to create edited message</extracomment>
<translation>Impossible de créer le message modifié</translation>
</message>
<message>
<location filename="../../tool/Utils.cpp" line="2194"/>
<source>info_popup_send_voice_message_error_message</source>

View file

@ -148,7 +148,7 @@ void AccountModel::removeAccount() {
? Utils::coreStringToAppString(params->getIdentityAddress()->asString())
: "Null");
mToRemove = true;
if (mMonitor) core->removeAccount(mMonitor);
if (mMonitor) core->removeAccountWithData(mMonitor);
}
std::shared_ptr<linphone::Account> AccountModel::getAccount() const {
@ -605,4 +605,16 @@ bool AccountModel::forwardToVoiceMailInDndPresence() {
std::list<std::shared_ptr<linphone::ChatRoom>> AccountModel::getChatRooms() {
return mMonitor->getChatRooms();
}
}
QString AccountModel::getCcmpServerUrl() const {
return Utils::coreStringToAppString(mMonitor->getParams()->getCcmpServerUrl());
}
void AccountModel::setCcmpServerUrl(QString value) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto params = mMonitor->getParams()->clone();
params->setCcmpServerUrl(Utils::appStringToCoreString(value));
mMonitor->setParams(params);
emit ccmpServerUrlChanged(value);
}

View file

@ -91,6 +91,8 @@ public:
std::string configAccountSection();
bool forwardToVoiceMailInDndPresence();
std::list<std::shared_ptr<linphone::ChatRoom>> getChatRooms();
QString getCcmpServerUrl() const;
void setCcmpServerUrl(QString value);
signals:
void registrationStateChanged(const std::shared_ptr<linphone::Account> &account,
@ -126,6 +128,7 @@ signals:
void showMwiChanged(bool show);
void voicemailAddressChanged(QString value);
void presenceChanged(LinphoneEnums::Presence presence, bool userInitiated);
void ccmpServerUrlChanged(QString value);
void setValueFailed(const QString &errorMessage);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
* Copyright (c) 2010-2026 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
@ -529,3 +529,27 @@ void CallModel::onRemoteRecording(const std::shared_ptr<linphone::Call> &call, b
void CallModel::onAuthenticationTokenVerified(const std::shared_ptr<linphone::Call> &call, bool verified) {
emit authenticationTokenVerified(call, verified);
}
void CallModel::onHeadsetAnswerCallRequested(const std::shared_ptr<linphone::Call> &call) {
emit headsetAnswerCallRequested();
}
void CallModel::onHeadsetEndCallRequested(const std::shared_ptr<linphone::Call> &call) {
emit headsetEndCallRequested();
}
void CallModel::onHeadsetHoldCallRequested(const std::shared_ptr<linphone::Call> &call) {
emit headsetHoldCallRequested();
}
void CallModel::onHeadsetMicrophoneMuteToggled(const std::shared_ptr<linphone::Call> &call, bool mute) {
emit headsetMicrophoneMuteToggled(mute);
}
void CallModel::onHeadsetRejectCallRequested(const std::shared_ptr<linphone::Call> &call) {
emit headsetRejectCallRequested();
}
void CallModel::onHeadsetResumeCallRequested(const std::shared_ptr<linphone::Call> &call) {
emit headsetResumeCallRequested();
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2024 Belledonne Communications SARL.
* Copyright (c) 2010-2026 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
@ -156,6 +156,12 @@ private:
const std::shared_ptr<linphone::AudioDevice> &audioDevice) override;
virtual void onRemoteRecording(const std::shared_ptr<linphone::Call> &call, bool recording) override;
virtual void onAuthenticationTokenVerified(const std::shared_ptr<linphone::Call> &call, bool verified) override;
virtual void onHeadsetAnswerCallRequested(const std::shared_ptr<linphone::Call> &call) override;
virtual void onHeadsetEndCallRequested(const std::shared_ptr<linphone::Call> &call) override;
virtual void onHeadsetHoldCallRequested(const std::shared_ptr<linphone::Call> &call) override;
virtual void onHeadsetMicrophoneMuteToggled(const std::shared_ptr<linphone::Call> &call, bool mute) override;
virtual void onHeadsetRejectCallRequested(const std::shared_ptr<linphone::Call> &call) override;
virtual void onHeadsetResumeCallRequested(const std::shared_ptr<linphone::Call> &call) override;
signals:
void dtmfReceived(const std::shared_ptr<linphone::Call> &call, int dtmf);
@ -185,6 +191,12 @@ signals:
const std::shared_ptr<linphone::AudioDevice> &audioDevice);
void remoteRecording(const std::shared_ptr<linphone::Call> &call, bool recording);
void authenticationTokenVerified(const std::shared_ptr<linphone::Call> &call, bool verified);
void headsetAnswerCallRequested();
void headsetEndCallRequested();
void headsetHoldCallRequested();
void headsetMicrophoneMuteToggled(bool mute);
void headsetRejectCallRequested();
void headsetResumeCallRequested();
};
#endif

View file

@ -185,6 +185,11 @@ ChatModel::createReplyMessage(const std::shared_ptr<linphone::ChatMessage> &mess
return mMonitor->createReplyMessage(message);
}
std::shared_ptr<linphone::ChatMessage>
ChatModel::createReplacesMessage(const std::shared_ptr<linphone::ChatMessage> &message) {
return mMonitor->createReplacesMessage(message);
}
std::shared_ptr<linphone::ChatMessage>
ChatModel::createForwardMessage(const std::shared_ptr<linphone::ChatMessage> &message) {
return mMonitor->createForwardMessage(message);

View file

@ -68,6 +68,7 @@ public:
std::shared_ptr<linphone::ChatMessage> createReplyMessage(const std::shared_ptr<linphone::ChatMessage> &message);
std::shared_ptr<linphone::ChatMessage> createForwardMessage(const std::shared_ptr<linphone::ChatMessage> &message);
std::shared_ptr<linphone::ChatMessage> createReplacesMessage(const std::shared_ptr<linphone::ChatMessage> &message);
std::shared_ptr<linphone::ChatMessage> createTextMessageFromText(QString text);
std::shared_ptr<linphone::ChatMessage> createMessage(QString text,

View file

@ -51,7 +51,7 @@ ChatMessageModel::~ChatMessageModel() {
}
QString ChatMessageModel::getText() const {
return ToolModel::getMessageFromContent(mMonitor->getContents());
return ToolModel::getMessageFromMessage(mMonitor);
}
QString ChatMessageModel::getUtf8Text() const {
@ -103,6 +103,13 @@ void ChatMessageModel::deleteMessageFromChatRoom(bool deletedByUser) {
}
}
void ChatMessageModel::retractMessageFromChatRoom() {
auto chatRoom = mMonitor->getChatRoom();
if (chatRoom) {
chatRoom->retractMessage(mMonitor);
}
}
void ChatMessageModel::sendReaction(const QString &reaction) {
auto linReaction = mMonitor->createReaction(Utils::appStringToCoreString(reaction));
linReaction->send();
@ -188,3 +195,11 @@ void ChatMessageModel::onEphemeralMessageTimerStarted(const std::shared_ptr<linp
void ChatMessageModel::onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> &message) {
emit ephemeralMessageDeleted(message);
}
void ChatMessageModel::onRetracted(const std::shared_ptr<linphone::ChatMessage> &message) {
emit retracted(message);
}
void ChatMessageModel::onContentEdited(const std::shared_ptr<linphone::ChatMessage> &message) {
emit contentEdited(message);
}

View file

@ -52,6 +52,7 @@ public:
void markAsRead();
void deleteMessageFromChatRoom(bool deletedByUser);
void retractMessageFromChatRoom();
void sendReaction(const QString &reaction);
@ -95,6 +96,8 @@ signals:
void ephemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> &message);
void ephemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> &message);
void ephemeralMessageTimeUpdated(const std::shared_ptr<linphone::ChatMessage> &message, int expireTime);
void retracted(const std::shared_ptr<linphone::ChatMessage> &message);
void contentEdited(const std::shared_ptr<linphone::ChatMessage> &message);
private:
linphone::ChatMessage::State mMessageState;
@ -130,6 +133,8 @@ private:
const std::shared_ptr<const linphone::ParticipantImdnState> &state) override;
void onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> &message) override;
void onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> &message) override;
void onRetracted(const std::shared_ptr<linphone::ChatMessage> &message) override;
void onContentEdited(const std::shared_ptr<linphone::ChatMessage> &message) override;
};
#endif
#endif

View file

@ -837,26 +837,13 @@ QString SettingsModel::getDefaultDomain() const {
mConfig->getString(SettingsModel::AppSection, "default_domain", "sip.linphone.org"));
}
void SettingsModel::enableCallForward(QString destination) {
// TODO implement business logic to activate call forward to destination on PBX via external API (contains voicemail
// or a destination).
mConfig->setString(UiSection, "call_forward_to_address", Utils::appStringToCoreString(destination));
emit callForwardToAddressChanged(getCallForwardToAddress());
}
void SettingsModel::disableCallForward() {
// TODO implement business logic to de-activate call forward on PBX via external API
mConfig->setString(UiSection, "call_forward_to_address", "");
}
QString SettingsModel::getCallForwardToAddress() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
return Utils::coreStringToAppString(mConfig->getString(UiSection, "call_forward_to_address", ""));
}
void SettingsModel::setCallForwardToAddress(const QString &data) {
if (data == "") disableCallForward();
else enableCallForward(data);
mConfig->setString(UiSection, "call_forward_to_address", Utils::appStringToCoreString(data)); // TODO implement BL
emit(callForwardToAddressChanged(data));
}
@ -1139,13 +1126,6 @@ DEFINE_GETSET_CONFIG(SettingsModel,
DisableCommandLine,
"disable_command_line",
false)
DEFINE_GETSET_CONFIG(SettingsModel,
bool,
Bool,
disableCallForward,
DisableCallForward,
"disable_call_forward",
true)
DEFINE_GETSET_CONFIG_STRING(SettingsModel,
themeMainColor,
ThemeMainColor,

View file

@ -223,7 +223,6 @@ public:
DECLARE_GETSET(bool, usernameOnlyForCardDAVLookupsInCalls, UsernameOnlyForCardDAVLookupsInCalls)
DECLARE_GETSET(QString, commandLine, CommandLine)
DECLARE_GETSET(bool, disableCommandLine, DisableCommandLine)
DECLARE_GETSET(bool, disableCallForward, DisableCallForward)
DECLARE_GETSET(QString, callForwardToAddress, CallForwardToAddress)
DECLARE_GETSET(QString, chatNotificationSoundPath, ChatNotificationSoundPath)
DECLARE_GETSET(QString, themeMainColor, ThemeMainColor)
@ -293,7 +292,6 @@ private:
VfsUtils mVfsUtils;
#endif
void enableCallForward(QString destination);
void disableCallForward();
static std::shared_ptr<SettingsModel> gSettingsModel;

View file

@ -537,6 +537,15 @@ QString ToolModel::getMessageFromContent(std::list<std::shared_ptr<linphone::Con
return res;
}
QString ToolModel::getMessageFromMessage(std::shared_ptr<linphone::ChatMessage> message) {
if (message->isRetracted()) {
return message->isOutgoing() ? tr("conversation_message_content_deleted_by_us_label")
: tr("conversation_message_content_deleted_label");
} else {
return getMessageFromContent(message->getContents());
}
}
// Load downloaded codecs like OpenH264 (needs to be after core is created and has loaded its plugins, as
// reloadMsPlugins modifies plugin path for the factory)
void ToolModel::loadDownloadedCodecs() {

View file

@ -77,6 +77,7 @@ public:
const std::shared_ptr<linphone::Friend> &f);
static QString getMessageFromContent(std::list<std::shared_ptr<linphone::Content>> contents);
static QString getMessageFromMessage(std::shared_ptr<linphone::ChatMessage> message);
static void loadDownloadedCodecs();
static void updateCodecs();

View file

@ -2159,6 +2159,50 @@ void Utils::sendReplyMessage(ChatMessageGui *message, ChatGui *chatGui, QString
});
}
void Utils::sendReplaceMessage(ChatMessageGui *message, ChatGui *chatGui, QString text, QVariantList files) {
auto chatModel = chatGui && chatGui->mCore ? chatGui->mCore->getModel() : nullptr;
auto chatMessageModel = message && message->mCore ? message->mCore->getModel() : nullptr;
if (!chatModel || !chatMessageModel) {
//: Cannot edit to invalid message
QString error = !chatMessageModel ? tr("chat_message_edit_error")
//: Error in the chat
: tr("chat_error");
//: Error
showInformationPopup(tr("info_popup_error_title"),
//: Could not send edited message : %1
tr("info_popup_edited_message_error").arg(error));
return;
}
QList<std::shared_ptr<ChatMessageContentModel>> filesContent;
for (auto &file : files) {
auto contentGui = qvariant_cast<ChatMessageContentGui *>(file);
if (contentGui) {
auto contentCore = contentGui->mCore;
filesContent.append(contentCore->getContentModel());
}
}
App::postModelAsync([chatModel, chatMessageModel, text, filesContent] {
mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO));
auto chat = chatModel->getMonitor();
auto messageToEdit = chatMessageModel->getMonitor();
auto linMessage = chatModel->createReplacesMessage(messageToEdit);
if (linMessage) {
linMessage->addUtf8TextContent(Utils::appStringToCoreString(text));
for (auto &content : filesContent) {
linMessage->addFileContent(content->getContent());
}
linMessage->send();
} else {
App::postCoreAsync([] {
//: Error
showInformationPopup(tr("info_popup_error_title"),
//: Failed to create edited message
tr("info_popup_send_edited_message_error_message"));
});
}
});
}
VariantObject *Utils::createVoiceRecordingMessage(RecorderGui *recorderGui, ChatGui *chatGui) {
VariantObject *data = new VariantObject("createVoiceRecordingMessage");
if (!data) return nullptr;

View file

@ -183,6 +183,8 @@ public:
Q_INVOKABLE static void
sendReplyMessage(ChatMessageGui *message, ChatGui *chatGui, QString text, QVariantList files);
Q_INVOKABLE static void forwardMessageTo(ChatMessageGui *message, ChatGui *chatGui);
Q_INVOKABLE static void
sendReplaceMessage(ChatMessageGui *message, ChatGui *chatGui, QString text, QVariantList files);
Q_INVOKABLE static void sendVoiceRecordingMessage(RecorderGui *recorderGui, ChatGui *chatGui);
Q_INVOKABLE static QString getEphemeralFormatedTime(int selectedTime);

View file

@ -11,19 +11,21 @@ import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
ListView {
id: mainItem
model: CallProxy {
id: callProxy
sourceModel: AppCpp.calls
}
implicitHeight: contentHeight
spacing: Utils.getSizeWithScreenRatio(15)
clip: true
onCountChanged: forceLayout()
signal transferCallToAnotherRequested(CallGui dest)
property bool isTransferList: false
property string currentRemoteAddress: AppCpp.calls.currentCall ? AppCpp.calls.currentCall.core.remoteAddress : ""
signal transferCallToAnotherRequested(CallGui dest)
onCountChanged: forceLayout()
model: CallProxy {
id: callProxy
sourceModel: AppCpp.calls
showCurrentCall: !mainItem.isTransferList
}
delegate: RowLayout {
id: callInformationItem

View file

@ -32,6 +32,7 @@ Control.Control {
leftPadding: isRemoteMessage ? Utils.getSizeWithScreenRatio(5) : 0
signal messageDeletionRequested()
signal messageEditionRequested()
signal isFileHoveringChanged(bool isFileHovering)
signal showReactionsForMessageRequested()
signal showImdnStatusForMessageRequested()
@ -247,11 +248,21 @@ Control.Control {
}
contentItem: ColumnLayout {
spacing: Utils.getSizeWithScreenRatio(5)
Text {
id: retractedId
visible: mainItem.chatMessage.core.isRetracted
font: Typography.p1i
color: DefaultStyle.info_800_main
Layout.fillWidth: true
Layout.fillHeight: true
text: mainItem.chatMessage.core.text
}
ChatMessageContent {
id: chatBubbleContent
Layout.fillWidth: true
Layout.fillHeight: true
chatGui: mainItem.chat
visible: !mainItem.chatMessage.core.isRetracted
searchedTextPart: mainItem.searchedTextPart
chatMessageGui: mainItem.chatMessage
maxWidth: mainItem.maxWidth
@ -287,16 +298,26 @@ Control.Control {
}
}
RowLayout {
spacing: mainItem.isRemoteMessage ? 0 : Utils.getSizeWithScreenRatio(5)
spacing: mainItem.isRemoteMessage && !mainItem.chatMessage.core.isEdited ? 0 : Utils.getSizeWithScreenRatio(5)
Layout.alignment: Qt.AlignVCenter
Layout.preferredHeight: childrenRect.height
Text {
Layout.alignment: Qt.AlignVCenter
text: qsTr("conversation_message_edited_label")
visible: mainItem.chatMessage.core.isEdited
color: DefaultStyle.main2_500_main
font {
pixelSize: Typography.p3.pixelSize
weight: Typography.p3.weight
}
}
Text {
Layout.alignment: Qt.AlignVCenter
text: UtilsCpp.formatDate(mainItem.chatMessage.core.timestamp, true, false, "dd/MM")
color: DefaultStyle.main2_500_main
font {
pixelSize: Typography.p3.pixelSize
weight: Typography.p3.weight
pixelSize: Typography.p3.pixelSize
weight: Typography.p3.weight
}
}
EffectImage {
@ -413,8 +434,22 @@ Control.Control {
optionsMenu.close()
}
}
IconLabelButton {
inverseLayout: true
//: "Edit"
text: qsTr("menu_edit_chat_message")
visible: mainItem.chatMessage.core.isEditable
icon.source: AppIcons.pencil
Layout.fillWidth: true
Layout.preferredHeight: Utils.getSizeWithScreenRatio(45)
onClicked: {
mainItem.messageEditionRequested()
optionsMenu.close()
}
}
IconLabelButton {
inverseLayout: true
visible: !mainItem.chatMessage.core.isRetracted
//: Reply
text: qsTr("chat_message_reply")
icon.source: AppIcons.reply
@ -427,6 +462,7 @@ Control.Control {
}
IconLabelButton {
inverseLayout: true
visible: !mainItem.chatMessage.core.isRetracted
text: chatBubbleContent.selectedText != ""
//: "Copy selection"
? qsTr("chat_message_copy_selection")
@ -447,6 +483,7 @@ Control.Control {
}
IconLabelButton {
inverseLayout: true
visible: !mainItem.chatMessage.core.isRetracted
//: Forward
text: qsTr("chat_message_forward")
icon.source: AppIcons.forward

View file

@ -158,10 +158,21 @@ ColumnLayout {
}
}
Text {
text: conferenceInfo.dateTime.toLocaleString(Qt.locale(), "dddd d MMMM yyyy")
font: Typography.p4
color: DefaultStyle.main2_500_main
RowLayout {
spacing: Utils.getSizeWithScreenRatio(8)
Text {
text: conferenceInfo.dateTime.toLocaleString(Qt.locale(), "dddd d MMMM yyyy")
font: Typography.p4
color: DefaultStyle.main2_500_main
}
RoundButton {
id: calendarPlusButton
style: ButtonStyle.noBackground
icon.source: AppIcons.calendarPlus
onClicked: {
conferenceInfo.exportConferenceToICS()
}
}
}
Text {
//: from %1 to %2 (UTC%3)

View file

@ -25,6 +25,7 @@ ListView {
signal showImdnStatusForMessageRequested(ChatMessageGui chatMessage)
signal replyToMessageRequested(ChatMessageGui chatMessage)
signal forwardMessageRequested(ChatMessageGui chatMessage)
signal editMessageRequested(ChatMessageGui chatMessage)
signal requestHighlight(int indexToHighlight)
signal requestAutoPlayVoiceRecording(int indexToPlay)
currentIndex: -1
@ -225,6 +226,51 @@ ListView {
indicatorColor: DefaultStyle.main1_500_main
}
Dialog {
id: messageDeletionDialog
width: Utils.getSizeWithScreenRatio(637)
//: "Supprimer le message ?"
title: qsTr("conversation_dialog_delete_chat_message_title")
property var chatMessage
buttons: RowLayout {
id: buttonsLayout
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
spacing: Utils.getSizeWithScreenRatio(20)
MediumButton {
id: firstButtonId
text: qsTr("conversation_dialog_delete_locally_label")
style: ButtonStyle.main
onClicked: {
messageDeletionDialog.chatMessage.core.lDelete()
messageDeletionDialog.close()
}
KeyNavigation.left: thirdButtonId
KeyNavigation.right: secondButtonId
}
MediumButton {
id: secondButtonId
text: qsTr("conversation_dialog_delete_for_everyone_label")
style: ButtonStyle.main
onClicked: {
messageDeletionDialog.chatMessage.core.lRetract()
messageDeletionDialog.close()
}
KeyNavigation.left: firstButtonId
KeyNavigation.right: thirdButtonId
}
MediumButton {
id: thirdButtonId
text: qsTr("dialog_cancel")
style: ButtonStyle.secondary
onClicked: {
messageDeletionDialog.close()
}
KeyNavigation.left: secondButtonId
KeyNavigation.right: firstButtonId
}
}
}
delegate: DelegateChooser {
role: "eventType"
DelegateChoice {
@ -262,7 +308,15 @@ ListView {
? parent.right
: undefined
onMessageDeletionRequested: chatMessage.core.lDelete()
onMessageDeletionRequested: {
if (chatMessage.core.isOutgoing && chatMessage.core.isRetractable && !chatMessage.core.isRetracted) {
messageDeletionDialog.chatMessage = chatMessage
messageDeletionDialog.open()
} else {
chatMessage.core.lDelete()
}
}
onMessageEditionRequested: mainItem.editMessageRequested(chatMessage)
onShowReactionsForMessageRequested: mainItem.showReactionsForMessageRequested(chatMessage)
onShowImdnStatusForMessageRequested: mainItem.showImdnStatusForMessageRequested(chatMessage)
onReplyToMessageRequested: mainItem.replyToMessageRequested(chatMessage)
@ -283,6 +337,16 @@ ListView {
}
}
}
Connections {
target: chatMessage.core
onIsRetractedChanged: {
if (chatMessage.core.isRetracted && chatMessage.core.isOutgoing) {
UtilsCpp.showInformationPopup(qsTr("info_toast_deleted_title"),
//: The message has been deleted
qsTr("info_toast_deleted_message"), true)
}
}
}
}
}

View file

@ -23,6 +23,7 @@ Control.Control {
// disable record button if call ongoing
property bool callOngoing: false
property bool isEditing: false
property ChatGui chat
@ -78,6 +79,7 @@ Control.Control {
spacing: Utils.getSizeWithScreenRatio(16)
PopupButton {
id: emojiPickerButton
visible: !mainItem.isEditing
style: ButtonStyle.noBackground
icon.source: checked ? AppIcons.closeX : AppIcons.smiley
popup.width: Utils.getSizeWithScreenRatio(393)
@ -189,7 +191,7 @@ Control.Control {
//: Cannot record a message while a call is ongoing
ToolTip.text: qsTr("cannot_record_while_in_call_tooltip")
enabled: !mainItem.callOngoing
visible: !mainItem.callOngoing && sendingTextArea.text.length === 0 && mainItem.selectedFilesCount === 0
visible: !mainItem.callOngoing && sendingTextArea.text.length === 0 && mainItem.selectedFilesCount === 0 && !mainItem.isEditing
style: ButtonStyle.noBackground
hoverEnabled: true
icon.source: AppIcons.microphone
@ -202,7 +204,7 @@ Control.Control {
Layout.preferredHeight: height
visible: sendingTextArea.text.length !== 0 || mainItem.selectedFilesCount > 0
style: ButtonStyle.noBackgroundOrange
icon.source: AppIcons.paperPlaneRight
icon.source: mainItem.isEditing ? AppIcons.pencil : AppIcons.paperPlaneRight
onClicked: {
mainItem.sendMessage()
}

View file

@ -20,6 +20,7 @@ CreationFormLayout {
topLayoutVisible: mainItem.displayCurrentCalls && callList.count > 0
topContent: [
Text {
visible: callList.count > 0
//: "Appels en cours"
text: qsTr("call_transfer_active_calls_label")
font {

View file

@ -21,6 +21,7 @@ FocusScope {
property CallGui call
property alias callHeaderContent: splitPanel.header.contentItem
property bool replyingToMessage: false
property bool editingMessage: false
enum PanelType { MessageReactions, SharedFiles, Medias, ImdnStatus, ForwardToList, ManageParticipants, EphemeralSettings, None}
signal oneOneCall(bool video)
@ -299,11 +300,19 @@ FocusScope {
onReplyToMessageRequested: (chatMessage) => {
mainItem.chatMessage = chatMessage
mainItem.replyingToMessage = true
if (mainItem.editingMessage) mainItem.editingMessage = false
}
onForwardMessageRequested: (chatMessage) => {
mainItem.chatMessage = chatMessage
contentLoader.panelType = SelectedChatView.PanelType.ForwardToList
detailsPanel.visible = true
if (mainItem.editingMessage) mainItem.editingMessage = false
}
onEditMessageRequested: (chatMessage) => {
mainItem.chatMessage = chatMessage
mainItem.editingMessage = true
if (mainItem.replyingToMessage) mainItem.replyingToMessage = false
messageSender.text = chatMessage.core.text
}
}
ScrollBar {
@ -367,7 +376,7 @@ FocusScope {
}
Control.Control {
id: selectedFilesArea
visible: selectedFiles.count > 0 || mainItem.replyingToMessage
visible: selectedFiles.count > 0 || mainItem.replyingToMessage || mainItem.editingMessage
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
topPadding: Utils.getSizeWithScreenRatio(12)
@ -384,7 +393,12 @@ FocusScope {
style: ButtonStyle.noBackground
onClicked: {
contents.clear()
mainItem.replyingToMessage = false
if (mainItem.replyingToMessage)
mainItem.replyingToMessage = false
else if (mainItem.editingMessage) {
mainItem.editingMessage = false
messageSender.text = ""
}
}
}
background: Item{
@ -410,11 +424,13 @@ FocusScope {
ColumnLayout {
id: replyLayout
spacing: 0
visible: mainItem.chatMessage && mainItem.replyingToMessage
visible: mainItem.chatMessage && (mainItem.replyingToMessage || mainItem.editingMessage)
Text {
Layout.fillWidth: true
//: Reply to %1
text: mainItem.chatMessage ? qsTr("reply_to_label").arg(UtilsCpp.boldTextPart(mainItem.chatMessage.core.fromName, mainItem.chatMessage.core.fromName)) : ""
text: mainItem.replyingToMessage ?
(mainItem.chatMessage ? qsTr("reply_to_label").arg(UtilsCpp.boldTextPart(mainItem.chatMessage.core.fromName, mainItem.chatMessage.core.fromName)) : "")
: qsTr("conversation_editing_message_title")
color: DefaultStyle.main2_500_main
font {
pixelSize: Typography.p3.pixelSize
@ -489,6 +505,7 @@ FocusScope {
chat: mainItem.chat
selectedFilesCount: contents.count
callOngoing: mainItem.call != null
isEditing: mainItem.editingMessage
onChatChanged: {
if (chat) messageSender.text = mainItem.chat.core.sendingText
}
@ -507,6 +524,10 @@ FocusScope {
mainItem.replyingToMessage = false
UtilsCpp.sendReplyMessage(mainItem.chatMessage, mainItem.chat, text, filesContents)
}
else if (mainItem.editingMessage) {
UtilsCpp.sendReplaceMessage(mainItem.chatMessage, mainItem.chat, text, filesContents)
mainItem.editingMessage = false
}
else if (filesContents.length === 0)
mainItem.chat.core.lSendTextMessage(text)
else mainItem.chat.core.lSendMessage(text, filesContents)

View file

@ -50,4 +50,8 @@ AbstractSettingsMenu {
qsTr("contact_editor_dialog_abort_confirmation_save")
)
} else {mainItem.goBack()}
Component.onCompleted: {
SettingsCpp.isSaved = true
}
}

View file

@ -207,6 +207,14 @@ AbstractSettingsLayout {
propertyOwnerGui: account
toValidate: true
}
DecoratedTextField {
Layout.fillWidth: true
//: "URL du serveur CCMP"
title: qsTr("account_settings_ccmp_server_url_title")
propertyName: "ccmpServerUrl"
propertyOwnerGui: account
toValidate: true
}
}
}
}

View file

@ -167,6 +167,17 @@ AbstractSettingsLayout {
subTitleText: modelData.core.clockRate + " Hz"
propertyName: "enabled"
propertyOwnerGui: modelData
Connections {
target: modelData.core
function onChanged() { SettingsCpp.isSaved = false }
}
Connections {
target: SettingsCpp
function onIsSavedChanged(saved) {
if (saved)
modelData.core.save()
}
}
}
}
}
@ -194,6 +205,17 @@ AbstractSettingsLayout {
subTitleText: modelData.core.encoderDescription
propertyName: "enabled"
propertyOwnerGui: modelData
Connections {
target: modelData.core
function onChanged() { SettingsCpp.isSaved = false }
}
Connections {
target: SettingsCpp
function onIsSavedChanged(saved) {
if (saved)
modelData.core.save()
}
}
}
}
ListView {

View file

@ -9,11 +9,9 @@ import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
AbstractSettingsLayout {
id: mainItem
width: parent?.width
property bool enableCallForward: SettingsCpp.callForwardToAddress.length > 0
property string localCallForwardToAddress: SettingsCpp.callForwardToAddress
width: parent?.width
contentModel: [
{
@ -23,44 +21,14 @@ AbstractSettingsLayout {
}
]
Connections {
target: SettingsCpp
function onCallForwardToAddressChanged() {
requestTimeOut.stop()
UtilsCpp.getMainWindow().closeLoadingPopup()
UtilsCpp.showInformationPopup("",
SettingsCpp.callForwardToAddress
? qsTr("settings_call_forward_activation_success") + (SettingsCpp.callForwardToAddress == "voicemail" ? qsTr("settings_call_forward_to_voicemail") : SettingsCpp.callForwardToAddress)
: qsTr("settings_call_forward_deactivation_success")
, true)
}
}
Timer {
id: requestTimeOut
interval: 10000
running: false
repeat: false
onTriggered: {
UtilsCpp.getMainWindow().closeLoadingPopup()
UtilsCpp.showInformationPopup("", qsTr("settings_call_forward_address_timeout"), false)
}
}
onSave: {
if (mainItem.enableCallForward && mainItem.localCallForwardToAddress.length == 0) {
if (mainItem.enableCallForward && SettingsCpp.callForwardToAddress.length == 0) {
UtilsCpp.getMainWindow().showInformationPopup("", qsTr("settings_call_forward_address_cannot_be_empty"), false)
return
}
requestTimeOut.start()
if (!mainItem.enableCallForward && SettingsCpp.callForwardToAddress.length > 0) {
UtilsCpp.getMainWindow().showLoadingPopup(qsTr("settings_call_forward_address_progress_disabling") + " ...")
SettingsCpp.callForwardToAddress = ""
} else if (SettingsCpp.callForwardToAddress != mainItem.localCallForwardToAddress) {
UtilsCpp.getMainWindow().showLoadingPopup(qsTr("settings_call_forward_address_progress_enabling")+(mainItem.localCallForwardToAddress === 'voicemail' ? qsTr("settings_call_forward_to_voicemail") : mainItem.localCallForwardToAddress) + " ...")
SettingsCpp.callForwardToAddress = mainItem.localCallForwardToAddress
}
SettingsCpp.save()
}
onUndo: SettingsCpp.undo()
// Generic forward parameters
/////////////////////////////
@ -76,6 +44,11 @@ AbstractSettingsLayout {
subTitleText: qsTr("settings_call_forward_activate_subtitle")
propertyName: "enableCallForward"
propertyOwner: mainItem
onToggled: function () {
SettingsCpp.isSaved = false
if (!mainItem.enableCallForward)
SettingsCpp.callForwardToAddress = ""
}
}
Text {
visible: mainItem.enableCallForward
@ -99,7 +72,7 @@ AbstractSettingsLayout {
Component.onCompleted: {
if (mainItem.enableCallForward) {
forwardDestination.currentIndex =
(mainItem.localCallForwardToAddress === "voicemail" || mainItem.localCallForwardToAddress.length === 0) ? 0 : 1;
(SettingsCpp.callForwardToAddress === "voicemail" || SettingsCpp.callForwardToAddress.length === 0) ? 0 : 1;
} else {
forwardDestination.currentIndex = 0;
}
@ -109,16 +82,16 @@ AbstractSettingsLayout {
if (!forwardDestination.isInitialized)
return;
if (currentIndex == 0)
mainItem.localCallForwardToAddress = "voicemail";
SettingsCpp.callForwardToAddress = "voicemail";
else {
mainItem.localCallForwardToAddress = "";
SettingsCpp.callForwardToAddress = "";
sipInputField.empty();
}
}
onVisibleChanged: {
if (visible) {
currentIndex = 0
mainItem.localCallForwardToAddress = "voicemail";
SettingsCpp.callForwardToAddress = "voicemail";
}
}
@ -127,8 +100,8 @@ AbstractSettingsLayout {
id: sipInputField
visible: mainItem.enableCallForward && forwardDestination.currentIndex == 1
Layout.fillWidth: true
propertyName: "localCallForwardToAddress"
propertyOwner: mainItem
propertyName: "callForwardToAddress"
propertyOwner: SettingsCpp
//: SIP Address
title: qsTr("settings_call_forward_sipaddress_title")
placeHolder: qsTr("settings_call_forward_sipaddress_placeholder")

View file

@ -738,7 +738,7 @@ AbstractMainPage {
KeyNavigation.left: linkButton
KeyNavigation.right: linkButton
KeyNavigation.up: deletePopup
KeyNavigation.down: joinButton
KeyNavigation.down: calendarPlusButton
onClicked: {
var success = UtilsCpp.copyToClipboard(mainItem.selectedConference.core.uri)
if (success) UtilsCpp.showInformationPopup(qsTr("saved"),
@ -767,6 +767,18 @@ AbstractMainPage {
capitalization: Font.Capitalize
}
}
RoundButton {
id: calendarPlusButton
style: ButtonStyle.noBackground
icon.source: AppIcons.calendarPlus
KeyNavigation.left: calendarPlusButton
KeyNavigation.right: calendarPlusButton
KeyNavigation.up: shareNetworkButton
KeyNavigation.down: joinButton
onClicked: {
mainItem.selectedConference.core.exportConferenceToICS()
}
}
}
RowLayout {
spacing: Utils.getSizeWithScreenRatio(8)

View file

@ -124,8 +124,8 @@ AbstractWindow {
function onAssistantGoDirectlyToThirdPartySipAccountLoginChanged() {
initStackViewItem()
}
function onIsSavedChanged() {
if (SettingsCpp.isSaved) UtilsCpp.showInformationPopup(qsTr("information_popup_success_title"),
function onIsSavedChanged(saved) {
if (saved) UtilsCpp.showInformationPopup(qsTr("information_popup_success_title"),
//: "Les changements ont été sauvegardés"
qsTr("information_popup_changes_saved"), true, mainWindow)
}

View file

@ -160,4 +160,5 @@ QtObject {
property string ephemeralSettings: "image://internal/ephemeral-settings.svg"
property string hourglass: "image://internal/hourglass-simple.svg"
property string qtLogo: "image://internal/qt-logo.png"
property string calendarPlus: "image://internal/calendar-plus.svg"
}

View file

@ -47,6 +47,7 @@ QtObject {
property var success_700: "#377d71"
property var success_900: "#1E4C53"
property var info_500_main: "#4AA8FF"
property var info_800_main: "#02528D"
property var vue_meter_light_green: "#6FF88D"
property var vue_meter_dark_green: "#00D916"

View file

@ -81,6 +81,14 @@ QtObject {
weight: Font.Normal
})
// Text/P1i - Paragraph text Italic
property font p1i: Qt.font( {
family: DefaultStyle.defaultFont,
pixelSize: Utils.getSizeWithScreenRatio(14),
weight: Font.Normal,
italic: true
})
// Text/P1s - Paragraph text
property font p1s: Qt.font( {
family: DefaultStyle.defaultFont,

View file

@ -117,12 +117,11 @@ elseif(WIN32)
NAMES msys2_shell.cmd
HINTS "C:/msys64/"
)
set(MSVC_VERSION ${MSVC_TOOLSET_VERSION})
set(CMAKE_INSTALL_UCRT_LIBRARIES TRUE)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_INSTALL_DEBUG_LIBRARIES TRUE)
endif()
include(InstallRequiredSystemLibraries)
endif()
include(InstallRequiredSystemLibraries)
find_file(UCRTBASE_LIB "ucrtbase.dll" PATHS "C:/Windows/System32")
install(FILES ${UCRTBASE_LIB} DESTINATION "${CMAKE_INSTALL_BINDIR}")

@ -1 +1 @@
Subproject commit 3ac59232c3f6c0553226708ef7ce81f716fbb10e
Subproject commit dc5d0d260cc5db90dc4d7dcb49780a12aaada33b