mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 03:18:07 +00:00
Record call + fixes (
remove friend listener fix call history layout (sometimes the details exceeded row bottom) do not open terminate calls popup when all call ended already change '.' with ' ' only if display name is the address initials headers in contact list delegate confirmation dialog delete history use intermediate variable try to fix variant object crash ) recordable option fix effect image not colorized on visible change
This commit is contained in:
parent
4782bd2990
commit
f9abfb9fbc
32 changed files with 583 additions and 328 deletions
|
|
@ -58,6 +58,9 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
|
|||
encryption == LinphoneEnums::MediaEncryption::Dtls;
|
||||
mPaused = mState == LinphoneEnums::CallState::Pausing || mState == LinphoneEnums::CallState::Paused ||
|
||||
mState == LinphoneEnums::CallState::PausedByRemote;
|
||||
mRecording = call->getParams() && call->getParams()->isRecording();
|
||||
mRemoteRecording = call->getRemoteParams() && call->getRemoteParams()->isRecording();
|
||||
mRecordable = mState == LinphoneEnums::CallState::StreamsRunning;
|
||||
}
|
||||
|
||||
CallCore::~CallCore() {
|
||||
|
|
@ -87,6 +90,19 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
mAccountModelConnection->makeConnectToCore(&CallCore::lSetCameraEnabled, [this](bool enabled) {
|
||||
mAccountModelConnection->invokeToModel([this, enabled]() { mCallModel->setCameraEnabled(enabled); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToCore(&CallCore::lStartRecording, [this]() {
|
||||
mAccountModelConnection->invokeToModel([this]() { mCallModel->startRecording(); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToCore(&CallCore::lStopRecording, [this]() {
|
||||
mAccountModelConnection->invokeToModel([this]() { mCallModel->stopRecording(); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToModel(&CallModel::recordingChanged, [this](bool recording) {
|
||||
mAccountModelConnection->invokeToCore([this, recording]() { setRecording(recording); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToModel(
|
||||
&CallModel::remoteRecording, [this](const std::shared_ptr<linphone::Call> &call, bool recording) {
|
||||
mAccountModelConnection->invokeToCore([this, recording]() { setRemoteRecording(recording); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToModel(&CallModel::cameraEnabledChanged, [this](bool enabled) {
|
||||
mAccountModelConnection->invokeToCore([this, enabled]() { setCameraEnabled(enabled); });
|
||||
});
|
||||
|
|
@ -102,6 +118,12 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
mAccountModelConnection->makeConnectToModel(&CallModel::statusChanged, [this](linphone::Call::Status status) {
|
||||
mAccountModelConnection->invokeToCore([this, status]() { setStatus(LinphoneEnums::fromLinphone(status)); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToModel(&CallModel::stateChanged,
|
||||
[this](linphone::Call::State state, const std::string &message) {
|
||||
mAccountModelConnection->invokeToCore([this, state]() {
|
||||
setRecordable(state == linphone::Call::State::StreamsRunning);
|
||||
});
|
||||
});
|
||||
mAccountModelConnection->makeConnectToCore(&CallCore::lSetPaused, [this](bool paused) {
|
||||
mAccountModelConnection->invokeToModel([this, paused]() { mCallModel->setPaused(paused); });
|
||||
});
|
||||
|
|
@ -275,6 +297,36 @@ void CallCore::setRemoteVideoEnabled(bool enabled) {
|
|||
}
|
||||
}
|
||||
|
||||
bool CallCore::getRecording() const {
|
||||
return mRecording;
|
||||
}
|
||||
void CallCore::setRecording(bool recording) {
|
||||
if (mRecording != recording) {
|
||||
mRecording = recording;
|
||||
emit recordingChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool CallCore::getRemoteRecording() const {
|
||||
return mRemoteRecording;
|
||||
}
|
||||
void CallCore::setRemoteRecording(bool recording) {
|
||||
if (mRemoteRecording != recording) {
|
||||
mRemoteRecording = recording;
|
||||
emit remoteRecordingChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool CallCore::getRecordable() const {
|
||||
return mRecordable;
|
||||
}
|
||||
void CallCore::setRecordable(bool recordable) {
|
||||
if (mRecordable != recordable) {
|
||||
mRecordable = recordable;
|
||||
emit recordableChanged();
|
||||
}
|
||||
}
|
||||
|
||||
LinphoneEnums::CallState CallCore::getTransferState() const {
|
||||
return mTransferState;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ class CallCore : public QObject, public AbstractObject {
|
|||
Q_PROPERTY(bool peerSecured READ getPeerSecured WRITE setPeerSecured NOTIFY peerSecuredChanged)
|
||||
Q_PROPERTY(
|
||||
bool remoteVideoEnabled READ getRemoteVideoEnabled WRITE setRemoteVideoEnabled NOTIFY remoteVideoEnabledChanged)
|
||||
Q_PROPERTY(bool recording READ getRecording WRITE setRecording NOTIFY recordingChanged)
|
||||
Q_PROPERTY(bool remoteRecording READ getRemoteRecording WRITE setRemoteRecording NOTIFY remoteRecordingChanged)
|
||||
Q_PROPERTY(bool recordable READ getRecordable WRITE setRecordable NOTIFY recordableChanged)
|
||||
Q_PROPERTY(LinphoneEnums::CallState transferState READ getTransferState NOTIFY transferStateChanged)
|
||||
|
||||
public:
|
||||
|
|
@ -89,6 +92,15 @@ public:
|
|||
bool getRemoteVideoEnabled() const;
|
||||
void setRemoteVideoEnabled(bool enabled);
|
||||
|
||||
bool getRecording() const;
|
||||
void setRecording(bool recording);
|
||||
|
||||
bool getRemoteRecording() const;
|
||||
void setRemoteRecording(bool recording);
|
||||
|
||||
bool getRecordable() const;
|
||||
void setRecordable(bool recordable);
|
||||
|
||||
LinphoneEnums::CallState getTransferState() const;
|
||||
void setTransferState(LinphoneEnums::CallState state, const QString &message);
|
||||
|
||||
|
|
@ -108,6 +120,9 @@ signals:
|
|||
void transferStateChanged();
|
||||
void peerSecuredChanged();
|
||||
void remoteVideoEnabledChanged(bool remoteVideoEnabled);
|
||||
void recordingChanged();
|
||||
void remoteRecordingChanged();
|
||||
void recordableChanged();
|
||||
|
||||
// Linphone commands
|
||||
void lAccept(bool withVideo); // Accept an incoming call
|
||||
|
|
@ -119,6 +134,8 @@ signals:
|
|||
void lSetCameraEnabled(bool enabled);
|
||||
void lSetPaused(bool paused);
|
||||
void lTransferCall(const QString &dest);
|
||||
void lStartRecording();
|
||||
void lStopRecording();
|
||||
|
||||
/* TODO
|
||||
Q_INVOKABLE void acceptWithVideo();
|
||||
|
|
@ -133,13 +150,10 @@ signals:
|
|||
Q_INVOKABLE void rejectVideoRequest();
|
||||
|
||||
Q_INVOKABLE void takeSnapshot();
|
||||
Q_INVOKABLE void startRecording();
|
||||
Q_INVOKABLE void stopRecording();
|
||||
|
||||
Q_INVOKABLE void sendDtmf(const QString &dtmf);
|
||||
Q_INVOKABLE void verifyAuthenticationToken(bool verify);
|
||||
Q_INVOKABLE void updateStreams();
|
||||
Q_INVOKABLE void toggleSpeakerMute();
|
||||
*/
|
||||
private:
|
||||
std::shared_ptr<CallModel> mCallModel;
|
||||
|
|
@ -156,6 +170,9 @@ private:
|
|||
bool mCameraEnabled;
|
||||
bool mPaused = false;
|
||||
bool mRemoteVideoEnabled = false;
|
||||
bool mRecording = false;
|
||||
bool mRemoteRecording = false;
|
||||
bool mRecordable = false;
|
||||
QSharedPointer<SafeConnection<CallCore, CallModel>> mAccountModelConnection;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
|
|
|
|||
|
|
@ -50,7 +50,10 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact) : QObje
|
|||
name.empty() ? Utils::getDisplayName(mAddress)->getValue().toString() : Utils::coreStringToAppString(name);
|
||||
mStarred = contact->getStarred();
|
||||
mIsSaved = true;
|
||||
} else mIsSaved = false;
|
||||
} else {
|
||||
mIsSaved = false;
|
||||
mStarred = false;
|
||||
}
|
||||
}
|
||||
|
||||
FriendCore::FriendCore(const FriendCore &friendCore) {
|
||||
|
|
@ -60,6 +63,8 @@ FriendCore::FriendCore(const FriendCore &friendCore) {
|
|||
}
|
||||
|
||||
FriendCore::~FriendCore() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
emit mFriendModel->removeListener();
|
||||
}
|
||||
|
||||
void FriendCore::setSelf(SafeSharedPointer<FriendCore> me) {
|
||||
|
|
@ -217,7 +222,6 @@ void FriendCore::remove() {
|
|||
|
||||
void FriendCore::save() { // Save Values to model
|
||||
FriendCore *thisCopy = new FriendCore(*this); // Pointer to avoid multiple copies in lambdas
|
||||
auto linphoneAddr = ToolModel::interpretUrl(mAddress);
|
||||
|
||||
if (mFriendModel) {
|
||||
mFriendModelConnection->invokeToModel([this, thisCopy]() { // Copy values to avoid concurrency
|
||||
|
|
@ -227,7 +231,8 @@ void FriendCore::save() { // Save Values to model
|
|||
mFriendModelConnection->invokeToCore([this]() { saved(); });
|
||||
});
|
||||
} else {
|
||||
mCoreModelConnection->invokeToModel([this, thisCopy, linphoneAddr]() {
|
||||
mCoreModelConnection->invokeToModel([this, thisCopy]() {
|
||||
auto linphoneAddr = ToolModel::interpretUrl(mAddress);
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
auto contact = core->findFriend(linphoneAddr);
|
||||
auto friendExists = contact != nullptr;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ bool FriendInitialProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sour
|
|||
QRegularExpression search(mFilterText, QRegularExpression::CaseInsensitiveOption |
|
||||
QRegularExpression::UseUnicodePropertiesOption);
|
||||
auto friendData = sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).value<FriendGui *>();
|
||||
auto name = friendData->getCore()->getName();
|
||||
show = friendData->getCore()->getName().indexOf(search) == 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ class FriendInitialProxy : public SortFilterProxy, public AbstractObject {
|
|||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
|
||||
// Q_PROPERTY(QAbstractItemModel *sourceModel READ sourceModel WRITE setSourceModel NOTIFY sourceModelChanged)
|
||||
|
||||
public:
|
||||
FriendInitialProxy(QObject *parent = Q_NULLPTR);
|
||||
|
|
@ -52,7 +51,6 @@ signals:
|
|||
|
||||
protected:
|
||||
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
// virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||
|
||||
QString mFilterText;
|
||||
QSharedPointer<MagicSearchProxy> mSource;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc
|
|||
"data/image/users-three-selected.svg"
|
||||
"data/image/noItemImage.svg"
|
||||
"data/image/dots-three-vertical.svg"
|
||||
"data/image/more.svg"
|
||||
"data/image/plus-circle.svg"
|
||||
"data/image/microphone-stage.svg"
|
||||
"data/image/group-call.svg"
|
||||
|
|
@ -64,6 +65,7 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc
|
|||
"data/image/empty.svg"
|
||||
"data/image/heart.svg"
|
||||
"data/image/heart-fill.svg"
|
||||
"data/image/record-fill.svg"
|
||||
|
||||
data/shaders/roundEffect.vert.qsb
|
||||
data/shaders/roundEffect.frag.qsb
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
|
||||
|
|
@ -33,7 +33,6 @@ CallHistoryModel::CallHistoryModel(const std::shared_ptr<linphone::CallLog> &cal
|
|||
}
|
||||
|
||||
CallHistoryModel::~CallHistoryModel() {
|
||||
// qDebug() << "[CallHistoryModel] delete" << this;
|
||||
// mustBeInLinphoneThread("~" + getClassName());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <QDebug>
|
||||
|
||||
#include "core/path/Paths.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
|
|
@ -49,6 +50,11 @@ void CallModel::accept(bool withVideo) {
|
|||
auto core = CoreModel::getInstance()->getCore();
|
||||
auto params = core->createCallParams(mMonitor);
|
||||
params->enableVideo(withVideo);
|
||||
params->setRecordFile(
|
||||
Paths::getCapturesDirPath()
|
||||
.append(Utils::generateSavedFilename(QString::fromStdString(mMonitor->getToAddress()->getUsername()), ""))
|
||||
.append(".mkv")
|
||||
.toStdString());
|
||||
mMonitor->enableCamera(withVideo);
|
||||
// Answer with local call address.
|
||||
auto localAddress = mMonitor->getCallLog()->getLocalAddress();
|
||||
|
|
@ -116,6 +122,30 @@ void CallModel::setCameraEnabled(bool enabled) {
|
|||
emit cameraEnabledChanged(enabled);
|
||||
}
|
||||
|
||||
void CallModel::startRecording() {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
mMonitor->startRecording();
|
||||
emit recordingChanged(mMonitor->getParams()->isRecording());
|
||||
}
|
||||
|
||||
void CallModel::stopRecording() {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
mMonitor->stopRecording();
|
||||
emit recordingChanged(mMonitor->getParams()->isRecording());
|
||||
// TODO : display notification
|
||||
}
|
||||
|
||||
void CallModel::setRecordFile(const std::string &path) {
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
auto params = core->createCallParams(mMonitor);
|
||||
params->setRecordFile(path);
|
||||
mMonitor->update(params);
|
||||
}
|
||||
|
||||
std::string CallModel::getRecordFile() const {
|
||||
return mMonitor->getParams()->getRecordFile();
|
||||
}
|
||||
|
||||
std::shared_ptr<const linphone::Address> CallModel::getRemoteAddress() {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
return mMonitor->getRemoteAddress();
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class CallModel : public ::Listener<linphone::Call, linphone::CallListener>,
|
|||
public AbstractObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
CallModel(const std::shared_ptr<linphone::Call> &account, QObject *parent = nullptr);
|
||||
CallModel(const std::shared_ptr<linphone::Call> &call, QObject *parent = nullptr);
|
||||
~CallModel();
|
||||
|
||||
void accept(bool withVideo);
|
||||
|
|
@ -43,10 +43,15 @@ public:
|
|||
void setMicrophoneMuted(bool isMuted);
|
||||
void setSpeakerMuted(bool isMuted);
|
||||
void setCameraEnabled(bool enabled);
|
||||
void startRecording();
|
||||
void stopRecording();
|
||||
void setRecordFile(const std::string &path);
|
||||
|
||||
void setPaused(bool paused);
|
||||
void transferTo(const std::shared_ptr<linphone::Address> &address);
|
||||
void terminateAllCalls();
|
||||
|
||||
std::string getRecordFile() const;
|
||||
std::shared_ptr<const linphone::Address> getRemoteAddress();
|
||||
bool getAuthenticationTokenVerified();
|
||||
|
||||
|
|
@ -57,6 +62,7 @@ signals:
|
|||
void durationChanged(int);
|
||||
void pausedChanged(bool paused);
|
||||
void remoteVideoEnabledChanged(bool remoteVideoEnabled);
|
||||
void recordingChanged(bool recording);
|
||||
|
||||
private:
|
||||
QTimer mDurationTimer;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "ToolModel.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/path/Paths.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
#include <QDebug>
|
||||
|
|
@ -51,7 +52,10 @@ QString ToolModel::getDisplayName(const std::shared_ptr<const linphone::Address>
|
|||
QString displayName;
|
||||
if (address) {
|
||||
displayName = Utils::coreStringToAppString(address->getDisplayName());
|
||||
if (displayName.isEmpty()) displayName = Utils::coreStringToAppString(address->getUsername());
|
||||
if (displayName.isEmpty()) {
|
||||
displayName = Utils::coreStringToAppString(address->getUsername());
|
||||
displayName.replace('.', ' ');
|
||||
}
|
||||
// TODO
|
||||
// std::shared_ptr<linphone::Address> cleanAddress = address->clone();
|
||||
// cleanAddress->clean();
|
||||
|
|
@ -59,7 +63,6 @@ QString ToolModel::getDisplayName(const std::shared_ptr<const linphone::Address>
|
|||
// auto sipAddressEntry = getSipAddressEntry(qtAddress, cleanAddress);
|
||||
// displayName = sipAddressEntry->displayNames.get();
|
||||
}
|
||||
displayName.replace('.', ' ');
|
||||
return displayName;
|
||||
}
|
||||
|
||||
|
|
@ -85,6 +88,14 @@ QSharedPointer<CallCore> ToolModel::createCall(const QString &sipAddress,
|
|||
|
||||
std::shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
|
||||
params->enableVideo(false);
|
||||
if (Utils::coreStringToAppString(params->getRecordFile()).isEmpty()) {
|
||||
|
||||
params->setRecordFile(
|
||||
Paths::getCapturesDirPath()
|
||||
.append(Utils::generateSavedFilename(QString::fromStdString(address->getUsername()), ""))
|
||||
.append(".mkv")
|
||||
.toStdString());
|
||||
}
|
||||
|
||||
QHashIterator<QString, QString> iterator(headers);
|
||||
while (iterator.hasNext()) {
|
||||
|
|
@ -92,8 +103,8 @@ QSharedPointer<CallCore> ToolModel::createCall(const QString &sipAddress,
|
|||
params->addCustomHeader(Utils::appStringToCoreString(iterator.key()),
|
||||
Utils::appStringToCoreString(iterator.value()));
|
||||
}
|
||||
|
||||
if (core->getDefaultAccount()) params->setAccount(core->getDefaultAccount());
|
||||
// CallModel::setRecordFile(params, Utils::coreStringToAppString(address->getUsername()));
|
||||
auto call = core->inviteAddressWithParams(address, params);
|
||||
return call ? CallCore::create(call) : nullptr;
|
||||
|
||||
|
|
|
|||
|
|
@ -239,4 +239,16 @@ QString Utils::formatDateElapsedTime(const QDateTime &date) {
|
|||
|
||||
auto s = dateSec - h * 3600 - m * 60;
|
||||
return QString::number(s) + " s";
|
||||
}
|
||||
|
||||
QString Utils::generateSavedFilename(const QString &from, const QString &to) {
|
||||
auto escape = [](const QString &str) {
|
||||
constexpr char ReservedCharacters[] = "[<|>|:|\"|/|\\\\|\\?|\\*|\\+|\\||_|-]+";
|
||||
static QRegularExpression regexp(ReservedCharacters);
|
||||
return QString(str).replace(regexp, "");
|
||||
};
|
||||
return QStringLiteral("%1_%2_%3")
|
||||
.arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_hh-mm-ss"))
|
||||
.arg(escape(from))
|
||||
.arg(escape(to));
|
||||
}
|
||||
|
|
@ -68,13 +68,14 @@ public:
|
|||
bool dotsSeparator = true); // Return the elapsed time formated
|
||||
Q_INVOKABLE static QString formatDate(const QDateTime &date, bool includeTime = true); // Return the date formated
|
||||
Q_INVOKABLE static QString formatDateElapsedTime(const QDateTime &date); // Return the date formated
|
||||
static QString generateSavedFilename(const QString &from, const QString &to);
|
||||
|
||||
static inline QString coreStringToAppString(const std::string &str) {
|
||||
if (Constants::LinphoneLocaleEncoding == QString("UTF-8")) return QString::fromStdString(str);
|
||||
else
|
||||
return QString::fromLocal8Bit(str.c_str(),
|
||||
int(str.size())); // When using Locale. Be careful about conversion bijection
|
||||
// with UTF-8, you may loss characters
|
||||
int(str.size())); // When using Locale. Be careful about conversion
|
||||
// bijection with UTF-8, you may loss characters
|
||||
}
|
||||
|
||||
static inline std::string appStringToCoreString(const QString &str) {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ Window {
|
|||
}
|
||||
onClosing: (close) => {
|
||||
close.accepted = false
|
||||
terminateAllCallsDialog.open()
|
||||
if (callsModel.haveCall)
|
||||
terminateAllCallsDialog.open()
|
||||
}
|
||||
|
||||
Timer {
|
||||
|
|
@ -69,41 +70,11 @@ Window {
|
|||
}
|
||||
}
|
||||
|
||||
Popup {
|
||||
Dialog {
|
||||
id: terminateAllCallsDialog
|
||||
modal: true
|
||||
anchors.centerIn: parent
|
||||
closePolicy: Control.Popup.NoAutoClose
|
||||
padding: 10 * DefaultStyle.dp
|
||||
contentItem: ColumnLayout {
|
||||
height: terminateAllCallsDialog.height
|
||||
width: 278 * DefaultStyle.dp
|
||||
spacing: 8 * DefaultStyle.dp
|
||||
Text {
|
||||
text: qsTr("La fenêtre est sur le point d'être fermée. Cela terminera tous les appels en cours. Souhaitez vous continuer ?")
|
||||
Layout.preferredWidth: parent.width
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
wrapMode: Text.Wrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Button {
|
||||
text: qsTr("Oui")
|
||||
onClicked: {
|
||||
call.core.lTerminateAllCalls()
|
||||
terminateAllCallsDialog.close()
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: qsTr("Non")
|
||||
onClicked: terminateAllCallsDialog.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
onAccepted: call.core.lTerminateAllCalls()
|
||||
width: 278 * DefaultStyle.dp
|
||||
text: qsTr("La fenêtre est sur le point d'être fermée. Cela terminera tous les appels en cours. Souhaitez vous continuer ?")
|
||||
}
|
||||
|
||||
CallProxy{
|
||||
|
|
@ -127,11 +98,13 @@ Window {
|
|||
required property string enabledIcon
|
||||
property string disabledIcon
|
||||
enabled: call != undefined
|
||||
padding: 18 * DefaultStyle.dp
|
||||
leftPadding: 0
|
||||
rightPadding: 0
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
checkable: true
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
RectangleTest{}
|
||||
color: bottomButton.enabled
|
||||
? disabledIcon
|
||||
? DefaultStyle.grey_500
|
||||
|
|
@ -142,10 +115,10 @@ Window {
|
|||
radius: 71 * DefaultStyle.dp
|
||||
}
|
||||
contentItem: EffectImage {
|
||||
image.source: disabledIcon && bottomButton.checked ? disabledIcon : enabledIcon
|
||||
anchors.fill: parent
|
||||
image.width: 32 * DefaultStyle.dp
|
||||
image.height: 32 * DefaultStyle.dp
|
||||
source: disabledIcon && bottomButton.checked ? disabledIcon : enabledIcon
|
||||
imageWidth: 32 * DefaultStyle.dp
|
||||
imageHeight: 32 * DefaultStyle.dp
|
||||
anchors.centerIn: parent
|
||||
colorizationColor: disabledIcon && bottomButton.checked ? DefaultStyle.main2_0 : DefaultStyle.grey_0
|
||||
}
|
||||
}
|
||||
|
|
@ -211,20 +184,20 @@ Window {
|
|||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: 25 * DefaultStyle.dp
|
||||
RowLayout {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 10 * DefaultStyle.dp
|
||||
EffectImage {
|
||||
id: callStatusIcon
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
image.width: 15 * DefaultStyle.dp
|
||||
image.height: 15 * DefaultStyle.dp
|
||||
image.sourceSize.width: 15 * DefaultStyle.dp
|
||||
image.sourceSize.height: 15 * DefaultStyle.dp
|
||||
image.source: mainWindow.call.core.paused
|
||||
? AppIcons.pause
|
||||
: (mainWindow.call.core.state === LinphoneEnums.CallState.End
|
||||
fillMode: Image.PreserveAspectFit
|
||||
width: 15 * DefaultStyle.dp
|
||||
height: 15 * DefaultStyle.dp
|
||||
source:(mainWindow.call.core.state === LinphoneEnums.CallState.End
|
||||
|| mainWindow.call.core.state === LinphoneEnums.CallState.Released)
|
||||
? AppIcons.endCall
|
||||
? AppIcons.endCall
|
||||
: mainWindow.call.core.paused
|
||||
? AppIcons.pause
|
||||
: mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing
|
||||
? AppIcons.outgoingCall
|
||||
: AppIcons.incomingCall
|
||||
|
|
@ -261,6 +234,23 @@ Window {
|
|||
visible: mainWindow.call.core.state === LinphoneEnums.CallState.Connected
|
||||
|| mainWindow.call.core.state === LinphoneEnums.CallState.StreamsRunning
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
RowLayout {
|
||||
visible: mainWindow.call.core.recording || mainWindow.call.core.remoteRecording
|
||||
Text {
|
||||
color: DefaultStyle.danger_500main
|
||||
font.pixelSize: 14 * DefaultStyle.dp
|
||||
text: mainWindow.call.core.recording ? qsTr("Vous enregistrez l'appel") : qsTr("Votre correspondant enregistre l'appel")
|
||||
}
|
||||
EffectImage {
|
||||
source: AppIcons.recordFill
|
||||
colorizationColor: DefaultStyle.danger_500main
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Control.Control {
|
||||
|
|
@ -481,7 +471,7 @@ Window {
|
|||
visible: parent.visible
|
||||
closeButtonVisible: false
|
||||
onLaunchCall: {
|
||||
var callVarObject = UtilsCpp.createCall(dialerTextInput.text + "@sip.linphone.org")
|
||||
UtilsCpp.createCall(dialerTextInput.text + "@sip.linphone.org")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -595,7 +585,7 @@ Window {
|
|||
background: Item {}
|
||||
contentItem: RowLayout {
|
||||
EffectImage {
|
||||
image.source: AppIcons.endCall
|
||||
source: AppIcons.endCall
|
||||
colorizationColor: DefaultStyle.danger_500main
|
||||
width: 32 * DefaultStyle.dp
|
||||
height: 32 * DefaultStyle.dp
|
||||
|
|
@ -745,7 +735,6 @@ Window {
|
|||
Layout.preferredWidth: 55 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 55 * DefaultStyle.dp
|
||||
onClicked: mainWindow.call.core.lSetCameraEnabled(!mainWindow.call.core.cameraEnabled)
|
||||
|
||||
}
|
||||
BottomButton {
|
||||
enabledIcon: AppIcons.microphone
|
||||
|
|
@ -755,25 +744,27 @@ Window {
|
|||
Layout.preferredHeight: 55 * DefaultStyle.dp
|
||||
onClicked: mainWindow.call.core.lSetMicrophoneMuted(!mainWindow.call.core.microphoneMuted)
|
||||
}
|
||||
BottomButton {
|
||||
PopupButton {
|
||||
id: moreOptionsButton
|
||||
checkable: true
|
||||
enabledIcon: AppIcons.verticalDots
|
||||
Layout.preferredWidth: 55 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 55 * DefaultStyle.dp
|
||||
onPressed: {
|
||||
moreOptionsMenu.visible = !moreOptionsMenu.visible
|
||||
background: Rectangle {
|
||||
anchors.fill: moreOptionsButton
|
||||
color: moreOptionsButton.checked ? DefaultStyle.grey_0 : DefaultStyle.grey_500
|
||||
radius: 40 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Popup {
|
||||
id: moreOptionsMenu
|
||||
x: moreOptionsButton.x
|
||||
y: moreOptionsButton.y - height
|
||||
padding: 20 * DefaultStyle.dp
|
||||
|
||||
// closePolicy: Control.Popup.CloseOnEscape
|
||||
onAboutToHide: moreOptionsButton.checked = false
|
||||
contentItem: ColumnLayout {
|
||||
contentItem: Item {
|
||||
EffectImage {
|
||||
source: AppIcons.more
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
anchors.centerIn: parent
|
||||
colorizationColor: moreOptionsButton.checked ? DefaultStyle.grey_500 : DefaultStyle.grey_0
|
||||
}
|
||||
}
|
||||
popup.x: width/2
|
||||
popup.y: y - popup.height + height/4
|
||||
popup.contentItem: ColumnLayout {
|
||||
id: optionsList
|
||||
spacing: 10 * DefaultStyle.dp
|
||||
|
||||
|
|
@ -785,8 +776,9 @@ Window {
|
|||
}
|
||||
contentItem: RowLayout {
|
||||
Image {
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: AppIcons.callList
|
||||
}
|
||||
Text {
|
||||
|
|
@ -807,8 +799,9 @@ Window {
|
|||
}
|
||||
contentItem: RowLayout {
|
||||
Image {
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: AppIcons.dialer
|
||||
}
|
||||
Text {
|
||||
|
|
@ -829,13 +822,16 @@ Window {
|
|||
visible: false
|
||||
}
|
||||
contentItem: RowLayout {
|
||||
Image {
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
EffectImage {
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: mainWindow.call.core.speakerMuted ? AppIcons.speakerSlash : AppIcons.speaker
|
||||
colorizationColor: mainWindow.call.core.speakerMuted ? DefaultStyle.danger_500main : undefined
|
||||
}
|
||||
Text {
|
||||
text: mainWindow.call.core.speakerMuted ? qsTr("Activer le son") : qsTr("Désactiver le son")
|
||||
color: mainWindow.call.core.speakerMuted ? DefaultStyle.danger_500main : DefaultStyle.main2_600
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -843,6 +839,32 @@ Window {
|
|||
mainWindow.call.core.lSetSpeakerMuted(!mainWindow.call.core.speakerMuted)
|
||||
}
|
||||
}
|
||||
Control.Button {
|
||||
id: recordButton
|
||||
Layout.fillWidth: true
|
||||
enabled: mainWindow.call.core.recordable
|
||||
checkable: true
|
||||
background: Item {
|
||||
visible: false
|
||||
}
|
||||
contentItem: RowLayout {
|
||||
EffectImage {
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: AppIcons.recordFill
|
||||
colorizationColor: mainWindow.call.core.recording ? DefaultStyle.danger_500main : undefined
|
||||
}
|
||||
Text {
|
||||
color: mainWindow.call.core.recording ? DefaultStyle.danger_500main : DefaultStyle.main2_600
|
||||
text: mainWindow.call.core.recording ? qsTr("Terminer l'enregistrement") : qsTr("Enregistrer l'appel")
|
||||
}
|
||||
|
||||
}
|
||||
onClicked: {
|
||||
mainWindow.call.core.recording ? mainWindow.call.core.lStopRecording() : mainWindow.call.core.lStartRecording()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ Item {
|
|||
contentItem: RowLayout {
|
||||
spacing: 15 * DefaultStyle.dp
|
||||
EffectImage {
|
||||
image.source: AppIcons.smiley
|
||||
source: AppIcons.smiley
|
||||
colorizationColor: DefaultStyle.success_500main
|
||||
Layout.preferredWidth: 32 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 32 * DefaultStyle.dp
|
||||
|
|
@ -136,7 +136,7 @@ Item {
|
|||
background: Item {
|
||||
}
|
||||
contentItem: Image {
|
||||
source: AppIcons.verticalDots
|
||||
source: AppIcons.more
|
||||
}
|
||||
Popup{
|
||||
id: accountList
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
view/Item/ComboBox.qml
|
||||
view/Item/ContactsList.qml
|
||||
view/Item/DesktopPopup.qml
|
||||
view/Item/Dialog.qml
|
||||
view/Item/DigitInput.qml
|
||||
view/Item/EffectImage.qml
|
||||
view/Item/ErrorText.qml
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@ Item {
|
|||
spacing: 5 * DefaultStyle.dp
|
||||
EffectImage {
|
||||
id: newAccount
|
||||
image.source: AppIcons.plusCircle
|
||||
source: AppIcons.plusCircle
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: height
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
fillMode: Image.PreserveAspectFit
|
||||
colorizationColor: DefaultStyle.main2_500main
|
||||
}
|
||||
Text{
|
||||
|
|
|
|||
|
|
@ -231,31 +231,10 @@ Item {
|
|||
weight: 800 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Repeater {
|
||||
model: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "\\d"]
|
||||
RowLayout {
|
||||
visible: contactList.count > 0
|
||||
spacing: 8 * DefaultStyle.dp
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
Layout.preferredWidth: 20 * DefaultStyle.dp
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.topMargin: 15 * DefaultStyle.dp // Align center with the first row
|
||||
text: modelData == "\\d" ? " " : modelData
|
||||
color: DefaultStyle.main2_400
|
||||
font {
|
||||
pixelSize: 20 * DefaultStyle.dp
|
||||
weight: 500 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
ContactsList{
|
||||
Layout.fillWidth: true
|
||||
id: contactList
|
||||
initialProxyModel: modelData
|
||||
searchBarText: searchBar.text
|
||||
// contactMenuVisible: false
|
||||
}
|
||||
}
|
||||
ContactsList{
|
||||
Layout.fillWidth: true
|
||||
id: contactList
|
||||
searchBarText: searchBar.text
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
|
|
@ -269,16 +248,11 @@ Item {
|
|||
ContactsList{
|
||||
contactMenuVisible: false
|
||||
Layout.fillHeight: true
|
||||
|
||||
model: FriendInitialProxy {
|
||||
filterText: ""
|
||||
property int sourceFlags: LinphoneEnums.MagicSearchSource.FavoriteFriends//mainItem.magicSearchSourceFlags
|
||||
sourceModel: MagicSearchProxy {
|
||||
id: search
|
||||
searchText: searchBar.text.length === 0 ? "*" : searchBar.text
|
||||
aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend
|
||||
sourceFlags: LinphoneEnums.MagicSearchSource.FavoriteFriends
|
||||
}
|
||||
initialHeadersVisible: false
|
||||
model: MagicSearchProxy {
|
||||
searchText: searchBar.text.length === 0 ? "*" : searchBar.text
|
||||
sourceFlags: LinphoneEnums.MagicSearchSource.FavoriteFriends
|
||||
aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -299,7 +273,7 @@ Item {
|
|||
id: numPad
|
||||
width: parent.width
|
||||
onLaunchCall: {
|
||||
var callVarObject = UtilsCpp.createCall(searchBar.text + "@sip.linphone.org")
|
||||
UtilsCpp.createCall(searchBar.text + "@sip.linphone.org")
|
||||
// TODO : auto completion instead of sip linphone
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ Control.CheckBox {
|
|||
// color: mainItem.checked ? DefaultStyle.main1_500_main : "transparent"
|
||||
EffectImage {
|
||||
visible: mainItem.checked
|
||||
image.source: AppIcons.check
|
||||
source: AppIcons.check
|
||||
colorizationColor: DefaultStyle.main1_500_main
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ StackView{
|
|||
id: initials
|
||||
Rectangle {
|
||||
id: initialItem
|
||||
property string initials: UtilsCpp.getInitials(mainItem.displayNameObj.value)
|
||||
property string initials: displayNameObj ? UtilsCpp.getInitials(mainItem.displayNameObj.value) : ""
|
||||
radius: width / 2
|
||||
color: DefaultStyle.main2_200
|
||||
height: mainItem.height
|
||||
|
|
|
|||
|
|
@ -123,12 +123,12 @@ Rectangle{
|
|||
}
|
||||
EffectImage {
|
||||
id: manageAccount
|
||||
image.source: AppIcons.manageProfile
|
||||
source: AppIcons.manageProfile
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
image.sourceSize.width: 24 * DefaultStyle.dp
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
width: 24 * DefaultStyle.dp
|
||||
fillMode: Image.PreserveAspectFit
|
||||
colorizationColor: DefaultStyle.main2_500main
|
||||
MouseArea{ // TODO
|
||||
anchors.fill: parent
|
||||
|
|
|
|||
|
|
@ -11,118 +11,128 @@ ListView {
|
|||
height: contentHeight
|
||||
visible: count > 0
|
||||
|
||||
property string initialProxyModel
|
||||
|
||||
property bool favorite: true
|
||||
// Component.onCompleted: model.sourceModel.sourceFlags = magicSearchSourceFlags
|
||||
|
||||
property string searchBarText
|
||||
|
||||
property bool contactMenuVisible: true
|
||||
property bool initialHeadersVisible: true
|
||||
|
||||
model: FriendInitialProxy {
|
||||
filterText: initialProxyModel
|
||||
property int sourceFlags: LinphoneEnums.MagicSearchSource.FavoriteFriends//mainItem.magicSearchSourceFlags
|
||||
sourceModel: MagicSearchProxy {
|
||||
id: search
|
||||
searchText: searchBarText.length === 0 ? "*" : searchBarText
|
||||
}
|
||||
model: MagicSearchProxy {
|
||||
searchText: searchBarText.length === 0 ? "*" : searchBarText
|
||||
}
|
||||
delegate: Item {
|
||||
width: mainItem.width
|
||||
height: 56 * DefaultStyle.dp
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
z: 1
|
||||
Avatar {
|
||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||
contact: modelData
|
||||
|
||||
delegate: RowLayout {
|
||||
id: itemDelegate
|
||||
property var previousItem : mainItem.model.count > 0 && index > 0 ? mainItem.model.getAt(index-1) : null
|
||||
property var previousDisplayName: previousItem ? UtilsCpp.getDisplayName(previousItem.core.address) : null
|
||||
property string previousDisplayNameText: previousDisplayName ? previousDisplayName.value : ""
|
||||
property var displayName: UtilsCpp.getDisplayName(modelData.core.address)
|
||||
property string displayNameText: displayName ? displayName.value : ""
|
||||
Text {
|
||||
Layout.preferredWidth: 20 * DefaultStyle.dp
|
||||
opacity: (!previousItem || !previousDisplayNameText.startsWith(displayNameText[0])) ? 1 : 0
|
||||
text: displayNameText[0]
|
||||
color: DefaultStyle.main2_400
|
||||
font {
|
||||
pixelSize: 20 * DefaultStyle.dp
|
||||
weight: 500 * DefaultStyle.dp
|
||||
capitalization: Font.AllUppercase
|
||||
}
|
||||
Text {
|
||||
text: UtilsCpp.getDisplayName(modelData.core.address).value
|
||||
font.pixelSize: 14 * DefaultStyle.dp
|
||||
font.capitalization: Font.Capitalize
|
||||
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
PopupButton {
|
||||
id: friendPopup
|
||||
hoverEnabled: true
|
||||
visible: mainItem.contactMenuVisible && (contactArea.containsMouse || hovered || popup.opened)
|
||||
popup.x: 0
|
||||
popup.padding: 10 * DefaultStyle.dp
|
||||
popup.contentItem: ColumnLayout {
|
||||
Button {
|
||||
background: Item{}
|
||||
contentItem: RowLayout {
|
||||
Image {
|
||||
source: modelData.core.starred ? AppIcons.heartFill : AppIcons.heart
|
||||
fillMode: Image.PreserveAspectFit
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
}
|
||||
Text {
|
||||
text: modelData.core.starred ? qsTr("Enlever des favoris") : qsTr("Mettre en favori")
|
||||
color: DefaultStyle.main2_500main
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
Item {
|
||||
width: mainItem.width
|
||||
height: 56 * DefaultStyle.dp
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
z: 1
|
||||
Avatar {
|
||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||
contact: modelData
|
||||
}
|
||||
Text {
|
||||
text: itemDelegate.displayNameText
|
||||
font.pixelSize: 14 * DefaultStyle.dp
|
||||
font.capitalization: Font.Capitalize
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
PopupButton {
|
||||
id: friendPopup
|
||||
hoverEnabled: true
|
||||
visible: mainItem.contactMenuVisible && (contactArea.containsMouse || hovered || popup.opened)
|
||||
popup.x: 0
|
||||
popup.padding: 10 * DefaultStyle.dp
|
||||
popup.contentItem: ColumnLayout {
|
||||
Button {
|
||||
background: Item{}
|
||||
contentItem: RowLayout {
|
||||
Image {
|
||||
source: modelData.core.starred ? AppIcons.heartFill : AppIcons.heart
|
||||
fillMode: Image.PreserveAspectFit
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
}
|
||||
Text {
|
||||
text: modelData.core.starred ? qsTr("Enlever des favoris") : qsTr("Mettre en favori")
|
||||
color: DefaultStyle.main2_500main
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
modelData.core.lSetStarred(!modelData.core.starred)
|
||||
friendPopup.close()
|
||||
}
|
||||
}
|
||||
Button {
|
||||
background: Item{}
|
||||
contentItem: RowLayout {
|
||||
EffectImage {
|
||||
image.source: AppIcons.trashCan
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
colorizationColor: DefaultStyle.danger_500main
|
||||
onClicked: {
|
||||
modelData.core.lSetStarred(!modelData.core.starred)
|
||||
friendPopup.close()
|
||||
}
|
||||
Text {
|
||||
text: qsTr("Supprimmer")
|
||||
color: DefaultStyle.danger_500main
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
Button {
|
||||
background: Item{}
|
||||
contentItem: RowLayout {
|
||||
EffectImage {
|
||||
source: AppIcons.trashCan
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
fillMode: Image.PreserveAspectFit
|
||||
colorizationColor: DefaultStyle.danger_500main
|
||||
}
|
||||
Text {
|
||||
text: qsTr("Supprimmer")
|
||||
color: DefaultStyle.danger_500main
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
modelData.core.remove()
|
||||
friendPopup.close()
|
||||
onClicked: {
|
||||
modelData.core.remove()
|
||||
friendPopup.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: contactArea
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
anchors.fill: contactArea
|
||||
opacity: 0.1
|
||||
color: DefaultStyle.main2_500main
|
||||
visible: contactArea.containsMouse || friendPopup.hovered
|
||||
}
|
||||
onClicked: {
|
||||
startCallPopup.contact = modelData
|
||||
startCallPopup.open()
|
||||
// mainItem.callButtonPressed(modelData.core.address)
|
||||
MouseArea {
|
||||
id: contactArea
|
||||
hoverEnabled: true
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
anchors.fill: contactArea
|
||||
opacity: 0.1
|
||||
color: DefaultStyle.main2_500main
|
||||
visible: contactArea.containsMouse || friendPopup.hovered
|
||||
}
|
||||
onClicked: {
|
||||
startCallPopup.contact = modelData
|
||||
startCallPopup.open()
|
||||
// mainItem.callButtonPressed(modelData.core.address)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
81
Linphone/view/Item/Dialog.qml
Normal file
81
Linphone/view/Item/Dialog.qml
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2 as Control
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
import Linphone
|
||||
|
||||
Popup {
|
||||
id: mainItem
|
||||
modal: true
|
||||
anchors.centerIn: parent
|
||||
closePolicy: Control.Popup.NoAutoClose
|
||||
rightPadding: 10 * DefaultStyle.dp
|
||||
leftPadding: 10 * DefaultStyle.dp
|
||||
topPadding: 10 * DefaultStyle.dp
|
||||
bottomPadding: 10 * DefaultStyle.dp + buttonsLayout.height
|
||||
property int radius: 16 * DefaultStyle.dp
|
||||
property color underlineColor: DefaultStyle.main1_500_main
|
||||
property string text
|
||||
signal accepted()
|
||||
signal rejected()
|
||||
|
||||
background: Item {
|
||||
anchors.fill: parent
|
||||
Rectangle {
|
||||
visible: mainItem.underlineColor != undefined
|
||||
width: mainItem.width
|
||||
height: mainItem.height + 2 * DefaultStyle.dp
|
||||
color: mainItem.underlineColor
|
||||
radius: mainItem.radius
|
||||
}
|
||||
Rectangle{
|
||||
id: backgroundItem
|
||||
width: mainItem.width
|
||||
height: mainItem.height
|
||||
radius: mainItem.radius
|
||||
color: DefaultStyle.grey_0
|
||||
border.color: DefaultStyle.grey_0
|
||||
}
|
||||
MultiEffect {
|
||||
anchors.fill: backgroundItem
|
||||
source: backgroundItem
|
||||
shadowEnabled: true
|
||||
shadowColor: DefaultStyle.grey_900
|
||||
shadowBlur: 1.0
|
||||
shadowOpacity: 0.1
|
||||
}
|
||||
RowLayout {
|
||||
id: buttonsLayout
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.bottomMargin: 10 * DefaultStyle.dp
|
||||
Button {
|
||||
text: qsTr("Oui")
|
||||
onClicked: {
|
||||
mainItem.accepted()
|
||||
mainItem.close()
|
||||
}
|
||||
}
|
||||
Button {
|
||||
text: qsTr("Non")
|
||||
onClicked: {
|
||||
mainItem.rejected()
|
||||
mainItem.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contentItem: Text {
|
||||
width: parent.width
|
||||
Layout.preferredWidth: 278 * DefaultStyle.dp
|
||||
text: mainItem.text
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
wrapMode: Text.Wrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
|
@ -5,41 +5,46 @@ import QtQuick.Effects
|
|||
|
||||
import Linphone
|
||||
|
||||
Item {
|
||||
// The loader is needed here to refresh the colorization effect (effect2) which is not refreshed when visibility change
|
||||
// and causes colorization issue when effect image is inside a popup
|
||||
Loader {
|
||||
id: mainItem
|
||||
property alias image: image
|
||||
property alias effect: effect
|
||||
property alias effect2: effect2
|
||||
active: visible
|
||||
property var source
|
||||
property var fillMode: Image.PreserveAspectFit
|
||||
property var colorizationColor
|
||||
readonly property bool useColor: colorizationColor != undefined
|
||||
width: image.width
|
||||
height: image.height
|
||||
property int imageWidth: width
|
||||
property int imageHeight: height
|
||||
property bool useColor: colorizationColor != undefined
|
||||
sourceComponent: Item {
|
||||
Image {
|
||||
id: image
|
||||
visible: !effect2.enabled
|
||||
source: mainItem.source
|
||||
fillMode: mainItem.fillMode
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
width: mainItem.imageWidth
|
||||
height: mainItem.imageHeight
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
MultiEffect {
|
||||
id: effect
|
||||
visible: false
|
||||
anchors.fill: image
|
||||
source: image
|
||||
maskSource: image
|
||||
brightness: effect2.enabled ? 1.0 : 0.0
|
||||
}
|
||||
|
||||
Image {
|
||||
id: image
|
||||
visible: !effect2.enabled
|
||||
sourceSize.width: parent.width
|
||||
sourceSize.height: parent.height
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
fillMode: Image.PreserveAspectFit
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
MultiEffect {
|
||||
id: effect
|
||||
visible: !effect2.enabled
|
||||
anchors.fill: image
|
||||
source: image
|
||||
maskSource: image
|
||||
brightness: effect2.enabled ? 1.0 : 0.0
|
||||
}
|
||||
MultiEffect {
|
||||
id: effect2
|
||||
enabled: mainItem.useColor
|
||||
anchors.fill: effect
|
||||
source: effect
|
||||
maskSource: effect
|
||||
colorizationColor: effect2.enabled ? mainItem.colorizationColor : 'black'
|
||||
colorization: effect2.enabled ? 1.0: 0.0
|
||||
MultiEffect {
|
||||
id: effect2
|
||||
enabled: mainItem.useColor
|
||||
anchors.fill: effect
|
||||
source: effect
|
||||
maskSource: effect
|
||||
colorizationColor: effect2.enabled && mainItem.colorizationColor ? mainItem.colorizationColor : 'black'
|
||||
colorization: effect2.enabled ? 1.0: 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,11 +153,11 @@ Control.Popup {
|
|||
}
|
||||
contentItem: EffectImage {
|
||||
id: buttonIcon
|
||||
image.source: AppIcons.phone
|
||||
source: AppIcons.phone
|
||||
anchors.centerIn: parent
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
fillMode: Image.PreserveAspectFit
|
||||
colorizationColor: DefaultStyle.grey_0
|
||||
}
|
||||
onClicked: mainItem.launchCall()
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ Control.Popup{
|
|||
width: mainItem.width
|
||||
height: mainItem.height
|
||||
radius: mainItem.radius
|
||||
color: DefaultStyle.grey_0
|
||||
border.color: DefaultStyle.grey_0
|
||||
// border.width: 1
|
||||
}
|
||||
MultiEffect {
|
||||
anchors.fill: backgroundItem
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ Button {
|
|||
radius: 40 * DefaultStyle.dp
|
||||
}
|
||||
contentItem: Image {
|
||||
source: AppIcons.verticalDots
|
||||
source: AppIcons.more
|
||||
sourceSize.width: 24 * DefaultStyle.dp
|
||||
sourceSize.height: 24 * DefaultStyle.dp
|
||||
width: 24 * DefaultStyle.dp
|
||||
|
|
@ -37,7 +37,7 @@ Button {
|
|||
id: popup
|
||||
x: - width
|
||||
y: mainItem.height
|
||||
closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnEscape
|
||||
closePolicy: Popup.CloseOnPressOutsideParent |Popup.CloseOnPressOutside
|
||||
|
||||
padding: 20 * DefaultStyle.dp
|
||||
|
||||
|
|
|
|||
|
|
@ -60,16 +60,18 @@ Control.TabBar {
|
|||
width: mainItem.width
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
height: tabButton.height
|
||||
width: tabButton.width
|
||||
// height: tabButton.height
|
||||
// width: tabButton.width
|
||||
EffectImage {
|
||||
id: buttonIcon
|
||||
property int buttonSize: 24 * DefaultStyle.dp
|
||||
image.source: mainItem.currentIndex === index ? modelData.selectedIcon : modelData.icon
|
||||
source: mainItem.currentIndex === index ? modelData.selectedIcon : modelData.icon
|
||||
Layout.preferredWidth: buttonSize
|
||||
Layout.preferredHeight: buttonSize
|
||||
width: buttonSize
|
||||
height: buttonSize
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
fillMode: Image.PreserveAspectFit
|
||||
colorizationColor: DefaultStyle.grey_0
|
||||
}
|
||||
Text {
|
||||
|
|
|
|||
|
|
@ -77,10 +77,10 @@ Item {
|
|||
Layout.alignment: Qt.AlignVCenter
|
||||
EffectImage {
|
||||
colorizationColor: DefaultStyle.grey_0
|
||||
image.source: mainItem.newItemIconSource
|
||||
image.width: 24 * DefaultStyle.dp
|
||||
image.height: 24 * DefaultStyle.dp
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
source: mainItem.newItemIconSource
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
Text {
|
||||
text: mainItem.noItemButtonText
|
||||
|
|
|
|||
|
|
@ -23,6 +23,18 @@ AbstractMainPage {
|
|||
listStackView.push(newCallItem)
|
||||
}
|
||||
|
||||
|
||||
Dialog {
|
||||
id: deleteHistoryPopup
|
||||
width: 278 * DefaultStyle.dp
|
||||
text: qsTr("L'historique d'appel sera supprimé. Souhaitez-vous continuer ?")
|
||||
}
|
||||
Dialog {
|
||||
id: deleteForUserPopup
|
||||
width: 278 * DefaultStyle.dp
|
||||
text: qsTr("L'historique d'appel de l'utilisateur sera supprimé. Souhaitez-vous continuer ?")
|
||||
}
|
||||
|
||||
leftPanelContent: Item {
|
||||
id: leftPanel
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -61,12 +73,12 @@ AbstractMainPage {
|
|||
background: Item{}
|
||||
contentItem: RowLayout {
|
||||
EffectImage {
|
||||
image.source: AppIcons.trashCan
|
||||
source: AppIcons.trashCan
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
fillMode: Image.PreserveAspectFit
|
||||
colorizationColor: DefaultStyle.danger_500main
|
||||
}
|
||||
Text {
|
||||
|
|
@ -78,9 +90,13 @@ AbstractMainPage {
|
|||
}
|
||||
}
|
||||
}
|
||||
Connections {
|
||||
target: deleteHistoryPopup
|
||||
onAccepted: historyListView.model.removeAllEntries()
|
||||
}
|
||||
onClicked: {
|
||||
historyListView.model.removeAllEntries()
|
||||
removeHistory.close()
|
||||
deleteHistoryPopup.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -182,50 +198,58 @@ AbstractMainPage {
|
|||
height: 45 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Text {
|
||||
property var remoteAddress: modelData ? UtilsCpp.getDisplayName(modelData.core.remoteAddress) : undefined
|
||||
text: remoteAddress ? remoteAddress.value : ""
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Image {
|
||||
source: modelData.core.status === LinphoneEnums.CallStatus.Declined
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
|
||||
? modelData.core.isOutgoing
|
||||
? AppIcons.outgoingCallRejected
|
||||
: AppIcons.incomingCallRejected
|
||||
: modelData.core.status === LinphoneEnums.CallStatus.Missed
|
||||
? modelData.core.isOutgoing
|
||||
? AppIcons.outgoingCallMissed
|
||||
: AppIcons.incomingCallMissed
|
||||
: modelData.core.isOutgoing
|
||||
? AppIcons.outgoingCall
|
||||
: AppIcons.incomingCall
|
||||
Layout.preferredWidth: 5 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 5 * DefaultStyle.dp
|
||||
sourceSize.width: 5 * DefaultStyle.dp
|
||||
sourceSize.height: 5 * DefaultStyle.dp
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
ColumnLayout {
|
||||
spacing: 5 * DefaultStyle.dp
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Text {
|
||||
// text: modelData.core.date
|
||||
text: UtilsCpp.formatDateElapsedTime(modelData.core.date)
|
||||
id: friendAddress
|
||||
property var remoteAddress: modelData ? UtilsCpp.getDisplayName(modelData.core.remoteAddress) : undefined
|
||||
text: remoteAddress ? remoteAddress.value : ""
|
||||
font {
|
||||
pixelSize: 12 * DefaultStyle.dp
|
||||
weight: 300 * DefaultStyle.dp
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
spacing: 3 * DefaultStyle.dp
|
||||
Image {
|
||||
source: modelData.core.status === LinphoneEnums.CallStatus.Declined
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.DeclinedElsewhere
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.Aborted
|
||||
|| modelData.core.status === LinphoneEnums.CallStatus.EarlyAborted
|
||||
? modelData.core.isOutgoing
|
||||
? AppIcons.outgoingCallRejected
|
||||
: AppIcons.incomingCallRejected
|
||||
: modelData.core.status === LinphoneEnums.CallStatus.Missed
|
||||
? modelData.core.isOutgoing
|
||||
? AppIcons.outgoingCallMissed
|
||||
: AppIcons.incomingCallMissed
|
||||
: modelData.core.isOutgoing
|
||||
? AppIcons.outgoingCall
|
||||
: AppIcons.incomingCall
|
||||
Layout.preferredWidth: 5 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 5 * DefaultStyle.dp
|
||||
sourceSize.width: 5 * DefaultStyle.dp
|
||||
sourceSize.height: 5 * DefaultStyle.dp
|
||||
RectangleTest{anchors.fill: parent}
|
||||
}
|
||||
Text {
|
||||
// text: modelData.core.date
|
||||
text: UtilsCpp.formatDateElapsedTime(modelData.core.date)
|
||||
font {
|
||||
pixelSize: 12 * DefaultStyle.dp
|
||||
weight: 300 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
// Item {
|
||||
// Layout.fillWidth: true
|
||||
// }
|
||||
Control.Button {
|
||||
implicitWidth: 24 * DefaultStyle.dp
|
||||
implicitHeight: 24 * DefaultStyle.dp
|
||||
|
|
@ -244,7 +268,7 @@ AbstractMainPage {
|
|||
var addr = modelData.core.remoteAddress
|
||||
var addressEnd = "@sip.linphone.org"
|
||||
if (!addr.endsWith(addressEnd)) addr += addressEnd
|
||||
var callVarObject = UtilsCpp.createCall(addr)
|
||||
UtilsCpp.createCall(addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -342,7 +366,7 @@ AbstractMainPage {
|
|||
onCallButtonPressed: (address) => {
|
||||
var addressEnd = "@sip.linphone.org"
|
||||
if (!address.endsWith(addressEnd)) address += addressEnd
|
||||
var callVarObject = UtilsCpp.createCall(address)
|
||||
UtilsCpp.createCall(address)
|
||||
// var window = UtilsCpp.getCallsWindow()
|
||||
}
|
||||
}
|
||||
|
|
@ -427,10 +451,13 @@ AbstractMainPage {
|
|||
iconSource: AppIcons.trashCan
|
||||
colorizationColor: DefaultStyle.danger_500main
|
||||
}
|
||||
Connections {
|
||||
target: deleteForUserPopup
|
||||
onAccepted: detailListView.model.removeEntriesWithFilter()
|
||||
}
|
||||
onClicked: {
|
||||
detailListView.model.removeEntriesWithFilter()
|
||||
// detailListView.currentIndex = -1 // reset index for ui
|
||||
detailOptions.close()
|
||||
deleteForUserPopup.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -659,12 +686,12 @@ AbstractMainPage {
|
|||
property string iconSource
|
||||
property color colorizationColor: DefaultStyle.main2_500main
|
||||
EffectImage {
|
||||
image.source: iconLabel.iconSource
|
||||
source: iconLabel.iconSource
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
image.fillMode: Image.PreserveAspectFit
|
||||
fillMode: Image.PreserveAspectFit
|
||||
colorizationColor: iconLabel.colorizationColor
|
||||
}
|
||||
Text {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ QtObject {
|
|||
property string usersThreeSelected: "image://internal/users-three-selected.svg"
|
||||
property string noItemImage: "image://internal/noItemImage.svg"
|
||||
property string verticalDots: "image://internal/dots-three-vertical.svg"
|
||||
property string more: "image://internal/more.svg"
|
||||
property string plusCircle: "image://internal/plus-circle.svg"
|
||||
property string micro: "image://internal/microphone-stage.svg"
|
||||
property string groupCall: "image://internal/group-call.svg"
|
||||
|
|
@ -64,4 +65,5 @@ QtObject {
|
|||
property string empty: "image://internal/empty.svg"
|
||||
property string heart: "image://internal/heart.svg"
|
||||
property string heartFill: "image://internal/heart-fill.svg"
|
||||
property string recordFill: "image://internal/record-fill.svg"
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ QtObject {
|
|||
|
||||
|
||||
|
||||
property double dp: 0.8 //1
|
||||
property double dp: 1
|
||||
|
||||
property string emojiFont: "Noto Color Emoji"
|
||||
property string defaultFont: "Noto Sans"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue