From 6849b8d378e9049a94e20789544bb3da1e468c34 Mon Sep 17 00:00:00 2001 From: Gaelle Braud Date: Wed, 3 Jan 2024 09:54:17 +0100 Subject: [PATCH] contacts list --- Linphone/core/App.cpp | 2 + Linphone/core/CMakeLists.txt | 1 + .../core/call-history/CallHistoryCore.cpp | 2 +- Linphone/core/friend/FriendCore.cpp | 96 ++++- Linphone/core/friend/FriendCore.hpp | 7 + Linphone/core/friend/FriendGui.cpp | 3 + Linphone/core/friend/FriendGui.hpp | 1 + Linphone/core/friend/FriendInitialProxy.cpp | 76 ++++ Linphone/core/friend/FriendInitialProxy.hpp | 63 +++ Linphone/core/search/MagicSearchList.cpp | 4 +- Linphone/core/search/MagicSearchProxy.cpp | 2 +- Linphone/data/CMakeLists.txt | 3 + .../model/call-history/CallHistoryModel.cpp | 4 +- Linphone/model/friend/FriendModel.cpp | 17 + Linphone/model/friend/FriendModel.hpp | 5 + Linphone/model/tool/ToolModel.cpp | 1 + Linphone/tool/LinphoneEnums.cpp | 7 + Linphone/tool/LinphoneEnums.hpp | 18 + Linphone/view/App/CallsWindow.qml | 2 +- Linphone/view/CMakeLists.txt | 3 +- Linphone/view/Item/Call/CallContactsLists.qml | 307 ++++++++++++++ Linphone/view/Item/Call/ContactsList.qml | 165 -------- Linphone/view/Item/Contact/Avatar.qml | 4 +- Linphone/view/Item/ContactsList.qml | 129 ++++++ Linphone/view/Item/PopupButton.qml | 2 +- Linphone/view/Page/Main/AbstractMainPage.qml | 2 +- Linphone/view/Page/Main/CallPage.qml | 375 +++++++++--------- Linphone/view/Prototype/FriendPrototype.qml | 3 +- Linphone/view/Style/AppIcons.qml | 5 +- 29 files changed, 933 insertions(+), 376 deletions(-) create mode 100644 Linphone/core/friend/FriendInitialProxy.cpp create mode 100644 Linphone/core/friend/FriendInitialProxy.hpp create mode 100644 Linphone/view/Item/Call/CallContactsLists.qml delete mode 100644 Linphone/view/Item/Call/ContactsList.qml create mode 100644 Linphone/view/Item/ContactsList.qml diff --git a/Linphone/core/App.cpp b/Linphone/core/App.cpp index 9967ab0c..e63c03bc 100644 --- a/Linphone/core/App.cpp +++ b/Linphone/core/App.cpp @@ -42,6 +42,7 @@ #include "core/camera/CameraGui.hpp" #include "core/friend/FriendCore.hpp" #include "core/friend/FriendGui.hpp" +#include "core/friend/FriendInitialProxy.hpp" #include "core/logger/QtLogger.hpp" #include "core/login/LoginPage.hpp" #include "core/notifier/Notifier.hpp" @@ -163,6 +164,7 @@ void App::initCppInterfaces() { qmlRegisterType(Constants::MainQmlUri, 1, 0, "FriendGui"); qmlRegisterUncreatableType(Constants::MainQmlUri, 1, 0, "FriendCore", QLatin1String("Uncreatable")); qmlRegisterType(Constants::MainQmlUri, 1, 0, "MagicSearchProxy"); + qmlRegisterType(Constants::MainQmlUri, 1, 0, "FriendInitialProxy"); qmlRegisterType(Constants::MainQmlUri, 1, 0, "CameraGui"); LinphoneEnums::registerMetaTypes(); } diff --git a/Linphone/core/CMakeLists.txt b/Linphone/core/CMakeLists.txt index 3918041e..9f99c9f7 100644 --- a/Linphone/core/CMakeLists.txt +++ b/Linphone/core/CMakeLists.txt @@ -16,6 +16,7 @@ list(APPEND _LINPHONEAPP_SOURCES core/camera/CameraDummy.cpp core/friend/FriendCore.cpp core/friend/FriendGui.cpp + core/friend/FriendInitialProxy.cpp core/logger/QtLogger.cpp core/login/LoginPage.cpp core/notifier/Notifier.cpp diff --git a/Linphone/core/call-history/CallHistoryCore.cpp b/Linphone/core/call-history/CallHistoryCore.cpp index 987d9950..ba806ae6 100644 --- a/Linphone/core/call-history/CallHistoryCore.cpp +++ b/Linphone/core/call-history/CallHistoryCore.cpp @@ -55,7 +55,7 @@ CallHistoryCore::CallHistoryCore(const std::shared_ptr &callL } CallHistoryCore::~CallHistoryCore() { - qDebug() << "[CallHistoryCore] delete" << this; + // qDebug() << "[CallHistoryCore] delete" << this; mustBeInMainThread("~" + getClassName()); } diff --git a/Linphone/core/friend/FriendCore.cpp b/Linphone/core/friend/FriendCore.cpp index 9c0653bd..3983941c 100644 --- a/Linphone/core/friend/FriendCore.cpp +++ b/Linphone/core/friend/FriendCore.cpp @@ -20,6 +20,8 @@ #include "FriendCore.hpp" #include "core/App.hpp" +#include "model/object/VariantObject.hpp" +#include "model/tool/ToolModel.hpp" #include "tool/Utils.hpp" #include "tool/thread/SafeConnection.hpp" @@ -42,7 +44,11 @@ FriendCore::FriendCore(const std::shared_ptr &contact) : QObje mPresenceTimestamp = mFriendModel->getPresenceTimestamp(); mPictureUri = Utils::coreStringToAppString(contact->getPhoto()); auto address = contact->getAddress(); - mAddress = address ? Utils::coreStringToAppString(contact->getAddress()->asString()) : "NoAddress"; + mAddress = address ? Utils::coreStringToAppString(contact->getAddress()->asStringUriOnly()) : "NoAddress"; + auto name = contact->getName(); + mName = + name.empty() ? Utils::getDisplayName(mAddress)->getValue().toString() : Utils::coreStringToAppString(name); + mStarred = contact->getStarred(); mIsSaved = true; } else mIsSaved = false; } @@ -76,11 +82,20 @@ void FriendCore::setSelf(QSharedPointer me) { mFriendModelConnection->makeConnectToModel(&FriendModel::pictureUriChanged, [this](QString uri) { mFriendModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); }); }); + mFriendModelConnection->makeConnectToModel(&FriendModel::starredChanged, [this](bool starred) { + mFriendModelConnection->invokeToCore([this, starred]() { this->onStarredChanged(starred); }); + }); + mFriendModelConnection->makeConnectToModel( + &FriendModel::objectNameChanged, + [this](const QString &objectName) { qDebug() << "object name changed" << objectName; }); // From GUI mFriendModelConnection->makeConnectToCore(&FriendCore::lSetPictureUri, [this](QString uri) { mFriendModelConnection->invokeToModel([this, uri]() { mFriendModel->setPictureUri(uri); }); }); + mFriendModelConnection->makeConnectToCore(&FriendCore::lSetStarred, [this](bool starred) { + mFriendModelConnection->invokeToModel([this, starred]() { mFriendModel->setStarred(starred); }); + }); } else { // Create mCoreModelConnection = QSharedPointer>( @@ -107,6 +122,16 @@ void FriendCore::setName(QString data) { } } +bool FriendCore::getStarred() const { + return mStarred; +} + +void FriendCore::onStarredChanged(bool starred) { + mStarred = starred; + save(); + emit starredChanged(); +} + QString FriendCore::getAddress() const { return mAddress; } @@ -190,35 +215,66 @@ void FriendCore::remove() { } } -void FriendCore::save() { // Save Values to model - FriendCore *thisCopy = new FriendCore(*this); // Pointer to avoid multiple copies in lambdas - if (mFriendModel) { // Update +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 - auto core = CoreModel::getInstance()->getCore(); auto contact = mFriendModel->getFriend(); thisCopy->writeInto(contact); thisCopy->deleteLater(); mFriendModelConnection->invokeToCore([this]() { saved(); }); }); - } else { // Creation - mCoreModelConnection->invokeToModel([this, thisCopy]() { + } else { + mCoreModelConnection->invokeToModel([this, thisCopy, linphoneAddr]() { auto core = CoreModel::getInstance()->getCore(); - auto contact = core->createFriend(); - thisCopy->writeInto(contact); - thisCopy->deleteLater(); - bool created = (core->getDefaultFriendList()->addFriend(contact) == linphone::FriendList::Status::OK); - if (created) { - mFriendModel = Utils::makeQObject_ptr(contact); - mFriendModel->setSelf(mFriendModel); - core->getDefaultFriendList()->updateSubscriptions(); + auto contact = core->findFriend(linphoneAddr); + auto friendExists = contact != nullptr; + if (contact != nullptr) { + thisCopy->writeInto(contact); + thisCopy->deleteLater(); + if (mFriendModelConnection) mFriendModelConnection->invokeToCore([this] { saved(); }); + else mCoreModelConnection->invokeToCore([this] { saved(); }); + } else { + auto contact = core->createFriend(); + thisCopy->writeInto(contact); + thisCopy->deleteLater(); + bool created = (core->getDefaultFriendList()->addFriend(contact) == linphone::FriendList::Status::OK); + if (created) { + mFriendModel = Utils::makeQObject_ptr(contact); + mFriendModel->setSelf(mFriendModel); + core->getDefaultFriendList()->updateSubscriptions(); + } + emit CoreModel::getInstance()->friendAdded(); + mCoreModelConnection->invokeToCore([this, created]() { + if (created) setSelf(mCoreModelConnection->mCore); + setIsSaved(created); + }); } - emit CoreModel::getInstance()->friendAdded(); - mCoreModelConnection->invokeToCore([this, created]() { - if (created) setSelf(mCoreModelConnection->mCore); - setIsSaved(created); - }); }); } + + // if (mFriendModel) { // Update + // } else { // Creation + // mCoreModelConnection->invokeToModel([this, thisCopy]() { + // auto core = CoreModel::getInstance()->getCore(); + // auto contact = core->createFriend(); + // thisCopy->writeInto(contact); + // thisCopy->deleteLater(); + // bool created = (core->getDefaultFriendList()->addFriend(contact) == linphone::FriendList::Status::OK); + // if (created) { + // mFriendModel = Utils::makeQObject_ptr(contact); + // mFriendModel->setSelf(mFriendModel); + // core->getDefaultFriendList()->updateSubscriptions(); + // } + // emit CoreModel::getInstance()->friendAdded(); + // mCoreModelConnection->invokeToCore([this, created]() { + // if (created) setSelf(mCoreModelConnection->mCore); + // setIsSaved(created); + // }); + // }); + // } } void FriendCore::undo() { // Retrieve values from model diff --git a/Linphone/core/friend/FriendCore.hpp b/Linphone/core/friend/FriendCore.hpp index eb42d8f0..da111f5d 100644 --- a/Linphone/core/friend/FriendCore.hpp +++ b/Linphone/core/friend/FriendCore.hpp @@ -46,6 +46,7 @@ class FriendCore : public QObject, public AbstractObject { consolidatedPresenceChanged) Q_PROPERTY(bool isSaved READ getIsSaved NOTIFY isSavedChanged) Q_PROPERTY(QString pictureUri READ getPictureUri WRITE lSetPictureUri NOTIFY pictureUriChanged) + Q_PROPERTY(bool starred READ getStarred WRITE lSetStarred NOTIFY starredChanged) public: // Should be call from model Thread. Will be automatically in App thread after initialization @@ -60,6 +61,9 @@ public: QString getName() const; void setName(QString data); + bool getStarred() const; + void onStarredChanged(bool starred); + QString getAddress() const; void setAddress(QString address); @@ -84,6 +88,7 @@ public: signals: void contactUpdated(); void nameChanged(QString name); + void starredChanged(); void addressChanged(QString address); void consolidatedPresenceChanged(LinphoneEnums::ConsolidatedPresence level); void presenceTimestampChanged(QDateTime presenceTimestamp); @@ -95,6 +100,7 @@ signals: void removed(FriendCore *contact); void lSetPictureUri(QString pictureUri); + void lSetStarred(bool starred); protected: void writeInto(std::shared_ptr contact) const; @@ -103,6 +109,7 @@ protected: LinphoneEnums::ConsolidatedPresence mConsolidatedPresence = LinphoneEnums::ConsolidatedPresence::Offline; QDateTime mPresenceTimestamp; QString mName; + bool mStarred; QString mAddress; QString mPictureUri; bool mIsSaved; diff --git a/Linphone/core/friend/FriendGui.cpp b/Linphone/core/friend/FriendGui.cpp index 738cb921..1a81764e 100644 --- a/Linphone/core/friend/FriendGui.cpp +++ b/Linphone/core/friend/FriendGui.cpp @@ -36,6 +36,9 @@ FriendGui::~FriendGui() { mustBeInMainThread("~" + getClassName()); } +void FriendGui::createContact(const QString &address) { +} + FriendCore *FriendGui::getCore() const { return mCore.get(); } diff --git a/Linphone/core/friend/FriendGui.hpp b/Linphone/core/friend/FriendGui.hpp index d98e0d6c..6b2a182d 100644 --- a/Linphone/core/friend/FriendGui.hpp +++ b/Linphone/core/friend/FriendGui.hpp @@ -35,6 +35,7 @@ public: FriendGui(QSharedPointer core); ~FriendGui(); FriendCore *getCore() const; + Q_INVOKABLE void createContact(const QString &address); QSharedPointer mCore; DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/core/friend/FriendInitialProxy.cpp b/Linphone/core/friend/FriendInitialProxy.cpp new file mode 100644 index 00000000..fc3530e4 --- /dev/null +++ b/Linphone/core/friend/FriendInitialProxy.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "FriendInitialProxy.hpp" +#include "FriendCore.hpp" +#include "FriendGui.hpp" +#include "tool/Utils.hpp" + +DEFINE_ABSTRACT_OBJECT(FriendInitialProxy) + +FriendInitialProxy::FriendInitialProxy(QObject *parent) : SortFilterProxy(parent) { +} + +FriendInitialProxy::~FriendInitialProxy() { + setSourceModel(nullptr); +} + +QString FriendInitialProxy::getFilterText() const { + return mFilterText; +} + +void FriendInitialProxy::setFilterText(const QString &filter) { + if (mFilterText != filter) { + mFilterText = filter; + invalidate(); + emit filterTextChanged(); + } +} + +// void FriendInitialProxy::setSourceModel(QAbstractItemModel *sourceModel) { +// mSource = qSharedPointerCast(QSharedPointer(sourceModel)); +// } + +// QAbstractItemModel *FriendInitialProxy::sourceModel() const { +// return mSource.get(); +// } + +bool FriendInitialProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { + bool show = (mFilterText.isEmpty() || mFilterText == "*"); + if (!show) { + QRegularExpression search(mFilterText, QRegularExpression::CaseInsensitiveOption | + QRegularExpression::UseUnicodePropertiesOption); + auto friendData = sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).value(); + auto name = friendData->getCore()->getName(); + show = friendData->getCore()->getName().indexOf(search) == 0; + } + + return show; +} + +// bool FriendInitialProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const { +// // auto l = getItemAt(left.row()); +// // auto r = getItemAt(right.row()); +// // return l->getName() < r->getName(); +// } + +QVariant FriendInitialProxy::data(const QModelIndex &index, int role) const { + return sourceModel()->data(mapToSource(index)); +} diff --git a/Linphone/core/friend/FriendInitialProxy.hpp b/Linphone/core/friend/FriendInitialProxy.hpp new file mode 100644 index 00000000..27083950 --- /dev/null +++ b/Linphone/core/friend/FriendInitialProxy.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010-2024 Belledonne Communications SARL. + * + * This file is part of linphone-desktop + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FRIEND_INITIAL_PROXY_H_ +#define FRIEND_INITIAL_PROXY_H_ + +#include "../proxy/SortFilterProxy.hpp" +#include "core/search/MagicSearchList.hpp" +#include "core/search/MagicSearchProxy.hpp" +#include "tool/AbstractObject.hpp" + +/** + * A proxy to filter the friends list with the first letter of the names + **/ +// ============================================================================= + +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); + ~FriendInitialProxy(); + + QString getFilterText() const; + void setFilterText(const QString &filter); + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + +signals: + void filterTextChanged(); + void sourceModelChanged(); + +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 mSource; + + DECLARE_ABSTRACT_OBJECT +}; + +#endif diff --git a/Linphone/core/search/MagicSearchList.cpp b/Linphone/core/search/MagicSearchList.cpp index f304d05f..67f85c93 100644 --- a/Linphone/core/search/MagicSearchList.cpp +++ b/Linphone/core/search/MagicSearchList.cpp @@ -133,6 +133,8 @@ void MagicSearchList::setAggregationFlag(LinphoneEnums::MagicSearchAggregation f QVariant MagicSearchList::data(const QModelIndex &index, int role) const { int row = index.row(); if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant(); - if (role == Qt::DisplayRole) return QVariant::fromValue(new FriendGui(mList[row].objectCast())); + if (role == Qt::DisplayRole) { + return QVariant::fromValue(new FriendGui(mList[row].objectCast())); + } return QVariant(); } diff --git a/Linphone/core/search/MagicSearchProxy.cpp b/Linphone/core/search/MagicSearchProxy.cpp index b6c06e33..74da7525 100644 --- a/Linphone/core/search/MagicSearchProxy.cpp +++ b/Linphone/core/search/MagicSearchProxy.cpp @@ -55,4 +55,4 @@ LinphoneEnums::MagicSearchAggregation MagicSearchProxy::getAggregationFlag() con void MagicSearchProxy::setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag) { qobject_cast(sourceModel())->lSetAggregationFlag(flag); -} +} \ No newline at end of file diff --git a/Linphone/data/CMakeLists.txt b/Linphone/data/CMakeLists.txt index 7fc2d466..92f2fd93 100644 --- a/Linphone/data/CMakeLists.txt +++ b/Linphone/data/CMakeLists.txt @@ -15,6 +15,7 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc "data/image/caret-down.svg" "data/image/caret-left.svg" "data/image/caret-right.svg" + "data/image/caret-up.svg" "data/image/verif_page_image.svg" "data/image/check.svg" "data/image/dialer.svg" @@ -61,6 +62,8 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc "data/image/trash-simple.svg" "data/image/copy.svg" "data/image/empty.svg" + "data/image/heart.svg" + "data/image/heart-fill.svg" data/shaders/roundEffect.vert.qsb data/shaders/roundEffect.frag.qsb diff --git a/Linphone/model/call-history/CallHistoryModel.cpp b/Linphone/model/call-history/CallHistoryModel.cpp index 4861dde2..7c8fe079 100644 --- a/Linphone/model/call-history/CallHistoryModel.cpp +++ b/Linphone/model/call-history/CallHistoryModel.cpp @@ -33,8 +33,8 @@ CallHistoryModel::CallHistoryModel(const std::shared_ptr &cal } CallHistoryModel::~CallHistoryModel() { - qDebug() << "[CallHistoryModel] delete" << this; - mustBeInLinphoneThread("~" + getClassName()); + // qDebug() << "[CallHistoryModel] delete" << this; + // mustBeInLinphoneThread("~" + getClassName()); } void CallHistoryModel::removeCallHistory() { diff --git a/Linphone/model/friend/FriendModel.cpp b/Linphone/model/friend/FriendModel.cpp index 7ea18b8d..853fce4d 100644 --- a/Linphone/model/friend/FriendModel.cpp +++ b/Linphone/model/friend/FriendModel.cpp @@ -49,6 +49,23 @@ QDateTime FriendModel::getPresenceTimestamp() const { } else return QDateTime(); } +QString FriendModel::getAddress() const { + return Utils::coreStringToAppString(mMonitor->getAddress()->asStringUriOnly()); +} + +QString FriendModel::getName() const { + return Utils::coreStringToAppString(mMonitor->getName()); +} + +bool FriendModel::getStarred() const { + return mMonitor->getStarred(); +} + +void FriendModel::setStarred(bool starred) { + mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); + mMonitor->setStarred(starred); + emit starredChanged(starred); +} void FriendModel::onPresenceReceived(const std::shared_ptr &contact) { emit presenceReceived(LinphoneEnums::fromLinphone(contact->getConsolidatedPresence()), getPresenceTimestamp()); } diff --git a/Linphone/model/friend/FriendModel.hpp b/Linphone/model/friend/FriendModel.hpp index 3aefe48c..9e3eb907 100644 --- a/Linphone/model/friend/FriendModel.hpp +++ b/Linphone/model/friend/FriendModel.hpp @@ -39,12 +39,17 @@ public: ~FriendModel(); QDateTime getPresenceTimestamp() const; + QString getAddress() const; + QString getName() const; + bool getStarred() const; std::shared_ptr getFriend() const; void setPictureUri(QString uri); + void setStarred(bool starred); signals: void pictureUriChanged(QString uri); + void starredChanged(bool starred); private: DECLARE_ABSTRACT_OBJECT diff --git a/Linphone/model/tool/ToolModel.cpp b/Linphone/model/tool/ToolModel.cpp index ffaaae18..2f26d174 100644 --- a/Linphone/model/tool/ToolModel.cpp +++ b/Linphone/model/tool/ToolModel.cpp @@ -59,6 +59,7 @@ QString ToolModel::getDisplayName(const std::shared_ptr // auto sipAddressEntry = getSipAddressEntry(qtAddress, cleanAddress); // displayName = sipAddressEntry->displayNames.get(); } + displayName.replace('.', ' '); return displayName; } diff --git a/Linphone/tool/LinphoneEnums.cpp b/Linphone/tool/LinphoneEnums.cpp index 68609471..eeab8ada 100644 --- a/Linphone/tool/LinphoneEnums.cpp +++ b/Linphone/tool/LinphoneEnums.cpp @@ -170,6 +170,13 @@ LinphoneEnums::MagicSearchAggregation LinphoneEnums::fromLinphone(const linphone return static_cast(data); } +linphone::MagicSearch::Source LinphoneEnums::toLinphone(const LinphoneEnums::MagicSearchSource &data) { + return static_cast(data); +} +LinphoneEnums::MagicSearchSource LinphoneEnums::fromLinphone(const linphone::MagicSearch::Source &data) { + return static_cast(data); +} + linphone::LogLevel LinphoneEnums::toLinphone(const QtMsgType &data) { switch (data) { case QtDebugMsg: diff --git a/Linphone/tool/LinphoneEnums.hpp b/Linphone/tool/LinphoneEnums.hpp index 22de7a6c..4d35ec81 100644 --- a/Linphone/tool/LinphoneEnums.hpp +++ b/Linphone/tool/LinphoneEnums.hpp @@ -218,6 +218,24 @@ Q_ENUM_NS(MagicSearchAggregation); linphone::MagicSearch::Aggregation toLinphone(const LinphoneEnums::MagicSearchAggregation &data); LinphoneEnums::MagicSearchAggregation fromLinphone(const linphone::MagicSearch::Aggregation &data); +enum class MagicSearchSource { + None = int(linphone::MagicSearch::Source::None), + Friends = int(linphone::MagicSearch::Source::Friends), + CallLogs = int(linphone::MagicSearch::Source::CallLogs), + LdapServers = int(linphone::MagicSearch::Source::LdapServers), + ChatRooms = int(linphone::MagicSearch::Source::ChatRooms), + Request = int(linphone::MagicSearch::Source::Request), + FavoriteFriends = int(linphone::MagicSearch::Source::FavoriteFriends), + ConferencesInfo = int(linphone::MagicSearch::Source::ConferencesInfo), + All = int(linphone::MagicSearch::Source::All) +}; +Q_ENUM_NS(MagicSearchSource); +// Q_DECLARE_FLAGS(MagicSearchSources, MagicSearchSource) +// Q_DECLARE_OPERATORS_FOR_FLAGS(MagicSearchSources) + +linphone::MagicSearch::Source toLinphone(const LinphoneEnums::MagicSearchSource &data); +LinphoneEnums::MagicSearchSource fromLinphone(const linphone::MagicSearch::Source &data); + linphone::LogLevel toLinphone(const QtMsgType &data); QtMsgType fromLinphone(const linphone::LogLevel &data); diff --git a/Linphone/view/App/CallsWindow.qml b/Linphone/view/App/CallsWindow.qml index e83bf341..7c1be498 100644 --- a/Linphone/view/App/CallsWindow.qml +++ b/Linphone/view/App/CallsWindow.qml @@ -454,7 +454,7 @@ Window { } Component { id: contactsListPanel - ContactsList { + CallContactsLists { sideMargin: 10 * DefaultStyle.dp topMargin: 15 * DefaultStyle.dp groupCallVisible: false diff --git a/Linphone/view/CMakeLists.txt b/Linphone/view/CMakeLists.txt index ebafceb4..d01350af 100644 --- a/Linphone/view/CMakeLists.txt +++ b/Linphone/view/CMakeLists.txt @@ -7,7 +7,7 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Item/Account/Accounts.qml - view/Item/Call/ContactsList.qml + view/Item/Call/CallContactsLists.qml view/Item/Call/OngoingCallRightPanel.qml view/Item/Notification/Notification.qml @@ -25,6 +25,7 @@ list(APPEND _LINPHONEAPP_QML_FILES view/Item/Carousel.qml view/Item/CheckBox.qml view/Item/ComboBox.qml + view/Item/ContactsList.qml view/Item/DesktopPopup.qml view/Item/DigitInput.qml view/Item/EffectImage.qml diff --git a/Linphone/view/Item/Call/CallContactsLists.qml b/Linphone/view/Item/Call/CallContactsLists.qml new file mode 100644 index 00000000..aa30c470 --- /dev/null +++ b/Linphone/view/Item/Call/CallContactsLists.qml @@ -0,0 +1,307 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.2 as Control +import QtQuick.Effects + +import Linphone +import UtilsCpp 1.0 + +Item { + id: mainItem + property int sideMargin: 25 * DefaultStyle.dp + property int topMargin: 5 * DefaultStyle.dp + property bool groupCallVisible + property color searchBarColor: DefaultStyle.grey_100 + property color searchBarBorderColor: "transparent" + signal callButtonPressed(string address) + clip: true + + Popup { + id: startCallPopup + property FriendGui contact + onContactChanged: { + + } + underlineColor: DefaultStyle.main1_500_main + anchors.centerIn: parent + width: parent.width + modal: true + leftPadding: 15 * DefaultStyle.dp + rightPadding: 15 * DefaultStyle.dp + topPadding: 20 * DefaultStyle.dp + bottomPadding: 25 * DefaultStyle.dp + contentItem: ColumnLayout { + RowLayout { + Text { + text: qsTr("Select channel") + font { + pixelSize: 16 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + } + Item { + Layout.fillWidth: true + } + Button { + Layout.preferredWidth: 24 * DefaultStyle.dp + Layout.preferredHeight: 24 * DefaultStyle.dp + background: Item{} + contentItem: Image { + anchors.fill: parent + source: AppIcons.closeX + } + onClicked: startCallPopup.close() + } + } + Repeater { + id: adresses + model: [{label: "SIP", address: startCallPopup.contact ? startCallPopup.contact.core.address : ""}, + {label: "Work", address: "06000000000"}, + {label: "Personal", address: "060000000"} + ] //account.adresses + Button { + id: channel + // required property int index + leftPadding: 0 + rightPadding: 0 + // topPadding: 0 + bottomPadding: 0 + Layout.fillWidth: true + + background: Item{} + contentItem: ColumnLayout { + RowLayout { + ColumnLayout { + Text { + Layout.leftMargin: 5 * DefaultStyle.dp + Layout.rightMargin: 5 * DefaultStyle.dp + text: modelData.label + font { + pixelSize: 14 * DefaultStyle.dp + weight: 700 * DefaultStyle.dp + } + } + Text { + Layout.leftMargin: 5 * DefaultStyle.dp + Layout.rightMargin: 5 * DefaultStyle.dp + text: modelData.address + font { + pixelSize: 13 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + } + } + Item { + Layout.fillWidth: true + } + } + Rectangle { + visible: index < adresses.count - 1 + Layout.fillWidth: true + Layout.preferredHeight: 1 * DefaultStyle.dp + color: DefaultStyle.main2_200 + } + } + onClicked: mainItem.callButtonPressed(modelData.address) + } + } + } + } + + + Control.ScrollBar { + id: contactsScrollbar + active: true + interactive: true + policy: Control.ScrollBar.AlwaysOn + // Layout.fillWidth: true + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + // x: mainItem.x + mainItem.width - width + // anchors.left: control.right + } + + Control.Control { + id: listLayout + anchors.fill: parent + anchors.topMargin: mainItem.topMargin + background: Item { + anchors.fill: parent + } + contentItem: ColumnLayout { + anchors.fill: parent + spacing: 10 * DefaultStyle.dp + SearchBar { + id: searchBar + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + Layout.maximumWidth: mainItem.width + Layout.leftMargin: mainItem.sideMargin + Layout.rightMargin: mainItem.sideMargin + color: mainItem.searchBarColor + borderColor: mainItem.searchBarBorderColor + placeholderText: qsTr("Rechercher un contact") + numericPad: numPad + } + Control.ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.leftMargin: mainItem.sideMargin + Layout.topMargin: 25 * DefaultStyle.dp + rightPadding: mainItem.sideMargin + contentWidth: width - mainItem.sideMargin + contentHeight: content.height + clip: true + Control.ScrollBar.vertical: contactsScrollbar + + ColumnLayout { + id: content + width: parent.width + spacing: 25 * DefaultStyle.dp + Button { + visible: mainItem.groupCallVisible + Layout.fillWidth: true + leftPadding: 0 + topPadding: 0 + rightPadding: 0 + bottomPadding: 0 + background: Rectangle { + color: DefaultStyle.groupCallButtonColor + anchors.fill: parent + radius: 50 * DefaultStyle.dp + } + contentItem: RowLayout { + Image { + source: AppIcons.groupCall + Layout.preferredWidth: 35 * DefaultStyle.dp + sourceSize.width: 35 * DefaultStyle.dp + fillMode: Image.PreserveAspectFit + } + Text { + text: "Appel de groupe" + font { + pixelSize: 16 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + } + Item { + Layout.fillWidth: true + } + Image { + source: AppIcons.rightArrow + } + } + } + + RowLayout { + visible: searchBar.text.length > 0 + Layout.maximumWidth: parent.width + Layout.fillWidth: true + Text { + text: searchBar.text + maximumLineCount: 1 + elide: Text.ElideRight + } + Item { + Layout.fillWidth: true + } + Control.Button { + implicitWidth: 30 * DefaultStyle.dp + implicitHeight: 30 * DefaultStyle.dp + background: Item { + visible: false + } + contentItem: Image { + source: AppIcons.phone + width: 20 * DefaultStyle.dp + sourceSize.width: 20 * DefaultStyle.dp + fillMode: Image.PreserveAspectFit + } + onClicked: { + mainItem.callButtonPressed(searchBar.text) + } + } + } + ColumnLayout { + Text { + text: qsTr("All contacts") + font { + pixelSize: 16 * DefaultStyle.dp + 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 + } + } + } + } + ColumnLayout { + Text { + text: qsTr("Suggestions") + font { + pixelSize: 16 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + } + 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 + } + } + } + } + Item { + Layout.fillHeight: true + } + } + } + } + } + + Item { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + height: numPad.implicitHeight + NumericPad { + id: numPad + width: parent.width + onLaunchCall: { + var callVarObject = UtilsCpp.createCall(searchBar.text + "@sip.linphone.org") + // TODO : auto completion instead of sip linphone + } + } + } +} diff --git a/Linphone/view/Item/Call/ContactsList.qml b/Linphone/view/Item/Call/ContactsList.qml deleted file mode 100644 index 9d651ea3..00000000 --- a/Linphone/view/Item/Call/ContactsList.qml +++ /dev/null @@ -1,165 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Layouts 1.3 -import QtQuick.Controls 2.2 as Control -import QtQuick.Effects - -import Linphone - -Item { - id: mainItem - property int sideMargin: 25 * DefaultStyle.dp - property int topMargin: 5 * DefaultStyle.dp - property bool groupCallVisible - property color searchBarColor: DefaultStyle.grey_100 - property color searchBarBorderColor: "transparent" - signal callButtonPressed(string address) - clip: true - Control.Control { - id: listLayout - anchors.fill: parent - anchors.leftMargin: mainItem.sideMargin - anchors.rightMargin: mainItem.sideMargin - anchors.topMargin: mainItem.topMargin - background: Item { - anchors.fill: parent - } - contentItem: ColumnLayout { - anchors.fill: parent - spacing: 10 * DefaultStyle.dp - SearchBar { - id: searchBar - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - Layout.maximumWidth: mainItem.width - color: mainItem.searchBarColor - borderColor: mainItem.searchBarBorderColor - placeholderText: qsTr("Rechercher un contact") - numericPad: numPad - } - Button { - visible: mainItem.groupCallVisible - Layout.fillWidth: true - leftPadding: 0 - topPadding: 0 - rightPadding: 0 - bottomPadding: 0 - background: Rectangle { - color: DefaultStyle.groupCallButtonColor - anchors.fill: parent - radius: 50 * DefaultStyle.dp - } - contentItem: RowLayout { - Image { - source: AppIcons.groupCall - Layout.preferredWidth: 35 * DefaultStyle.dp - sourceSize.width: 35 * DefaultStyle.dp - fillMode: Image.PreserveAspectFit - } - Text { - text: "Appel de groupe" - font { - pixelSize: 16 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - } - Item { - Layout.fillWidth: true - } - Image { - source: AppIcons.rightArrow - } - } - } - - RowLayout { - visible: searchBar.text.length > 0 // && contactList.count === 0 (pas trouvé dans la liste) - Layout.maximumWidth: parent.width - Layout.fillWidth: true - Text { - text: searchBar.text - maximumLineCount: 1 - elide: Text.ElideRight - } - Item { - Layout.fillWidth: true - } - Control.Button { - implicitWidth: 30 * DefaultStyle.dp - implicitHeight: 30 * DefaultStyle.dp - background: Item { - visible: false - } - contentItem: Image { - source: AppIcons.phone - width: 20 * DefaultStyle.dp - sourceSize.width: 20 * DefaultStyle.dp - fillMode: Image.PreserveAspectFit - } - onClicked: { - mainItem.callButtonPressed(searchBar.text) - } - } - } - ListView { - id: contactList - Layout.fillWidth: true - Layout.fillHeight: true - // call history - model: 30 - delegate: Item { - required property int index - width:contactList.width - height: 30 * DefaultStyle.dp - RowLayout { - anchors.fill: parent - Image { - source: AppIcons.info - } - ColumnLayout { - Text { - text: "John Doe" - } - // RowLayout { - // Image { - // source: AppIcons.incomingCall - // } - // Text { - // text: "info sur l'appel" - // } - // } - } - Item { - Layout.fillWidth: true - } - } - MouseArea { - hoverEnabled: true - Rectangle { - anchors.fill: parent - opacity: 0.1 - radius: 15 * DefaultStyle.dp - color: DefaultStyle.main2_500main - visible: parent.containsMouse - } - onClicked: contactList.currentIndex = parent.index - } - } - } - } - } - - Item { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - height: numPad.implicitHeight - NumericPad { - id: numPad - width: parent.width - onLaunchCall: { - var callVarObject = UtilsCpp.createCall(searchBar.text + "@sip.linphone.org") - // TODO : auto completion instead of sip linphone - } - } - } -} diff --git a/Linphone/view/Item/Contact/Avatar.qml b/Linphone/view/Item/Contact/Avatar.qml index 97e94b63..205d7d12 100644 --- a/Linphone/view/Item/Contact/Avatar.qml +++ b/Linphone/view/Item/Contact/Avatar.qml @@ -19,7 +19,9 @@ StackView{ ? account.core.identityAddress : call ? call.core.peerAddress - : '' + : contact + ? contact.core.address + : '' property var displayNameObj: UtilsCpp.getDisplayName(address) property bool haveAvatar: (account && account.core.pictureUri ) || (contact && contact.core.pictureUri) diff --git a/Linphone/view/Item/ContactsList.qml b/Linphone/view/Item/ContactsList.qml new file mode 100644 index 00000000..60cd3347 --- /dev/null +++ b/Linphone/view/Item/ContactsList.qml @@ -0,0 +1,129 @@ +import QtQuick 2.7 +import QtQuick.Layouts 1.3 + +import Linphone +import UtilsCpp 1.0 + +ListView { + id: mainItem + Layout.fillWidth: true + Layout.preferredHeight: contentHeight + 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 + + model: FriendInitialProxy { + filterText: initialProxyModel + property int sourceFlags: LinphoneEnums.MagicSearchSource.FavoriteFriends//mainItem.magicSearchSourceFlags + sourceModel: MagicSearchProxy { + id: search + 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 + } + 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 + } + } + } + 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 + } + Text { + text: qsTr("Supprimmer") + color: DefaultStyle.danger_500main + font { + pixelSize: 14 * DefaultStyle.dp + weight: 400 * DefaultStyle.dp + } + } + } + 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) + } + } + } +} \ No newline at end of file diff --git a/Linphone/view/Item/PopupButton.qml b/Linphone/view/Item/PopupButton.qml index 81926031..7a4ef307 100644 --- a/Linphone/view/Item/PopupButton.qml +++ b/Linphone/view/Item/PopupButton.qml @@ -13,7 +13,7 @@ Button { rightPadding: 0 topPadding: 0 bottomPadding: 0 - function closePopup() { + function close() { popup.close() } background: Rectangle { diff --git a/Linphone/view/Page/Main/AbstractMainPage.qml b/Linphone/view/Page/Main/AbstractMainPage.qml index 258a3c7e..bb974945 100644 --- a/Linphone/view/Page/Main/AbstractMainPage.qml +++ b/Linphone/view/Page/Main/AbstractMainPage.qml @@ -27,10 +27,10 @@ Item { implicitWidth: 8 * DefaultStyle.dp color: Control.SplitHandle.hovered ? DefaultStyle.grey_200 : DefaultStyle.grey_100 } - ColumnLayout { id: leftPanel Control.SplitView.preferredWidth: 350 * DefaultStyle.dp + Control.SplitView.minimumWidth: 350 * DefaultStyle.dp } Rectangle { id: rightPanel diff --git a/Linphone/view/Page/Main/CallPage.qml b/Linphone/view/Page/Main/CallPage.qml index c49a7300..99d3fd29 100644 --- a/Linphone/view/Page/Main/CallPage.qml +++ b/Linphone/view/Page/Main/CallPage.qml @@ -70,7 +70,7 @@ AbstractMainPage { colorizationColor: DefaultStyle.danger_500main } Text { - text: qsTr("Supprimmer l’historique") + text: qsTr("Supprimer l’historique") color: DefaultStyle.danger_500main font { pixelSize: 14 * DefaultStyle.dp @@ -80,7 +80,7 @@ AbstractMainPage { } onClicked: { historyListView.model.removeAllEntries() - removeHistory.closePopup() + removeHistory.close() } } } @@ -101,194 +101,197 @@ AbstractMainPage { } } } - RowLayout { - Control.Control { - id: listLayout + ColumnLayout { + SearchBar { + id: searchBar Layout.fillWidth: true - Layout.fillHeight: true Layout.leftMargin: listStackView.sideMargin Layout.rightMargin: listStackView.sideMargin + placeholderText: qsTr("Rechercher un appel") + } + RowLayout { + Layout.topMargin: 30 * DefaultStyle.dp + Control.Control { + id: listLayout + Layout.fillWidth: true + Layout.fillHeight: true + Layout.leftMargin: listStackView.sideMargin + Layout.rightMargin: listStackView.sideMargin - background: Rectangle { - anchors.fill: parent - } - ColumnLayout { - anchors.fill: parent - SearchBar { - id: searchBar - Layout.alignment: Qt.AlignTop - Layout.fillWidth: true - placeholderText: qsTr("Rechercher un appel") + background: Rectangle { + anchors.fill: parent } ColumnLayout { - Text { - text: qsTr("Aucun appel") - font { - pixelSize: 16 * DefaultStyle.dp - weight: 800 * DefaultStyle.dp - } - visible: historyListView.count === 0 - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: 30 * DefaultStyle.dp - } - ListView { - id: historyListView - clip: true - Layout.fillWidth: true - Layout.fillHeight: true - Layout.topMargin: 30 * DefaultStyle.dp - model: CallHistoryProxy{ - filterText: searchBar.text - } - currentIndex: -1 - onCurrentIndexChanged: { - mainItem.selectedRowHistoryGui = model.getAt(currentIndex) - } - spacing: 10 * DefaultStyle.dp - highlightMoveDuration: 10 - highlightMoveVelocity: -1 - // highlightFollowsCurrentItem: true - highlight: Rectangle { - x: historyListView.x - width: historyListView.width - height: historyListView.height - color: DefaultStyle.main2_100 - y: historyListView.currentItem? historyListView.currentItem.y : 0 + anchors.fill: parent + ColumnLayout { + Text { + text: qsTr("Aucun appel") + font { + pixelSize: 16 * DefaultStyle.dp + weight: 800 * DefaultStyle.dp + } + visible: historyListView.count === 0 + Layout.alignment: Qt.AlignHCenter } + ListView { + id: historyListView + clip: true + Layout.fillWidth: true + Layout.fillHeight: true + model: CallHistoryProxy{ + filterText: searchBar.text + } + currentIndex: -1 + + spacing: 10 * DefaultStyle.dp + highlightMoveDuration: 10 + highlightMoveVelocity: -1 + // highlightFollowsCurrentItem: true + highlight: Rectangle { + x: historyListView.x + width: historyListView.width + height: historyListView.height + color: DefaultStyle.main2_100 + y: historyListView.currentItem? historyListView.currentItem.y : 0 + } - delegate: Item { - width:historyListView.width - height: 56 * DefaultStyle.dp - anchors.topMargin: 5 * DefaultStyle.dp - anchors.bottomMargin: 5 * DefaultStyle.dp - RowLayout { - z: 1 - anchors.fill: parent - Item { - Layout.preferredWidth: historyAvatar.width - Layout.preferredHeight: historyAvatar.height - Layout.leftMargin: 5 * DefaultStyle.dp - MultiEffect { - source: historyAvatar - anchors.fill: historyAvatar - shadowEnabled: true - shadowBlur: 1 - shadowColor: DefaultStyle.grey_900 - shadowOpacity: 0.1 - } - Avatar { - id: historyAvatar - address: modelData.core.remoteAddress - width: 45 * DefaultStyle.dp - 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 + delegate: Item { + width:historyListView.width + height: 56 * DefaultStyle.dp + anchors.topMargin: 5 * DefaultStyle.dp + anchors.bottomMargin: 5 * DefaultStyle.dp + RowLayout { + z: 1 + anchors.fill: parent + Item { + Layout.preferredWidth: historyAvatar.width + Layout.preferredHeight: historyAvatar.height + Layout.leftMargin: 5 * DefaultStyle.dp + MultiEffect { + source: historyAvatar + anchors.fill: historyAvatar + shadowEnabled: true + shadowBlur: 1 + shadowColor: DefaultStyle.grey_900 + shadowOpacity: 0.1 + } + Avatar { + id: historyAvatar + address: modelData.core.remoteAddress + width: 45 * DefaultStyle.dp + height: 45 * 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 - } + ColumnLayout { + Layout.alignment: Qt.AlignVCenter Text { - // text: modelData.core.date - text: UtilsCpp.formatDateElapsedTime(modelData.core.date) + 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 { + 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 + } + Text { + // text: modelData.core.date + text: UtilsCpp.formatDateElapsedTime(modelData.core.date) + font { + pixelSize: 12 * DefaultStyle.dp + weight: 300 * DefaultStyle.dp + } } } } - } - Item { - Layout.fillWidth: true - } - Control.Button { - implicitWidth: 24 * DefaultStyle.dp - implicitHeight: 24 * DefaultStyle.dp - Layout.rightMargin: 5 * DefaultStyle.dp - padding: 0 - background: Item { - visible: false + Item { + Layout.fillWidth: true } - contentItem: Image { - source: AppIcons.phone - width: 24 * DefaultStyle.dp - sourceSize.width: 24 * DefaultStyle.dp - fillMode: Image.PreserveAspectFit - } - onClicked: { - var addr = modelData.core.remoteAddress - var addressEnd = "@sip.linphone.org" - if (!addr.endsWith(addressEnd)) addr += addressEnd - var callVarObject = UtilsCpp.createCall(addr) + Control.Button { + implicitWidth: 24 * DefaultStyle.dp + implicitHeight: 24 * DefaultStyle.dp + Layout.rightMargin: 5 * DefaultStyle.dp + padding: 0 + background: Item { + visible: false + } + contentItem: Image { + source: AppIcons.phone + width: 24 * DefaultStyle.dp + sourceSize.width: 24 * DefaultStyle.dp + fillMode: Image.PreserveAspectFit + } + onClicked: { + var addr = modelData.core.remoteAddress + var addressEnd = "@sip.linphone.org" + if (!addr.endsWith(addressEnd)) addr += addressEnd + var callVarObject = UtilsCpp.createCall(addr) + } } } - } - MouseArea { - hoverEnabled: true - anchors.fill: parent - Rectangle { + MouseArea { + hoverEnabled: true anchors.fill: parent - opacity: 0.1 - color: DefaultStyle.main2_500main - visible: parent.containsMouse - } - onPressed: { - historyListView.currentIndex = model.index + Rectangle { + anchors.fill: parent + opacity: 0.1 + color: DefaultStyle.main2_500main + visible: parent.containsMouse + } + onPressed: { + historyListView.currentIndex = model.index + } } } - } - - onCountChanged: { - mainItem.showDefaultItem = historyListView.count === 0 && historyListView.visible - } - - onVisibleChanged: { - mainItem.showDefaultItem = historyListView.count === 0 && historyListView.visible - if (!visible) currentIndex = -1 - } - - Connections { - target: mainItem - onShowDefaultItemChanged: mainItem.showDefaultItem = mainItem.showDefaultItem && historyListView.count === 0 && historyListView.visible - onListViewUpdated: { - historyListView.model.updateView() + onCurrentIndexChanged: { + mainItem.selectedRowHistoryGui = model.getAt(currentIndex) } + onCountChanged: { + mainItem.showDefaultItem = historyListView.count === 0 && historyListView.visible + } + + onVisibleChanged: { + mainItem.showDefaultItem = historyListView.count === 0 && historyListView.visible + if (!visible) currentIndex = -1 + } + + Connections { + target: mainItem + onShowDefaultItemChanged: mainItem.showDefaultItem = mainItem.showDefaultItem && historyListView.count === 0 && historyListView.visible + onListViewUpdated: { + historyListView.model.updateView() + } + } + Control.ScrollBar.vertical: scrollbar } - Control.ScrollBar.vertical: scrollbar } } } - } - Control.ScrollBar { - id: scrollbar - active: true - Layout.fillHeight: true + Control.ScrollBar { + id: scrollbar + active: true + policy: Control.ScrollBar.AlwaysOn + Layout.fillHeight: true + } } } } @@ -324,18 +327,24 @@ AbstractMainPage { Layout.fillWidth: true } } - ContactsList { + RowLayout { Layout.fillWidth: true Layout.fillHeight: true - Layout.maximumWidth: parent.width - groupCallVisible: true - searchBarColor: DefaultStyle.grey_100 - - onCallButtonPressed: (address) => { - var addressEnd = "@sip.linphone.org" - if (!address.endsWith(addressEnd)) address += addressEnd - var callVarObject = UtilsCpp.createCall(address) - // var window = UtilsCpp.getCallsWindow() + // Layout.maximumWidth: parent.width + CallContactsLists { + Layout.fillWidth: true + Layout.fillHeight: true + // Layout.leftMargin: listStackView.sideMargin + // Layout.rightMargin: listStackView.sideMargin + groupCallVisible: true + searchBarColor: DefaultStyle.grey_100 + + onCallButtonPressed: (address) => { + var addressEnd = "@sip.linphone.org" + if (!address.endsWith(addressEnd)) address += addressEnd + var callVarObject = UtilsCpp.createCall(address) + // var window = UtilsCpp.getCallsWindow() + } } } } @@ -366,7 +375,7 @@ AbstractMainPage { anchors.centerIn: parent width: 100 * DefaultStyle.dp height: 100 * DefaultStyle.dp - address: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.remoteAddress : "" + address: mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.remoteAddress || "" } PopupButton { id: detailOptions @@ -381,7 +390,14 @@ AbstractMainPage { text: qsTr("Ajouter aux contacts") iconSource: AppIcons.plusCircle } - onClicked: console.debug("[CallPage.qml] TODO : add to contact") + onClicked: { + // console.debug("[CallPage.qml] TODO : add to contact") + var friendGui = Qt.createQmlObject('import Linphone + FriendGui{}', detailAvatar) + friendGui.core.name = contactName.text + friendGui.core.address = contactAddress.text + friendGui.core.save() + } } Button { background: Item {} @@ -413,8 +429,8 @@ AbstractMainPage { } onClicked: { detailListView.model.removeEntriesWithFilter() - detailListView.currentIndex = -1 // reset index for ui - detailOptions.closePopup() + // detailListView.currentIndex = -1 // reset index for ui + detailOptions.close() } } } @@ -424,6 +440,7 @@ AbstractMainPage { Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true Text { + id: contactName property var remoteAddress: mainItem.selectedRowHistoryGui ? UtilsCpp.getDisplayName(mainItem.selectedRowHistoryGui.core.remoteAddress) : undefined Layout.alignment: Qt.AlignHCenter text: remoteAddress ? remoteAddress.value : "" @@ -434,6 +451,7 @@ AbstractMainPage { } } Text { + id: contactAddress text: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.remoteAddress : "" horizontalAlignment: Text.AlignHCenter font { @@ -554,7 +572,6 @@ AbstractMainPage { sourceSize.height: 6.67 * DefaultStyle.dp } Text { - Component.onCompleted: console.log("status", modelData.core.status) text: modelData.core.status === LinphoneEnums.CallStatus.Missed ? qsTr("Appel manqué") : modelData.core.isOutgoing diff --git a/Linphone/view/Prototype/FriendPrototype.qml b/Linphone/view/Prototype/FriendPrototype.qml index 9fdf6cd9..a92ab04a 100644 --- a/Linphone/view/Prototype/FriendPrototype.qml +++ b/Linphone/view/Prototype/FriendPrototype.qml @@ -32,7 +32,7 @@ Window{ contact.core.save() } } - Text{ + Text { text: 'IsSaved:'+contact.core.isSaved } } @@ -40,6 +40,7 @@ Window{ id: friends Layout.fillHeight: true Layout.fillWidth: true + onCountChanged: console.log("count changed", count) model: MagicSearchProxy{ id: search diff --git a/Linphone/view/Style/AppIcons.qml b/Linphone/view/Style/AppIcons.qml index 832f49c6..613fd649 100644 --- a/Linphone/view/Style/AppIcons.qml +++ b/Linphone/view/Style/AppIcons.qml @@ -10,6 +10,7 @@ QtObject { property string downArrow: "image://internal/caret-down.svg" property string returnArrow: "image://internal/caret-left.svg" property string rightArrow: "image://internal/caret-right.svg" + property string upArrow: "image://internal/caret-up.svg" property string info: "image://internal/info.svg" property string loginImage: "image://internal/login_image.svg" property string belledonne: "image://internal/belledonne.svg" @@ -61,4 +62,6 @@ QtObject { property string trashCan: "image://internal/trash-simple.svg" property string copy: "image://internal/copy.svg" property string empty: "image://internal/empty.svg" -} + property string heart: "image://internal/heart.svg" + property string heartFill: "image://internal/heart-fill.svg" +} \ No newline at end of file