mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 03:18:07 +00:00
contact list
fixes: generic VariantList FriendModel resetAddresses check null default account address list update on save generic item for white background lists ui fix set photo friend protect friendmodel setters remove main splitview to stick to the mock-up (keeping it commented cause it may be useful to be able to resize the panels) default image avatar fix crash when address not set
This commit is contained in:
parent
c33b35724a
commit
82b5d6a008
43 changed files with 2341 additions and 542 deletions
|
|
@ -50,6 +50,7 @@
|
|||
#include "core/phone-number/PhoneNumberProxy.hpp"
|
||||
#include "core/search/MagicSearchProxy.hpp"
|
||||
#include "core/singleapplication/singleapplication.h"
|
||||
#include "core/variant/VariantList.hpp"
|
||||
#include "model/object/VariantObject.hpp"
|
||||
#include "tool/Constants.hpp"
|
||||
#include "tool/EnumsToString.hpp"
|
||||
|
|
@ -161,6 +162,7 @@ void App::initCppInterfaces() {
|
|||
qmlRegisterUncreatableType<CallCore>(Constants::MainQmlUri, 1, 0, "CallCore", QLatin1String("Uncreatable"));
|
||||
qmlRegisterType<CallProxy>(Constants::MainQmlUri, 1, 0, "CallProxy");
|
||||
qmlRegisterType<CallHistoryProxy>(Constants::MainQmlUri, 1, 0, "CallHistoryProxy");
|
||||
qmlRegisterType<VariantList>(Constants::MainQmlUri, 1, 0, "VariantList");
|
||||
qmlRegisterType<CallGui>(Constants::MainQmlUri, 1, 0, "CallGui");
|
||||
qmlRegisterType<FriendGui>(Constants::MainQmlUri, 1, 0, "FriendGui");
|
||||
qmlRegisterUncreatableType<FriendCore>(Constants::MainQmlUri, 1, 0, "FriendCore", QLatin1String("Uncreatable"));
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
core/proxy/ListProxy.cpp
|
||||
core/proxy/Proxy.cpp
|
||||
core/proxy/SortFilterProxy.cpp
|
||||
|
||||
core/variant/VariantList.cpp
|
||||
)
|
||||
|
||||
## Single Application
|
||||
|
|
|
|||
|
|
@ -61,7 +61,10 @@ void CallHistoryList::setSelf(QSharedPointer<CallHistoryList> me) {
|
|||
// Avoid copy to lambdas
|
||||
QList<QSharedPointer<CallHistoryCore>> *callLogs = new QList<QSharedPointer<CallHistoryCore>>();
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
auto linphoneCallLogs = CoreModel::getInstance()->getCore()->getCallLogs();
|
||||
std::list<std::shared_ptr<linphone::CallLog>> linphoneCallLogs;
|
||||
if (auto account = CoreModel::getInstance()->getCore()->getDefaultAccount()) {
|
||||
linphoneCallLogs = account->getCallLogs();
|
||||
}
|
||||
for (auto it : linphoneCallLogs) {
|
||||
auto model = createCallHistoryCore(it);
|
||||
callLogs->push_back(model);
|
||||
|
|
@ -74,7 +77,8 @@ void CallHistoryList::setSelf(QSharedPointer<CallHistoryList> me) {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
mModelConnection->makeConnectToModel(&CoreModel::defaultAccountChanged,
|
||||
[this]() { mModelConnection->invokeToCore([this]() { lUpdate(); }); });
|
||||
mModelConnection->makeConnectToModel(&CoreModel::callLogUpdated,
|
||||
[this]() { mModelConnection->invokeToCore([this]() { lUpdate(); }); });
|
||||
lUpdate();
|
||||
|
|
|
|||
|
|
@ -122,7 +122,6 @@ signals:
|
|||
void stateChanged(LinphoneEnums::CallState state);
|
||||
void dirChanged(LinphoneEnums::CallDir dir);
|
||||
void lastErrorMessageChanged();
|
||||
void peerAddressChanged();
|
||||
void durationChanged(int duration);
|
||||
void speakerMutedChanged();
|
||||
void microphoneMutedChanged();
|
||||
|
|
|
|||
|
|
@ -20,13 +20,23 @@
|
|||
|
||||
#include "FriendCore.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "model/object/VariantObject.hpp"
|
||||
#include "core/proxy/ListProxy.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(FriendCore)
|
||||
|
||||
const QString addressLabel = FriendCore::tr("Adresse SIP");
|
||||
const QString phoneLabel = FriendCore::tr("Téléphone");
|
||||
|
||||
QVariant createFriendAddressVariant(const QString &label, const QString &address) {
|
||||
QVariantMap map;
|
||||
map.insert("label", label);
|
||||
map.insert("address", address);
|
||||
return map;
|
||||
}
|
||||
|
||||
QSharedPointer<FriendCore> FriendCore::create(const std::shared_ptr<linphone::Friend> &contact) {
|
||||
auto sharedPointer = QSharedPointer<FriendCore>(new FriendCore(contact), &QObject::deleteLater);
|
||||
sharedPointer->setSelf(sharedPointer);
|
||||
|
|
@ -43,28 +53,51 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact) : QObje
|
|||
mConsolidatedPresence = LinphoneEnums::fromLinphone(contact->getConsolidatedPresence());
|
||||
mPresenceTimestamp = mFriendModel->getPresenceTimestamp();
|
||||
mPictureUri = Utils::coreStringToAppString(contact->getPhoto());
|
||||
auto address = contact->getAddress();
|
||||
mAddress = address ? Utils::coreStringToAppString(contact->getAddress()->asStringUriOnly()) : "NoAddress";
|
||||
auto name = contact->getName();
|
||||
mName =
|
||||
name.empty() ? Utils::getDisplayName(mAddress)->getValue().toString() : Utils::coreStringToAppString(name);
|
||||
auto vcard = contact->getVcard();
|
||||
mOrganization = Utils::coreStringToAppString(vcard->getOrganization());
|
||||
mJob = Utils::coreStringToAppString(vcard->getJobTitle());
|
||||
mGivenName = Utils::coreStringToAppString(vcard->getGivenName());
|
||||
mFamilyName = Utils::coreStringToAppString(vcard->getFamilyName());
|
||||
auto addresses = contact->getAddresses();
|
||||
for (auto &address : addresses) {
|
||||
mAddressList.append(
|
||||
createFriendAddressVariant(addressLabel, Utils::coreStringToAppString(address->asStringUriOnly())));
|
||||
}
|
||||
mDefaultAddress =
|
||||
contact->getAddress() ? Utils::coreStringToAppString(contact->getAddress()->asStringUriOnly()) : QString();
|
||||
auto phoneNumbers = contact->getPhoneNumbersWithLabel();
|
||||
for (auto &phoneNumber : phoneNumbers) {
|
||||
mPhoneNumberList.append(
|
||||
createFriendAddressVariant(Utils::coreStringToAppString(phoneNumber->getLabel()),
|
||||
Utils::coreStringToAppString(phoneNumber->getPhoneNumber())));
|
||||
}
|
||||
|
||||
mStarred = contact->getStarred();
|
||||
mIsSaved = true;
|
||||
} else {
|
||||
mIsSaved = false;
|
||||
mStarred = false;
|
||||
}
|
||||
connect(this, &FriendCore::addressChanged, &FriendCore::allAddressesChanged);
|
||||
connect(this, &FriendCore::phoneNumberChanged, &FriendCore::allAddressesChanged);
|
||||
}
|
||||
|
||||
FriendCore::FriendCore(const FriendCore &friendCore) {
|
||||
// Only copy friend values without models for lambda using and avoid concurrencies.
|
||||
mAddress = friendCore.mAddress;
|
||||
mAddressList = friendCore.mAddressList;
|
||||
mPhoneNumberList = friendCore.mPhoneNumberList;
|
||||
mDefaultAddress = friendCore.mDefaultAddress;
|
||||
mGivenName = friendCore.mGivenName;
|
||||
mFamilyName = friendCore.mFamilyName;
|
||||
mOrganization = friendCore.mOrganization;
|
||||
mJob = friendCore.mJob;
|
||||
mPictureUri = friendCore.mPictureUri;
|
||||
mIsSaved = friendCore.mIsSaved;
|
||||
}
|
||||
|
||||
FriendCore::~FriendCore() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
emit mFriendModel->removeListener();
|
||||
if (mFriendModel) emit mFriendModel->removeListener();
|
||||
}
|
||||
|
||||
void FriendCore::setSelf(SafeSharedPointer<FriendCore> me) {
|
||||
|
|
@ -84,20 +117,47 @@ void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
|
|||
setPresenceTimestamp(presenceTimestamp);
|
||||
});
|
||||
});
|
||||
mFriendModelConnection->makeConnectToModel(&FriendModel::pictureUriChanged, [this](QString uri) {
|
||||
mFriendModelConnection->makeConnectToModel(&FriendModel::pictureUriChanged, [this](const 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::givenNameChanged, [this](const QString &name) {
|
||||
mFriendModelConnection->invokeToCore([this, name]() { setGivenName(name); });
|
||||
});
|
||||
mFriendModelConnection->makeConnectToModel(&FriendModel::familyNameChanged, [this](const QString &name) {
|
||||
mFriendModelConnection->invokeToCore([this, name]() { setFamilyName(name); });
|
||||
});
|
||||
mFriendModelConnection->makeConnectToModel(&FriendModel::organizationChanged, [this](const QString &orga) {
|
||||
mFriendModelConnection->invokeToCore([this, orga]() { setOrganization(orga); });
|
||||
});
|
||||
mFriendModelConnection->makeConnectToModel(&FriendModel::jobChanged, [this](const QString &job) {
|
||||
mFriendModelConnection->invokeToCore([this, job]() { setJob(job); });
|
||||
});
|
||||
mFriendModelConnection->makeConnectToModel(&FriendModel::addressesChanged, [this]() {
|
||||
auto numbers = mFriendModel->getAddresses();
|
||||
QList<QVariant> addr;
|
||||
for (auto &num : numbers) {
|
||||
addr.append(
|
||||
createFriendAddressVariant(addressLabel, Utils::coreStringToAppString(num->asStringUriOnly())));
|
||||
}
|
||||
mFriendModelConnection->invokeToCore([this, addr]() { resetPhoneNumbers(addr); });
|
||||
});
|
||||
mFriendModelConnection->makeConnectToModel(&FriendModel::phoneNumbersChanged, [this]() {
|
||||
auto numbers = mFriendModel->getPhoneNumbers();
|
||||
QList<QVariant> addr;
|
||||
for (auto &num : numbers) {
|
||||
addr.append(
|
||||
createFriendAddressVariant(phoneLabel, Utils::coreStringToAppString(num->getPhoneNumber())));
|
||||
}
|
||||
mFriendModelConnection->invokeToCore([this, addr]() { resetPhoneNumbers(addr); });
|
||||
});
|
||||
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); });
|
||||
});
|
||||
|
|
@ -110,19 +170,67 @@ void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
|
|||
}
|
||||
|
||||
void FriendCore::reset(const FriendCore &contact) {
|
||||
setAddress(contact.getAddress());
|
||||
setName(contact.getName());
|
||||
resetAddresses(contact.getAddresses());
|
||||
resetPhoneNumbers(contact.getPhoneNumbers());
|
||||
setDefaultAddress(contact.getDefaultAddress());
|
||||
setGivenName(contact.getGivenName());
|
||||
setFamilyName(contact.getFamilyName());
|
||||
setOrganization(contact.getOrganization());
|
||||
setJob(contact.getJob());
|
||||
setPictureUri(contact.getPictureUri());
|
||||
setIsSaved(mFriendModel != nullptr);
|
||||
}
|
||||
|
||||
QString FriendCore::getName() const {
|
||||
return mName;
|
||||
QString FriendCore::getDisplayName() const {
|
||||
return mGivenName + " " + mFamilyName;
|
||||
}
|
||||
|
||||
void FriendCore::setName(QString data) {
|
||||
if (mName != data) {
|
||||
mName = data;
|
||||
emit addressChanged(mName);
|
||||
QString FriendCore::getGivenName() const {
|
||||
return mGivenName;
|
||||
}
|
||||
|
||||
void FriendCore::setGivenName(const QString &name) {
|
||||
if (mGivenName != name) {
|
||||
mGivenName = name;
|
||||
emit givenNameChanged(name);
|
||||
emit displayNameChanged();
|
||||
setIsSaved(false);
|
||||
}
|
||||
}
|
||||
|
||||
QString FriendCore::getOrganization() const {
|
||||
return mOrganization;
|
||||
}
|
||||
|
||||
void FriendCore::setOrganization(const QString &orga) {
|
||||
if (mOrganization != orga) {
|
||||
mOrganization = orga;
|
||||
emit organizationChanged();
|
||||
setIsSaved(false);
|
||||
}
|
||||
}
|
||||
|
||||
QString FriendCore::getJob() const {
|
||||
return mJob;
|
||||
}
|
||||
|
||||
void FriendCore::setJob(const QString &job) {
|
||||
if (mJob != job) {
|
||||
mJob = job;
|
||||
emit jobChanged();
|
||||
setIsSaved(false);
|
||||
}
|
||||
}
|
||||
|
||||
QString FriendCore::getFamilyName() const {
|
||||
return mFamilyName;
|
||||
}
|
||||
|
||||
void FriendCore::setFamilyName(const QString &name) {
|
||||
if (mFamilyName != name) {
|
||||
mFamilyName = name;
|
||||
emit familyNameChanged(name);
|
||||
emit displayNameChanged();
|
||||
setIsSaved(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -137,18 +245,91 @@ void FriendCore::onStarredChanged(bool starred) {
|
|||
emit starredChanged();
|
||||
}
|
||||
|
||||
QString FriendCore::getAddress() const {
|
||||
return mAddress;
|
||||
QList<QVariant> FriendCore::getPhoneNumbers() const {
|
||||
return mPhoneNumberList;
|
||||
}
|
||||
|
||||
void FriendCore::setAddress(QString address) {
|
||||
if (mAddress != address) {
|
||||
mAddress = address;
|
||||
emit addressChanged(mAddress);
|
||||
QVariant FriendCore::getPhoneNumberAt(int index) const {
|
||||
if (index < 0 || index >= mPhoneNumberList.count()) return QVariant();
|
||||
return mPhoneNumberList[index];
|
||||
}
|
||||
|
||||
void FriendCore::setPhoneNumberAt(int index, const QString &label, const QString &phoneNumber) {
|
||||
if (index < 0 || index >= mPhoneNumberList.count()) return;
|
||||
auto map = mPhoneNumberList[index].toMap();
|
||||
auto oldLabel = map["label"].toString();
|
||||
if (/*oldLabel != label || */ map["address"] != phoneNumber) {
|
||||
mPhoneNumberList.replace(index, createFriendAddressVariant(label.isEmpty() ? oldLabel : label, phoneNumber));
|
||||
emit phoneNumberChanged();
|
||||
setIsSaved(false);
|
||||
}
|
||||
}
|
||||
|
||||
void FriendCore::removePhoneNumber(int index) {
|
||||
if (index != -1) mPhoneNumberList.remove(index);
|
||||
emit phoneNumberChanged();
|
||||
}
|
||||
|
||||
void FriendCore::appendPhoneNumber(const QString &label, const QString &number) {
|
||||
mPhoneNumberList.append(createFriendAddressVariant(label, number));
|
||||
emit phoneNumberChanged();
|
||||
}
|
||||
|
||||
void FriendCore::resetPhoneNumbers(QList<QVariant> newList) {
|
||||
mPhoneNumberList = newList;
|
||||
emit phoneNumberChanged();
|
||||
}
|
||||
|
||||
QList<QVariant> FriendCore::getAddresses() const {
|
||||
return mAddressList;
|
||||
}
|
||||
|
||||
QVariant FriendCore::getAddressAt(int index) const {
|
||||
if (index < 0 || index >= mAddressList.count()) return QVariant();
|
||||
return mAddressList[index];
|
||||
}
|
||||
|
||||
void FriendCore::setAddressAt(int index, const QString &label, const QString &address) {
|
||||
if (index < 0 || index >= mAddressList.count()) return;
|
||||
auto map = mAddressList[index].toMap();
|
||||
auto oldLabel = map["label"].toString();
|
||||
if (/*oldLabel != label || */ map["address"] != address) {
|
||||
mAddressList.replace(index, createFriendAddressVariant(label.isEmpty() ? oldLabel : label, address));
|
||||
emit addressChanged();
|
||||
setIsSaved(false);
|
||||
}
|
||||
}
|
||||
|
||||
void FriendCore::removeAddress(int index) {
|
||||
if (index != -1) mAddressList.remove(index);
|
||||
emit addressChanged();
|
||||
}
|
||||
|
||||
void FriendCore::appendAddress(const QString &addr) {
|
||||
mAddressList.append(createFriendAddressVariant(addressLabel, addr));
|
||||
emit addressChanged();
|
||||
}
|
||||
|
||||
void FriendCore::resetAddresses(QList<QVariant> newList) {
|
||||
mAddressList = newList;
|
||||
emit addressChanged();
|
||||
}
|
||||
|
||||
QList<QVariant> FriendCore::getAllAddresses() const {
|
||||
return mAddressList + mPhoneNumberList;
|
||||
}
|
||||
|
||||
QString FriendCore::getDefaultAddress() const {
|
||||
return mDefaultAddress;
|
||||
}
|
||||
|
||||
void FriendCore::setDefaultAddress(const QString &address) {
|
||||
if (mDefaultAddress != address) {
|
||||
mDefaultAddress = address;
|
||||
emit defaultAddressChanged();
|
||||
}
|
||||
}
|
||||
|
||||
LinphoneEnums::ConsolidatedPresence FriendCore::getConsolidatedPresence() const {
|
||||
return mConsolidatedPresence;
|
||||
}
|
||||
|
|
@ -177,6 +358,13 @@ QString FriendCore::getPictureUri() const {
|
|||
return mPictureUri;
|
||||
}
|
||||
|
||||
void FriendCore::setPictureUri(const QString &uri) {
|
||||
if (mPictureUri != uri) {
|
||||
mPictureUri = uri;
|
||||
emit pictureUriChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void FriendCore::onPictureUriChanged(QString uri) {
|
||||
mPictureUri = uri;
|
||||
emit pictureUriChanged();
|
||||
|
|
@ -192,21 +380,63 @@ void FriendCore::setIsSaved(bool data) {
|
|||
}
|
||||
}
|
||||
|
||||
void FriendCore::writeInto(std::shared_ptr<linphone::Friend> contact) const {
|
||||
void FriendCore::writeIntoModel(std::shared_ptr<FriendModel> model) const {
|
||||
mustBeInLinphoneThread(QString("[") + gClassName + "] " + Q_FUNC_INFO);
|
||||
model->getFriend()->edit();
|
||||
// needed to create the vcard if not created yet
|
||||
model->setName(mGivenName + (mFamilyName.isEmpty() || mGivenName.isEmpty() ? "" : " ") + mFamilyName);
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
auto newAddress = core->createAddress(Utils::appStringToCoreString(mAddress));
|
||||
contact->edit();
|
||||
if (newAddress) contact->setAddress(newAddress);
|
||||
else qDebug() << "Bad address : " << mAddress;
|
||||
contact->done();
|
||||
|
||||
std::list<std::shared_ptr<linphone::Address>> addresses;
|
||||
for (auto &addr : mAddressList) {
|
||||
auto friendAddress = addr.toMap();
|
||||
auto num =
|
||||
linphone::Factory::get()->createAddress(Utils::appStringToCoreString(friendAddress["address"].toString()));
|
||||
addresses.push_back(num);
|
||||
}
|
||||
model->resetAddresses(addresses);
|
||||
|
||||
model->setAddress(ToolModel::interpretUrl(mDefaultAddress));
|
||||
|
||||
std::list<std::shared_ptr<linphone::FriendPhoneNumber>> phones;
|
||||
for (auto &number : mPhoneNumberList) {
|
||||
auto friendAddress = number.toMap();
|
||||
auto num = linphone::Factory::get()->createFriendPhoneNumber(
|
||||
Utils::appStringToCoreString(friendAddress["address"].toString()),
|
||||
Utils::appStringToCoreString(friendAddress["label"].toString()));
|
||||
phones.push_back(num);
|
||||
}
|
||||
model->resetPhoneNumbers(phones);
|
||||
|
||||
model->setGivenName(mGivenName);
|
||||
model->setFamilyName(mFamilyName);
|
||||
model->setOrganization(mOrganization);
|
||||
model->setJob(mJob);
|
||||
model->setPictureUri(mPictureUri);
|
||||
model->getFriend()->done();
|
||||
}
|
||||
|
||||
void FriendCore::writeFrom(const std::shared_ptr<linphone::Friend> &contact) {
|
||||
void FriendCore::writeFromModel(const std::shared_ptr<FriendModel> &model) {
|
||||
mustBeInLinphoneThread(QString("[") + gClassName + "] " + Q_FUNC_INFO);
|
||||
auto address = contact->getAddress();
|
||||
mAddress = (address ? Utils::coreStringToAppString(address->asString()) : "");
|
||||
mName = Utils::coreStringToAppString(contact->getName());
|
||||
|
||||
QList<QVariant> addresses;
|
||||
for (auto &addr : model->getAddresses()) {
|
||||
addresses.append(
|
||||
createFriendAddressVariant(addressLabel, Utils::coreStringToAppString(addr->asStringUriOnly())));
|
||||
}
|
||||
mAddressList = addresses;
|
||||
|
||||
QList<QVariant> phones;
|
||||
for (auto &number : model->getPhoneNumbers()) {
|
||||
phones.append(createFriendAddressVariant(Utils::coreStringToAppString(number->getLabel()),
|
||||
Utils::coreStringToAppString(number->getPhoneNumber())));
|
||||
}
|
||||
mPhoneNumberList = phones;
|
||||
mGivenName = model->getGivenName();
|
||||
mFamilyName = model->getFamilyName();
|
||||
mOrganization = model->getOrganization();
|
||||
mJob = model->getJob();
|
||||
mPictureUri = model->getPictureUri();
|
||||
}
|
||||
|
||||
void FriendCore::remove() {
|
||||
|
|
@ -225,33 +455,40 @@ void FriendCore::save() { // Save Values to model
|
|||
|
||||
if (mFriendModel) {
|
||||
mFriendModelConnection->invokeToModel([this, thisCopy]() { // Copy values to avoid concurrency
|
||||
auto contact = mFriendModel->getFriend();
|
||||
thisCopy->writeInto(contact);
|
||||
thisCopy->writeIntoModel(mFriendModel);
|
||||
thisCopy->deleteLater();
|
||||
mFriendModelConnection->invokeToCore([this]() { saved(); });
|
||||
setIsSaved(true);
|
||||
});
|
||||
} else {
|
||||
mCoreModelConnection->invokeToModel([this, thisCopy]() {
|
||||
auto linphoneAddr = ToolModel::interpretUrl(mAddress);
|
||||
std::shared_ptr<linphone::Friend> contact;
|
||||
auto core = CoreModel::getInstance()->getCore();
|
||||
auto contact = core->findFriend(linphoneAddr);
|
||||
auto friendExists = contact != nullptr;
|
||||
for (auto &addr : mAddressList) {
|
||||
auto friendAddress = addr.toMap();
|
||||
auto linphoneAddr = ToolModel::interpretUrl(friendAddress["address"].toString());
|
||||
contact = core->findFriend(linphoneAddr);
|
||||
if (contact) break;
|
||||
}
|
||||
if (contact != nullptr) {
|
||||
thisCopy->writeInto(contact);
|
||||
auto friendModel = Utils::makeQObject_ptr<FriendModel>(contact);
|
||||
friendModel->setSelf(friendModel);
|
||||
thisCopy->writeIntoModel(friendModel);
|
||||
thisCopy->deleteLater();
|
||||
if (mFriendModelConnection) mFriendModelConnection->invokeToCore([this] { saved(); });
|
||||
else mCoreModelConnection->invokeToCore([this] { saved(); });
|
||||
} else {
|
||||
auto contact = core->createFriend();
|
||||
thisCopy->writeInto(contact);
|
||||
std::shared_ptr<FriendModel> friendModel;
|
||||
friendModel = Utils::makeQObject_ptr<FriendModel>(contact);
|
||||
friendModel->setSelf(friendModel);
|
||||
thisCopy->writeIntoModel(friendModel);
|
||||
thisCopy->deleteLater();
|
||||
bool created = (core->getDefaultFriendList()->addFriend(contact) == linphone::FriendList::Status::OK);
|
||||
if (created) {
|
||||
mFriendModel = Utils::makeQObject_ptr<FriendModel>(contact);
|
||||
mFriendModel->setSelf(mFriendModel);
|
||||
core->getDefaultFriendList()->updateSubscriptions();
|
||||
emit CoreModel::getInstance()->friendAdded();
|
||||
}
|
||||
emit CoreModel::getInstance()->friendAdded();
|
||||
mCoreModelConnection->invokeToCore([this, created]() {
|
||||
if (created) setSelf(mCoreModelConnection->mCore);
|
||||
setIsSaved(created);
|
||||
|
|
@ -259,38 +496,18 @@ void FriendCore::save() { // Save Values to model
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 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<FriendModel>(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
|
||||
if (mFriendModel) {
|
||||
mFriendModelConnection->invokeToModel([this]() {
|
||||
FriendCore *contact = new FriendCore(*this);
|
||||
contact->writeFrom(mFriendModel->getFriend());
|
||||
mFriendModelConnection->invokeToCore([this, contact]() {
|
||||
contact->writeFromModel(mFriendModel);
|
||||
contact->moveToThread(App::getInstance()->thread());
|
||||
mFriendModelConnection->invokeToCore([this, contact]() mutable {
|
||||
this->reset(*contact);
|
||||
contact->deleteLater();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,31 +21,43 @@
|
|||
#ifndef FRIEND_CORE_H_
|
||||
#define FRIEND_CORE_H_
|
||||
|
||||
// #include "FriendAddressList.hpp"
|
||||
#include "core/variant/VariantList.hpp"
|
||||
#include "model/friend/FriendModel.hpp"
|
||||
#include "tool/LinphoneEnums.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include "tool/thread/SafeSharedPointer.hpp"
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// This object is defferent from usual Core. It set internal data from directly from GUI.
|
||||
// Values are saved on request.
|
||||
// This allow revert feature.
|
||||
|
||||
class CoreModel;
|
||||
class FriendCore;
|
||||
|
||||
class FriendCore : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
|
||||
Q_PROPERTY(QString address READ getAddress WRITE setAddress NOTIFY addressChanged)
|
||||
Q_PROPERTY(QList<QVariant> allAdresses READ getAllAddresses NOTIFY allAddressesChanged)
|
||||
Q_PROPERTY(QList<QVariant> phoneNumbers READ getPhoneNumbers NOTIFY phoneNumberChanged)
|
||||
Q_PROPERTY(QList<QVariant> addresses READ getAddresses NOTIFY addressChanged)
|
||||
Q_PROPERTY(QString givenName READ getGivenName WRITE setGivenName NOTIFY givenNameChanged)
|
||||
Q_PROPERTY(QString familyName READ getFamilyName WRITE setFamilyName NOTIFY familyNameChanged)
|
||||
Q_PROPERTY(QString displayName READ getDisplayName NOTIFY displayNameChanged)
|
||||
Q_PROPERTY(QString organization READ getOrganization WRITE setOrganization NOTIFY organizationChanged)
|
||||
Q_PROPERTY(QString job READ getJob WRITE setJob NOTIFY jobChanged)
|
||||
Q_PROPERTY(QString defaultAddress READ getDefaultAddress WRITE setDefaultAddress NOTIFY defaultAddressChanged)
|
||||
Q_PROPERTY(QDateTime presenceTimestamp READ getPresenceTimestamp NOTIFY presenceTimestampChanged)
|
||||
Q_PROPERTY(LinphoneEnums::ConsolidatedPresence consolidatedPresence READ getConsolidatedPresence NOTIFY
|
||||
consolidatedPresenceChanged)
|
||||
Q_PROPERTY(bool isSaved READ getIsSaved NOTIFY isSavedChanged)
|
||||
Q_PROPERTY(QString pictureUri READ getPictureUri WRITE lSetPictureUri NOTIFY pictureUriChanged)
|
||||
Q_PROPERTY(QString pictureUri READ getPictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
|
||||
Q_PROPERTY(bool starred READ getStarred WRITE lSetStarred NOTIFY starredChanged)
|
||||
|
||||
public:
|
||||
|
|
@ -58,14 +70,41 @@ public:
|
|||
void setSelf(SafeSharedPointer<FriendCore> me);
|
||||
void reset(const FriendCore &contact);
|
||||
|
||||
QString getName() const;
|
||||
void setName(QString data);
|
||||
QString getDisplayName() const;
|
||||
|
||||
QString getFamilyName() const;
|
||||
void setFamilyName(const QString &name);
|
||||
|
||||
QString getGivenName() const;
|
||||
void setGivenName(const QString &name);
|
||||
|
||||
QString getOrganization() const;
|
||||
void setOrganization(const QString &name);
|
||||
|
||||
QString getJob() const;
|
||||
void setJob(const QString &name);
|
||||
|
||||
bool getStarred() const;
|
||||
void onStarredChanged(bool starred);
|
||||
|
||||
QString getAddress() const;
|
||||
void setAddress(QString address);
|
||||
QList<QVariant> getPhoneNumbers() const;
|
||||
QVariant getPhoneNumberAt(int index) const;
|
||||
Q_INVOKABLE void appendPhoneNumber(const QString &label, const QString &number);
|
||||
Q_INVOKABLE void removePhoneNumber(int index);
|
||||
Q_INVOKABLE void setPhoneNumberAt(int index, const QString &label, const QString &phoneNumber);
|
||||
void resetPhoneNumbers(QList<QVariant> newList);
|
||||
|
||||
QList<QVariant> getAddresses() const;
|
||||
QVariant getAddressAt(int index) const;
|
||||
Q_INVOKABLE void appendAddress(const QString &addr);
|
||||
Q_INVOKABLE void removeAddress(int index);
|
||||
Q_INVOKABLE void setAddressAt(int index, const QString &label, const QString &address);
|
||||
void resetAddresses(QList<QVariant> newList);
|
||||
|
||||
void setDefaultAddress(const QString &address);
|
||||
QString getDefaultAddress() const;
|
||||
|
||||
QList<QVariant> getAllAddresses() const;
|
||||
|
||||
LinphoneEnums::ConsolidatedPresence getConsolidatedPresence() const;
|
||||
void setConsolidatedPresence(LinphoneEnums::ConsolidatedPresence presence);
|
||||
|
|
@ -77,6 +116,7 @@ public:
|
|||
void setIsSaved(bool isSaved);
|
||||
|
||||
QString getPictureUri() const;
|
||||
void setPictureUri(const QString &uri);
|
||||
void onPictureUriChanged(QString uri);
|
||||
|
||||
void onPresenceReceived(LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp);
|
||||
|
|
@ -87,30 +127,39 @@ public:
|
|||
|
||||
signals:
|
||||
void contactUpdated();
|
||||
void nameChanged(QString name);
|
||||
void displayNameChanged();
|
||||
void givenNameChanged(const QString &name);
|
||||
void familyNameChanged(const QString &name);
|
||||
void starredChanged();
|
||||
void addressChanged(QString address);
|
||||
void phoneNumberChanged();
|
||||
void addressChanged();
|
||||
void organizationChanged();
|
||||
void jobChanged();
|
||||
void consolidatedPresenceChanged(LinphoneEnums::ConsolidatedPresence level);
|
||||
void presenceTimestampChanged(QDateTime presenceTimestamp);
|
||||
void sipAddressAdded(const QString &sipAddress);
|
||||
void sipAddressRemoved(const QString &sipAddress);
|
||||
void pictureUriChanged();
|
||||
void saved();
|
||||
void isSavedChanged(bool isSaved);
|
||||
void removed(FriendCore *contact);
|
||||
void defaultAddressChanged();
|
||||
void allAddressesChanged();
|
||||
|
||||
void lSetPictureUri(QString pictureUri);
|
||||
void lSetStarred(bool starred);
|
||||
|
||||
protected:
|
||||
void writeInto(std::shared_ptr<linphone::Friend> contact) const;
|
||||
void writeFrom(const std::shared_ptr<linphone::Friend> &contact);
|
||||
void writeIntoModel(std::shared_ptr<FriendModel> model) const;
|
||||
void writeFromModel(const std::shared_ptr<FriendModel> &model);
|
||||
|
||||
LinphoneEnums::ConsolidatedPresence mConsolidatedPresence = LinphoneEnums::ConsolidatedPresence::Offline;
|
||||
QDateTime mPresenceTimestamp;
|
||||
QString mName;
|
||||
QString mGivenName;
|
||||
QString mFamilyName;
|
||||
QString mOrganization;
|
||||
QString mJob;
|
||||
bool mStarred;
|
||||
QString mAddress;
|
||||
QList<QVariant> mPhoneNumberList;
|
||||
QList<QVariant> mAddressList;
|
||||
QString mDefaultAddress;
|
||||
QString mPictureUri;
|
||||
bool mIsSaved;
|
||||
std::shared_ptr<FriendModel> mFriendModel;
|
||||
|
|
@ -119,5 +168,6 @@ protected:
|
|||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(FriendCore *)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -58,7 +58,8 @@ 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 *>();
|
||||
show = friendData->getCore()->getName().indexOf(search) == 0;
|
||||
auto friendCore = friendData->getCore();
|
||||
show = friendCore->getGivenName().indexOf(search) == 0 || friendCore->getFamilyName().indexOf(search) == 0;
|
||||
}
|
||||
|
||||
return show;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public:
|
|||
}
|
||||
|
||||
virtual T getAt(const int &index) const {
|
||||
if (index < 0 || index >= mList.count()) return nullptr;
|
||||
if (index < 0 || index >= mList.count()) return T();
|
||||
else return mList[index];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ MagicSearchProxy::MagicSearchProxy(QObject *parent) : SortFilterProxy(parent) {
|
|||
connect(mList.get(), &MagicSearchList::sourceFlagsChanged, this, &MagicSearchProxy::sourceFlagsChanged);
|
||||
connect(mList.get(), &MagicSearchList::aggregationFlagChanged, this, &MagicSearchProxy::aggregationFlagChanged);
|
||||
setSourceModel(mList.get());
|
||||
connect(CoreModel::getInstance().get(), &CoreModel::friendRemoved, this,
|
||||
[this] { emit mList->lSearch(mSearchText); });
|
||||
connect(this, &MagicSearchProxy::forceUpdate, [this] { emit mList->lSearch(mSearchText); });
|
||||
sort(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,10 +48,13 @@ public:
|
|||
LinphoneEnums::MagicSearchAggregation getAggregationFlag() const;
|
||||
void setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag);
|
||||
|
||||
// Q_INVOKABLE forceUpdate();
|
||||
|
||||
signals:
|
||||
void searchTextChanged();
|
||||
void sourceFlagsChanged(int sourceFlags);
|
||||
void aggregationFlagChanged(LinphoneEnums::MagicSearchAggregation aggregationFlag);
|
||||
void forceUpdate();
|
||||
|
||||
protected:
|
||||
QString mSearchText;
|
||||
|
|
|
|||
55
Linphone/core/variant/VariantList.cpp
Normal file
55
Linphone/core/variant/VariantList.cpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// /*
|
||||
// * Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
// *
|
||||
// * This file is part of linphone-desktop
|
||||
// * (see https://www.linphone.org).
|
||||
// *
|
||||
// * This program is free software: you can redistribute it and/or modify
|
||||
// * it under the terms of the GNU General Public License as published by
|
||||
// * the Free Software Foundation, either version 3 of the License, or
|
||||
// * (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have received a copy of the GNU General Public License
|
||||
// * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// */
|
||||
|
||||
#include "VariantList.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(VariantList)
|
||||
|
||||
VariantList::VariantList(QObject *parent) {
|
||||
}
|
||||
|
||||
VariantList::VariantList(QList<QVariant> list, QObject *parent) {
|
||||
set(list);
|
||||
}
|
||||
|
||||
VariantList::~VariantList() {
|
||||
}
|
||||
|
||||
int VariantList::rowCount(const QModelIndex &parent) const {
|
||||
return mList.count();
|
||||
}
|
||||
|
||||
void VariantList::set(QList<QVariant> list) {
|
||||
beginResetModel();
|
||||
mList = list;
|
||||
endResetModel();
|
||||
emit listModelChanged();
|
||||
}
|
||||
|
||||
void VariantList::replace(int index, QVariant newValue) {
|
||||
mList.replace(index, newValue);
|
||||
}
|
||||
|
||||
QVariant VariantList::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 mList[row];
|
||||
return QVariant();
|
||||
}
|
||||
56
Linphone/core/variant/VariantList.hpp
Normal file
56
Linphone/core/variant/VariantList.hpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// /*
|
||||
// * Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
// *
|
||||
// * This file is part of linphone-desktop
|
||||
// * (see https://www.linphone.org).
|
||||
// *
|
||||
// * This program is free software: you can redistribute it and/or modify
|
||||
// * it under the terms of the GNU General Public License as published by
|
||||
// * the Free Software Foundation, either version 3 of the License, or
|
||||
// * (at your option) any later version.
|
||||
// *
|
||||
// * This program is distributed in the hope that it will be useful,
|
||||
// * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// * GNU General Public License for more details.
|
||||
// *
|
||||
// * You should have received a copy of the GNU General Public License
|
||||
// * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
// */
|
||||
// // This object is defferent from usual Core. It set internal data from directly from GUI.
|
||||
// // Values are saved on request.
|
||||
// // This allow revert feature.
|
||||
|
||||
#ifndef VARIANT_LIST_H_
|
||||
#define VARIANT_LIST_H_
|
||||
|
||||
#include "core/proxy/AbstractListProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
// ///////////////////////////// ADDRESS LIST /////////////////////////////
|
||||
|
||||
class VariantList : public AbstractListProxy<QVariant>, public AbstractObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QList<QVariant> model WRITE set NOTIFY listModelChanged)
|
||||
public:
|
||||
VariantList(QObject *parent = Q_NULLPTR);
|
||||
VariantList(QList<QVariant> list, QObject *parent = Q_NULLPTR);
|
||||
~VariantList();
|
||||
|
||||
void set(QList<QVariant> list);
|
||||
|
||||
void replace(int index, QVariant newValue);
|
||||
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
signals:
|
||||
void listModelChanged();
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
Q_DECLARE_METATYPE(VariantList *)
|
||||
|
||||
#endif
|
||||
|
|
@ -52,6 +52,7 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc
|
|||
"data/image/outgoing_call_rejected.svg"
|
||||
"data/image/microphone.svg"
|
||||
"data/image/microphone-slash.svg"
|
||||
"data/image/camera.svg"
|
||||
"data/image/video-camera.svg"
|
||||
"data/image/video-camera-slash.svg"
|
||||
"data/image/speaker-high.svg"
|
||||
|
|
@ -66,6 +67,10 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc
|
|||
"data/image/heart.svg"
|
||||
"data/image/heart-fill.svg"
|
||||
"data/image/record-fill.svg"
|
||||
"data/image/pencil-simple.svg"
|
||||
"data/image/share-network.svg"
|
||||
"data/image/bell-simple.svg"
|
||||
"data/image/bell-simple-slash.svg"
|
||||
"data/image/media_encryption_zrtp_pq.svg"
|
||||
|
||||
data/shaders/roundEffect.vert.qsb
|
||||
|
|
|
|||
|
|
@ -28,10 +28,20 @@
|
|||
|
||||
DEFINE_ABSTRACT_OBJECT(FriendModel)
|
||||
|
||||
FriendModel::FriendModel(const std::shared_ptr<linphone::Friend> &contact, QObject *parent)
|
||||
FriendModel::FriendModel(const std::shared_ptr<linphone::Friend> &contact, const QString &name, QObject *parent)
|
||||
: ::Listener<linphone::Friend, linphone::FriendListener>(contact, parent) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
}
|
||||
connect(this, &FriendModel::addressesChanged, [this] {
|
||||
if (mMonitor->getAddresses().size() == 0) return;
|
||||
if (!mMonitor->getAddress()) mMonitor->setAddress(*mMonitor->getAddresses().begin());
|
||||
});
|
||||
connect(this, &FriendModel::defaultAddressChanged, [this] {
|
||||
if (mMonitor->getAddresses().size() == 0) return;
|
||||
if (!mMonitor->getAddress()) mMonitor->setAddress(*mMonitor->getAddresses().begin());
|
||||
});
|
||||
if (!contact->getName().empty() || !name.isEmpty())
|
||||
mMonitor->setName(contact->getName().empty() ? Utils::appStringToCoreString(name) : contact->getName());
|
||||
};
|
||||
|
||||
FriendModel::~FriendModel() {
|
||||
mustBeInLinphoneThread("~" + getClassName());
|
||||
|
|
@ -49,14 +59,163 @@ QDateTime FriendModel::getPresenceTimestamp() const {
|
|||
} else return QDateTime();
|
||||
}
|
||||
|
||||
QString FriendModel::getAddress() const {
|
||||
return Utils::coreStringToAppString(mMonitor->getAddress()->asStringUriOnly());
|
||||
void FriendModel::setAddress(const std::shared_ptr<linphone::Address> &address) {
|
||||
if (address) {
|
||||
mMonitor->setAddress(address);
|
||||
emit defaultAddressChanged();
|
||||
}
|
||||
}
|
||||
|
||||
std::list<std::shared_ptr<linphone::FriendPhoneNumber>> FriendModel::getPhoneNumbers() const {
|
||||
return mMonitor->getPhoneNumbersWithLabel();
|
||||
}
|
||||
|
||||
void FriendModel::appendPhoneNumber(const std::shared_ptr<linphone::FriendPhoneNumber> &number) {
|
||||
if (number) {
|
||||
mMonitor->addPhoneNumberWithLabel(number);
|
||||
emit phoneNumbersChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void FriendModel::appendPhoneNumbers(const std::list<std::shared_ptr<linphone::FriendPhoneNumber>> &numbers) {
|
||||
for (auto &num : numbers)
|
||||
if (num) mMonitor->addPhoneNumberWithLabel(num);
|
||||
emit phoneNumbersChanged();
|
||||
}
|
||||
|
||||
void FriendModel::resetPhoneNumbers(const std::list<std::shared_ptr<linphone::FriendPhoneNumber>> &numbers) {
|
||||
for (auto &num : mMonitor->getPhoneNumbers())
|
||||
mMonitor->removePhoneNumber(num);
|
||||
for (auto &num : numbers)
|
||||
if (num) mMonitor->addPhoneNumberWithLabel(num);
|
||||
emit phoneNumbersChanged();
|
||||
}
|
||||
|
||||
void FriendModel::removePhoneNumber(const QString &number) {
|
||||
mMonitor->removePhoneNumber(Utils::appStringToCoreString(number));
|
||||
emit phoneNumbersChanged();
|
||||
}
|
||||
|
||||
void FriendModel::clearPhoneNumbers() {
|
||||
for (auto &number : mMonitor->getPhoneNumbers())
|
||||
mMonitor->removePhoneNumber(number);
|
||||
emit phoneNumbersChanged();
|
||||
}
|
||||
|
||||
std::list<std::shared_ptr<linphone::Address>> FriendModel::getAddresses() const {
|
||||
return mMonitor->getAddresses();
|
||||
}
|
||||
|
||||
void FriendModel::appendAddress(const std::shared_ptr<linphone::Address> &addr) {
|
||||
if (addr) {
|
||||
mMonitor->addAddress(addr);
|
||||
emit addressesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void FriendModel::appendAddresses(const std::list<std::shared_ptr<linphone::Address>> &addresses) {
|
||||
for (auto &addr : addresses)
|
||||
if (addr) mMonitor->addAddress(addr);
|
||||
emit addressesChanged();
|
||||
}
|
||||
|
||||
void FriendModel::resetAddresses(const std::list<std::shared_ptr<linphone::Address>> &addresses) {
|
||||
for (auto &addr : mMonitor->getAddresses())
|
||||
mMonitor->removeAddress(addr);
|
||||
for (auto &addr : addresses)
|
||||
if (addr) mMonitor->addAddress(addr);
|
||||
emit addressesChanged();
|
||||
}
|
||||
|
||||
void FriendModel::removeAddress(const std::shared_ptr<linphone::Address> &addr) {
|
||||
if (addr) {
|
||||
mMonitor->removeAddress(addr);
|
||||
emit addressesChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void FriendModel::clearAddresses() {
|
||||
for (auto &addr : mMonitor->getAddresses())
|
||||
if (addr) mMonitor->removeAddress(addr);
|
||||
emit addressesChanged();
|
||||
}
|
||||
|
||||
QString FriendModel::getName() const {
|
||||
return Utils::coreStringToAppString(mMonitor->getName());
|
||||
}
|
||||
|
||||
void FriendModel::setName(const QString &name) {
|
||||
mMonitor->setName(Utils::appStringToCoreString(name));
|
||||
}
|
||||
|
||||
QString FriendModel::getGivenName() const {
|
||||
auto vcard = mMonitor->getVcard();
|
||||
if (!vcard) {
|
||||
mMonitor->createVcard(mMonitor->getName());
|
||||
}
|
||||
return Utils::coreStringToAppString(mMonitor->getVcard()->getGivenName());
|
||||
}
|
||||
|
||||
void FriendModel::setGivenName(const QString &name) {
|
||||
auto vcard = mMonitor->getVcard();
|
||||
if (!vcard) {
|
||||
mMonitor->createVcard(mMonitor->getName());
|
||||
}
|
||||
mMonitor->getVcard()->setGivenName(Utils::appStringToCoreString(name));
|
||||
emit givenNameChanged(name);
|
||||
}
|
||||
|
||||
QString FriendModel::getFamilyName() const {
|
||||
auto vcard = mMonitor->getVcard();
|
||||
if (!vcard) {
|
||||
mMonitor->createVcard(mMonitor->getName());
|
||||
}
|
||||
return Utils::coreStringToAppString(mMonitor->getVcard()->getFamilyName());
|
||||
}
|
||||
|
||||
void FriendModel::setFamilyName(const QString &name) {
|
||||
auto vcard = mMonitor->getVcard();
|
||||
if (!vcard) {
|
||||
mMonitor->createVcard(mMonitor->getName());
|
||||
}
|
||||
mMonitor->getVcard()->setFamilyName(Utils::appStringToCoreString(name));
|
||||
emit familyNameChanged(name);
|
||||
}
|
||||
|
||||
QString FriendModel::getOrganization() const {
|
||||
auto vcard = mMonitor->getVcard();
|
||||
if (!vcard) {
|
||||
mMonitor->createVcard(mMonitor->getName());
|
||||
}
|
||||
return Utils::coreStringToAppString(mMonitor->getVcard()->getOrganization());
|
||||
}
|
||||
|
||||
void FriendModel::setOrganization(const QString &orga) {
|
||||
auto vcard = mMonitor->getVcard();
|
||||
if (!vcard) {
|
||||
mMonitor->createVcard(mMonitor->getName());
|
||||
}
|
||||
mMonitor->getVcard()->setOrganization(Utils::appStringToCoreString(orga));
|
||||
emit organizationChanged(orga);
|
||||
}
|
||||
|
||||
QString FriendModel::getJob() const {
|
||||
auto vcard = mMonitor->getVcard();
|
||||
if (!vcard) {
|
||||
mMonitor->createVcard(mMonitor->getName());
|
||||
}
|
||||
return Utils::coreStringToAppString(mMonitor->getVcard()->getJobTitle());
|
||||
}
|
||||
|
||||
void FriendModel::setJob(const QString &job) {
|
||||
auto vcard = mMonitor->getVcard();
|
||||
if (!vcard) {
|
||||
mMonitor->createVcard(mMonitor->getName());
|
||||
}
|
||||
mMonitor->getVcard()->setJobTitle(Utils::appStringToCoreString(job));
|
||||
emit jobChanged(job);
|
||||
}
|
||||
|
||||
bool FriendModel::getStarred() const {
|
||||
return mMonitor->getStarred();
|
||||
}
|
||||
|
|
@ -70,11 +229,17 @@ void FriendModel::onPresenceReceived(const std::shared_ptr<linphone::Friend> &co
|
|||
emit presenceReceived(LinphoneEnums::fromLinphone(contact->getConsolidatedPresence()), getPresenceTimestamp());
|
||||
}
|
||||
|
||||
void FriendModel::setPictureUri(QString uri) {
|
||||
QString FriendModel::getPictureUri() const {
|
||||
auto vcard = mMonitor->getVcard();
|
||||
if (!vcard) {
|
||||
mMonitor->createVcard(mMonitor->getName());
|
||||
}
|
||||
return Utils::coreStringToAppString(mMonitor->getVcard()->getPhoto());
|
||||
}
|
||||
|
||||
void FriendModel::setPictureUri(const QString &uri) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
auto account = std::dynamic_pointer_cast<linphone::Account>(mMonitor);
|
||||
auto params = account->getParams()->clone();
|
||||
auto oldPictureUri = Utils::coreStringToAppString(params->getPictureUri());
|
||||
auto oldPictureUri = Utils::coreStringToAppString(mMonitor->getPhoto());
|
||||
if (!oldPictureUri.isEmpty()) {
|
||||
QString appPrefix = QStringLiteral("image://%1/").arg(AvatarProvider::ProviderId);
|
||||
if (oldPictureUri.startsWith(appPrefix)) {
|
||||
|
|
@ -83,7 +248,6 @@ void FriendModel::setPictureUri(QString uri) {
|
|||
QFile oldPicture(oldPictureUri);
|
||||
if (!oldPicture.remove()) qWarning() << log().arg("Cannot delete old avatar file at " + oldPictureUri);
|
||||
}
|
||||
params->setPictureUri(Utils::appStringToCoreString(uri));
|
||||
account->setParams(params);
|
||||
mMonitor->setPhoto(Utils::appStringToCoreString(uri));
|
||||
emit pictureUriChanged(uri);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,22 +34,60 @@ class FriendModel : public ::Listener<linphone::Friend, linphone::FriendListener
|
|||
public linphone::FriendListener,
|
||||
public AbstractObject {
|
||||
Q_OBJECT
|
||||
friend class FriendCore;
|
||||
|
||||
public:
|
||||
FriendModel(const std::shared_ptr<linphone::Friend> &contact, QObject *parent = nullptr);
|
||||
FriendModel(const std::shared_ptr<linphone::Friend> &contact,
|
||||
const QString &name = QString(),
|
||||
QObject *parent = nullptr);
|
||||
~FriendModel();
|
||||
|
||||
QDateTime getPresenceTimestamp() const;
|
||||
QString getAddress() const;
|
||||
std::list<std::shared_ptr<linphone::FriendPhoneNumber>> getPhoneNumbers() const;
|
||||
std::list<std::shared_ptr<linphone::Address>> getAddresses() const;
|
||||
QString getName() const;
|
||||
QString getGivenName() const;
|
||||
QString getFamilyName() const;
|
||||
QString getOrganization() const;
|
||||
QString getJob() const;
|
||||
bool getStarred() const;
|
||||
std::shared_ptr<linphone::Friend> getFriend() const;
|
||||
QString getPictureUri() const;
|
||||
|
||||
void setPictureUri(QString uri);
|
||||
protected:
|
||||
void setAddress(const std::shared_ptr<linphone::Address> &address);
|
||||
void appendPhoneNumber(const std::shared_ptr<linphone::FriendPhoneNumber> &number);
|
||||
void appendPhoneNumbers(const std::list<std::shared_ptr<linphone::FriendPhoneNumber>> &numbers);
|
||||
void resetPhoneNumbers(const std::list<std::shared_ptr<linphone::FriendPhoneNumber>> &numbers);
|
||||
void removePhoneNumber(const QString &number);
|
||||
void clearPhoneNumbers();
|
||||
|
||||
void appendAddress(const std::shared_ptr<linphone::Address> &addr);
|
||||
void appendAddresses(const std::list<std::shared_ptr<linphone::Address>> &addresses);
|
||||
void resetAddresses(const std::list<std::shared_ptr<linphone::Address>> &addresses);
|
||||
void removeAddress(const std::shared_ptr<linphone::Address> &addr);
|
||||
void clearAddresses();
|
||||
|
||||
void setName(const QString &name);
|
||||
void setGivenName(const QString &name);
|
||||
void setFamilyName(const QString &name);
|
||||
void setOrganization(const QString &orga);
|
||||
void setJob(const QString &job);
|
||||
|
||||
void setPictureUri(const QString &uri);
|
||||
void setStarred(bool starred);
|
||||
|
||||
signals:
|
||||
void pictureUriChanged(QString uri);
|
||||
void pictureUriChanged(const QString &uri);
|
||||
void starredChanged(bool starred);
|
||||
void addressesChanged();
|
||||
void defaultAddressChanged();
|
||||
void phoneNumbersChanged();
|
||||
// void nameChanged(const QString &name);
|
||||
void givenNameChanged(const QString &name);
|
||||
void familyNameChanged(const QString &name);
|
||||
void organizationChanged(const QString &orga);
|
||||
void jobChanged(const QString &job);
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
|
|
|
|||
|
|
@ -48,6 +48,14 @@ std::shared_ptr<linphone::Address> ToolModel::interpretUrl(const QString &addres
|
|||
return interpretedAddress;
|
||||
}
|
||||
|
||||
std::shared_ptr<linphone::FriendPhoneNumber> ToolModel::makeLinphoneNumber(const QString &label,
|
||||
const QString &number) {
|
||||
auto linphoneNumber = std::make_shared<linphone::FriendPhoneNumber>(nullptr);
|
||||
linphoneNumber->setLabel(Utils::appStringToCoreString(label));
|
||||
linphoneNumber->setLabel(Utils::appStringToCoreString(number));
|
||||
return linphoneNumber;
|
||||
}
|
||||
|
||||
QString ToolModel::getDisplayName(const std::shared_ptr<const linphone::Address> &address) {
|
||||
QString displayName;
|
||||
if (address) {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ public:
|
|||
~ToolModel();
|
||||
|
||||
static std::shared_ptr<linphone::Address> interpretUrl(const QString &address);
|
||||
static std::shared_ptr<linphone::FriendPhoneNumber> makeLinphoneNumber(const QString &label, const QString &number);
|
||||
|
||||
static QString getDisplayName(const std::shared_ptr<const linphone::Address> &address);
|
||||
static QString getDisplayName(QString address);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
#include "core/App.hpp"
|
||||
#include "model/call/CallModel.hpp"
|
||||
#include "model/object/VariantObject.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "model/object/VariantObject.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
#include "tool/providers/AvatarProvider.hpp"
|
||||
#include <QClipboard>
|
||||
#include <QImageReader>
|
||||
#include <QQuickWindow>
|
||||
#include <QRandomGenerator>
|
||||
|
|
@ -49,6 +50,7 @@ VariantObject *Utils::getDisplayName(const QString &address) {
|
|||
QStringList splitted = address.split(":");
|
||||
if (splitted.size() > 0 && splitted[0] == "sip") splitted.removeFirst();
|
||||
VariantObject *data = new VariantObject(splitted.first().split("@").first()); // Scope : GUI
|
||||
if (!data) return nullptr;
|
||||
data->makeRequest([address]() {
|
||||
QString displayName = ToolModel::getDisplayName(address);
|
||||
return displayName;
|
||||
|
|
@ -57,6 +59,19 @@ VariantObject *Utils::getDisplayName(const QString &address) {
|
|||
return data;
|
||||
}
|
||||
|
||||
QString Utils::getGivenNameFromFullName(const QString &fullName) {
|
||||
if (fullName.isEmpty()) return QString();
|
||||
auto nameSplitted = fullName.split(" ");
|
||||
return nameSplitted[0];
|
||||
}
|
||||
|
||||
QString Utils::getFamilyNameFromFullName(const QString &fullName) {
|
||||
if (fullName.isEmpty()) return QString();
|
||||
auto nameSplitted = fullName.split(" ");
|
||||
nameSplitted.removeFirst();
|
||||
return nameSplitted.join(" ");
|
||||
}
|
||||
|
||||
QString Utils::getInitials(const QString &username) {
|
||||
if (username.isEmpty()) return "";
|
||||
|
||||
|
|
@ -81,7 +96,7 @@ VariantObject *Utils::createCall(const QString &sipAddress,
|
|||
const QString &prepareTransfertAddress,
|
||||
const QHash<QString, QString> &headers) {
|
||||
VariantObject *data = new VariantObject(QVariant()); // Scope : GUI
|
||||
|
||||
if (!data) return nullptr;
|
||||
data->makeRequest([sipAddress, prepareTransfertAddress, headers]() {
|
||||
auto call = ToolModel::createCall(sipAddress, prepareTransfertAddress, headers);
|
||||
if (call) {
|
||||
|
|
@ -90,10 +105,14 @@ VariantObject *Utils::createCall(const QString &sipAddress,
|
|||
auto app = App::getInstance();
|
||||
auto window = app->getCallsWindow(callGui);
|
||||
smartShowWindow(window);
|
||||
qDebug() << "Utils : call created" << callGui;
|
||||
// callGui.value<CallGui *>()->getCore()->lSetCameraEnabled(true);
|
||||
});
|
||||
return callGui;
|
||||
} else return QVariant();
|
||||
} else {
|
||||
qDebug() << "Utils : failed to create call";
|
||||
return QVariant();
|
||||
}
|
||||
});
|
||||
data->requestValue();
|
||||
|
||||
|
|
@ -131,7 +150,7 @@ QQuickWindow *Utils::getMainWindow() {
|
|||
|
||||
VariantObject *Utils::haveAccount() {
|
||||
VariantObject *result = new VariantObject();
|
||||
|
||||
if (!result) return nullptr;
|
||||
// Using connect ensure to have sender() and receiver() alive.
|
||||
result->makeRequest([]() {
|
||||
// Model
|
||||
|
|
@ -287,4 +306,8 @@ QStringList Utils::generateSecurityLettersArray(int arraySize, int correctIndex,
|
|||
|
||||
int Utils::getRandomIndex(int size) {
|
||||
return QRandomGenerator::global()->bounded(size);
|
||||
}
|
||||
|
||||
void Utils::copyToClipboard(const QString &text) {
|
||||
QApplication::clipboard()->setText(text);
|
||||
}
|
||||
|
|
@ -52,6 +52,8 @@ public:
|
|||
}
|
||||
|
||||
Q_INVOKABLE static VariantObject *getDisplayName(const QString &address);
|
||||
Q_INVOKABLE static QString getGivenNameFromFullName(const QString &fullName);
|
||||
Q_INVOKABLE static QString getFamilyNameFromFullName(const QString &fullName);
|
||||
Q_INVOKABLE static QString getInitials(const QString &username); // Support UTF32
|
||||
|
||||
Q_INVOKABLE static VariantObject *createCall(const QString &sipAddress,
|
||||
|
|
@ -72,6 +74,7 @@ public:
|
|||
Q_INVOKABLE static QString formatDateElapsedTime(const QDateTime &date);
|
||||
Q_INVOKABLE static QStringList generateSecurityLettersArray(int arraySize, int correctIndex, QString correctCode);
|
||||
Q_INVOKABLE static int getRandomIndex(int size);
|
||||
Q_INVOKABLE static void copyToClipboard(const QString &text);
|
||||
static QString generateSavedFilename(const QString &from, const QString &to);
|
||||
|
||||
static inline QString coreStringToAppString(const std::string &str) {
|
||||
|
|
|
|||
|
|
@ -208,7 +208,6 @@ Window {
|
|||
spacing: 10 * DefaultStyle.dp
|
||||
EffectImage {
|
||||
id: callStatusIcon
|
||||
fillMode: Image.PreserveAspectFit
|
||||
width: 15 * DefaultStyle.dp
|
||||
height: 15 * DefaultStyle.dp
|
||||
source:(mainWindow.call.core.state === LinphoneEnums.CallState.End
|
||||
|
|
|
|||
163
Linphone/view/App/Layout/ContactLayout.qml
Normal file
163
Linphone/view/App/Layout/ContactLayout.qml
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as Control
|
||||
import Linphone
|
||||
import UtilsCpp 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: mainItem
|
||||
spacing: 30 * DefaultStyle.dp
|
||||
|
||||
property var contact
|
||||
property string contactAddress: contact && contact.core.defaultAddress || ""
|
||||
property string contactName: contact && contact.core.displayName || ""
|
||||
|
||||
property bool addressVisible: true
|
||||
|
||||
property alias buttonContent: rightButton.data
|
||||
property alias detailContent: detailControl.data
|
||||
|
||||
component LabelButton: ColumnLayout {
|
||||
id: labelButton
|
||||
property alias image: buttonImg
|
||||
property alias button: button
|
||||
property string label
|
||||
spacing: 8 * DefaultStyle.dp
|
||||
Button {
|
||||
id: button
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredWidth: 56 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 56 * DefaultStyle.dp
|
||||
topPadding: 16 * DefaultStyle.dp
|
||||
bottomPadding: 16 * DefaultStyle.dp
|
||||
leftPadding: 16 * DefaultStyle.dp
|
||||
rightPadding: 16 * DefaultStyle.dp
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 40 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_200
|
||||
}
|
||||
contentItem: Image {
|
||||
id: buttonImg
|
||||
source: labelButton.source
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
fillMode: Image.PreserveAspectFit
|
||||
sourceSize.width: 24 * DefaultStyle.dp
|
||||
sourceSize.height: 24 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: labelButton.label
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: mainItem.implicitWidth
|
||||
Layout.preferredHeight: detailAvatar.height
|
||||
// Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Avatar {
|
||||
// TODO : find friend and pass contact argument
|
||||
id: detailAvatar
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 100 * DefaultStyle.dp
|
||||
height: 100 * DefaultStyle.dp
|
||||
contact: mainItem.contact || null
|
||||
address: !contact && mainItem.contactAddress || mainItem.contactName
|
||||
}
|
||||
Item {
|
||||
id: rightButton
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: detailAvatar.verticalCenter
|
||||
anchors.rightMargin: 20 * DefaultStyle.dp
|
||||
width: 30 * DefaultStyle.dp
|
||||
height: 30 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
// Layout.fillWidth: true
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: mainItem.contactName
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Text {
|
||||
id: contactAddress
|
||||
visible: mainItem.addressVisible
|
||||
text: mainItem.contactAddress
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font {
|
||||
pixelSize: 12 * DefaultStyle.dp
|
||||
weight: 300 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Text {
|
||||
// connection status
|
||||
}
|
||||
}
|
||||
Item {
|
||||
// spacing: 10 * DefaultStyle.dp
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredWidth: mainItem.implicitWidth
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
// Layout.fillHeight: true
|
||||
LabelButton {
|
||||
anchors.left: parent.left
|
||||
// width: 24 * DefaultStyle.dp//image.width
|
||||
// height: image.height
|
||||
image.source: AppIcons.phone
|
||||
label: qsTr("Appel")
|
||||
button.onClicked: {
|
||||
var addr = mainItem.contact.core.defaultAddress
|
||||
var addressEnd = "@sip.linphone.org"
|
||||
if (!addr.endsWith(addressEnd)) addr += addressEnd
|
||||
UtilsCpp.createCall(addr)
|
||||
}
|
||||
}
|
||||
LabelButton {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
// Layout.preferredWidth: image.width
|
||||
// Layout.preferredHeight: image.height
|
||||
image.source: AppIcons.chatTeardropText
|
||||
label: qsTr("Message")
|
||||
button.onClicked: console.debug("[CallPage.qml] TODO : open conversation")
|
||||
}
|
||||
LabelButton {
|
||||
id: videoCall
|
||||
anchors.right: parent.right
|
||||
// Layout.preferredWidth: image.width
|
||||
// Layout.preferredHeight: image.height
|
||||
image.source: AppIcons.videoCamera
|
||||
label: qsTr("Appel Video")
|
||||
button.onClicked: {
|
||||
var addr = mainItem.contact.core.defaultAddress
|
||||
var addressEnd = "@sip.linphone.org"
|
||||
if(!addr.endsWith(addressEnd)) addr += addressEnd
|
||||
UtilsCpp.createCall(addr)
|
||||
console.log("[CallPage.qml] TODO : enable video")
|
||||
}
|
||||
}
|
||||
// Item {Layout.fillWidth: true}
|
||||
|
||||
}
|
||||
ColumnLayout {
|
||||
id: detailControl
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 30 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
|
|
@ -160,7 +160,7 @@ Item {
|
|||
CallPage {
|
||||
id: callPage
|
||||
}
|
||||
//ContactPage{}
|
||||
ContactPage{}
|
||||
//ConversationPage{}
|
||||
//MeetingPage{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
list(APPEND _LINPHONEAPP_QML_FILES
|
||||
view/App/Main.qml
|
||||
view/App/CallsWindow.qml
|
||||
view/App/Layout/ContactLayout.qml
|
||||
view/App/Layout/LoginLayout.qml
|
||||
view/App/Layout/MainLayout.qml
|
||||
|
||||
|
|
@ -18,6 +19,8 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
view/Item/Contact/Avatar.qml
|
||||
view/Item/Contact/Contact.qml
|
||||
view/Item/Contact/ContactDescription.qml
|
||||
view/Item/Contact/ContactEdition.qml
|
||||
view/Item/Contact/ContactsList.qml
|
||||
view/Item/Contact/Sticker.qml
|
||||
|
||||
view/Item/BusyIndicator.qml
|
||||
|
|
@ -25,12 +28,12 @@ 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/Dialog.qml
|
||||
view/Item/DigitInput.qml
|
||||
view/Item/EffectImage.qml
|
||||
view/Item/ErrorText.qml
|
||||
view/Item/IconLabelButton.qml
|
||||
view/Item/MovableMouseArea.qml
|
||||
view/Item/NumericPad.qml
|
||||
view/Item/PhoneNumberComboBox.qml
|
||||
|
|
@ -39,6 +42,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
view/Item/PopupButton.qml
|
||||
view/Item/RadioButton.qml
|
||||
view/Item/RectangleTest.qml
|
||||
view/Item/RoundedBackgroundControl.qml
|
||||
view/Item/SearchBar.qml
|
||||
view/Item/TabBar.qml
|
||||
view/Item/Text.qml
|
||||
|
|
@ -60,6 +64,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
|
|||
|
||||
view/Page/Main/AbstractMainPage.qml
|
||||
view/Page/Main/CallPage.qml
|
||||
view/Page/Main/ContactPage.qml
|
||||
|
||||
# Prototypes
|
||||
view/Prototype/PhoneNumberPrototype.qml
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ Item {
|
|||
Layout.fillWidth: true
|
||||
Layout.topMargin: mainItem.spacing
|
||||
Layout.bottomMargin: mainItem.spacing
|
||||
height: 1
|
||||
height: 1 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_300
|
||||
}
|
||||
MouseArea{
|
||||
|
|
|
|||
|
|
@ -20,6 +20,13 @@ Control.Button {
|
|||
topPadding: 11 * DefaultStyle.dp
|
||||
bottomPadding: 11 * DefaultStyle.dp
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: hovered ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
acceptedButtons: Qt.NoButton
|
||||
}
|
||||
|
||||
background: Item {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ Item {
|
|||
id: startCallPopup
|
||||
property FriendGui contact
|
||||
onContactChanged: {
|
||||
|
||||
console.log("contact changed", contact)
|
||||
}
|
||||
underlineColor: DefaultStyle.main1_500_main
|
||||
anchors.centerIn: parent
|
||||
|
|
@ -53,56 +53,83 @@ Item {
|
|||
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
|
||||
}
|
||||
component AddressButton: Button {
|
||||
property int index
|
||||
property string label
|
||||
property string address
|
||||
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: label
|
||||
// TODO : change this with domain
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 700 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
Layout.leftMargin: 5 * DefaultStyle.dp
|
||||
Layout.rightMargin: 5 * DefaultStyle.dp
|
||||
text: address
|
||||
font {
|
||||
pixelSize: 13 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
visible: index < adresses.count - 1
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_200
|
||||
}
|
||||
}
|
||||
onClicked: mainItem.callButtonPressed(modelData.address)
|
||||
Rectangle {
|
||||
visible: index < selectedContactAddresses.count - 1
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_200
|
||||
}
|
||||
}
|
||||
onClicked: mainItem.callButtonPressed(address)
|
||||
}
|
||||
Repeater {
|
||||
id: selectedContactAddresses
|
||||
model: VariantList {
|
||||
model: startCallPopup.contact && startCallPopup.contact.core.addresses || []
|
||||
}
|
||||
// model: startCallPopup.contact ? startCallPopup.contact.core.addresses : ""
|
||||
// {label: "Work", address: "06000000000"},
|
||||
// {label: "Personal", address: "060000000"}
|
||||
//account.adresses
|
||||
delegate: AddressButton {
|
||||
// property int index
|
||||
// property string label
|
||||
// property string address
|
||||
}
|
||||
}
|
||||
Repeater {
|
||||
id: selectedContactPhoneNumbers
|
||||
model: VariantList {
|
||||
model: startCallPopup.contact && startCallPopup.contact.core.phoneNumbers || []
|
||||
}
|
||||
// model: startCallPopup.contact ? startCallPopup.contact.core.addresses : ""
|
||||
// {label: "Work", address: "06000000000"},
|
||||
// {label: "Personal", address: "060000000"}
|
||||
//account.adresses
|
||||
delegate: AddressButton {
|
||||
// property int index
|
||||
// property string label
|
||||
// property string address
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -113,7 +140,7 @@ Item {
|
|||
id: contactsScrollbar
|
||||
active: true
|
||||
interactive: true
|
||||
policy: Control.ScrollBar.AlwaysOn
|
||||
policy: Control.ScrollBar.AsNeeded
|
||||
// Layout.fillWidth: true
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
|
|
@ -233,9 +260,11 @@ Item {
|
|||
}
|
||||
ContactsList{
|
||||
Layout.fillWidth: true
|
||||
contactMenuVisible: false
|
||||
id: contactList
|
||||
searchBarText: searchBar.text
|
||||
onContactSelected: (contact) => {
|
||||
console.log("contact selected", contact)
|
||||
startCallPopup.contact = contact
|
||||
startCallPopup.open()
|
||||
}
|
||||
|
|
@ -251,6 +280,7 @@ Item {
|
|||
}
|
||||
ContactsList{
|
||||
contactMenuVisible: false
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
initialHeadersVisible: false
|
||||
model: MagicSearchProxy {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import UtilsCpp
|
|||
// Initials will be displayed if there isn't any avatar.
|
||||
// TODO : get FriendGui from Call.
|
||||
|
||||
StackView{
|
||||
StackView {
|
||||
id: mainItem
|
||||
property AccountGui account: null
|
||||
property FriendGui contact: null
|
||||
|
|
@ -20,9 +20,10 @@ StackView{
|
|||
: call
|
||||
? call.core.peerAddress
|
||||
: contact
|
||||
? contact.core.address
|
||||
? contact.core.defaultAddress
|
||||
: ''
|
||||
property var displayNameObj: UtilsCpp.getDisplayName(address)
|
||||
property string displayNameVal: displayNameObj ? displayNameObj.value : ""
|
||||
property bool haveAvatar: (account && account.core.pictureUri )
|
||||
|| (contact && contact.core.pictureUri)
|
||||
|
||||
|
|
@ -57,7 +58,7 @@ StackView{
|
|||
id: initials
|
||||
Rectangle {
|
||||
id: initialItem
|
||||
property string initials: displayNameObj ? UtilsCpp.getInitials(mainItem.displayNameObj.value) : ""
|
||||
property string initials: UtilsCpp.getInitials(mainItem.displayNameVal)
|
||||
radius: width / 2
|
||||
color: DefaultStyle.main2_200
|
||||
height: mainItem.height
|
||||
|
|
@ -74,6 +75,13 @@ StackView{
|
|||
capitalization: Font.AllUppercase
|
||||
}
|
||||
}
|
||||
Image {
|
||||
visible: initialItem.initials.length === 0
|
||||
width: mainItem.width/3
|
||||
height: width
|
||||
source: AppIcons.profile
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
}
|
||||
Component{
|
||||
|
|
@ -92,7 +100,9 @@ StackView{
|
|||
sourceSize.height: avatarItem.height
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
anchors.centerIn: parent
|
||||
source: mainItem.account ? mainItem.account.core.pictureUri : mainItem.contact.core.pictureUri
|
||||
source: mainItem.account && mainItem.account.core.pictureUri
|
||||
|| mainItem.contact && mainItem.contact.core.pictureUri
|
||||
|| ""
|
||||
mipmap: true
|
||||
}
|
||||
ShaderEffect {
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ import UtilsCpp
|
|||
ColumnLayout{
|
||||
id: mainItem
|
||||
property AccountGui account: null
|
||||
property var displayName: account ? UtilsCpp.getDisplayName(account.core.identityAddress) : ''
|
||||
property string topText: displayName ? displayName.value : ''
|
||||
property string bottomText: account ? account.core.identityAddress : ''
|
||||
property var displayName: account ? UtilsCpp.getDisplayName(account.core.identityAddress) : ""
|
||||
property string topText: displayName ? displayName.value : ""
|
||||
property string bottomText: account ? account.core.identityAddress : ""
|
||||
spacing: 0
|
||||
width: topTextItem.implicitWidth
|
||||
Text {
|
||||
|
|
|
|||
250
Linphone/view/Item/Contact/ContactEdition.qml
Normal file
250
Linphone/view/Item/Contact/ContactEdition.qml
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
import QtCore
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls as Control
|
||||
import QtQuick.Dialogs
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
import Linphone
|
||||
import UtilsCpp 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: mainItem
|
||||
|
||||
property FriendGui contact
|
||||
property string title: qsTr("Modifier contact")
|
||||
property string saveButtonText: qsTr("Enregistrer")
|
||||
property string oldPictureUri
|
||||
signal closeEdition()
|
||||
|
||||
Rectangle {
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 40 * DefaultStyle.dp
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10 * DefaultStyle.dp
|
||||
text: mainItem.title
|
||||
font {
|
||||
pixelSize: 20 * DefaultStyle.dp
|
||||
weight: 800 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Button {
|
||||
background: Item{}
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10 * DefaultStyle.dp
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
contentItem: Image {
|
||||
anchors.fill: parent
|
||||
source: AppIcons.closeX
|
||||
}
|
||||
onClicked: {
|
||||
// contact.core.pictureUri = mainItem.oldPictureUri
|
||||
mainItem.contact.core.undo()
|
||||
mainItem.closeEdition()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 69 * DefaultStyle.dp
|
||||
Avatar {
|
||||
contact: mainItem.contact
|
||||
Layout.preferredWidth: 72 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 72 * DefaultStyle.dp
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
IconLabelButton {
|
||||
visible: !mainItem.contact || mainItem.contact.core.pictureUri.length === 0
|
||||
Layout.preferredWidth: width
|
||||
Layout.preferredHeight: 17 * DefaultStyle.dp
|
||||
iconSource: AppIcons.camera
|
||||
iconSize: 17 * DefaultStyle.dp
|
||||
text: qsTr("Ajouter une image")
|
||||
onClicked: fileDialog.open()
|
||||
}
|
||||
RowLayout {
|
||||
visible: mainItem.contact && mainItem.contact.core.pictureUri.length != 0
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
IconLabelButton {
|
||||
Layout.preferredWidth: width
|
||||
Layout.preferredHeight: 17 * DefaultStyle.dp
|
||||
iconSource: AppIcons.pencil
|
||||
iconSize: 17 * DefaultStyle.dp
|
||||
text: qsTr("Modifier")
|
||||
onClicked: fileDialog.open()
|
||||
}
|
||||
FileDialog {
|
||||
id: fileDialog
|
||||
currentFolder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
|
||||
onAccepted: {
|
||||
mainItem.oldPictureUri = mainItem.contact.core.pictureUri
|
||||
var avatarPath = UtilsCpp.createAvatar( selectedFile )
|
||||
if(avatarPath){
|
||||
mainItem.contact.core.pictureUri = avatarPath
|
||||
}
|
||||
}
|
||||
}
|
||||
IconLabelButton {
|
||||
Layout.preferredHeight: 17 * DefaultStyle.dp
|
||||
Layout.preferredWidth: width
|
||||
iconSize: 17 * DefaultStyle.dp
|
||||
iconSource: AppIcons.trashCan
|
||||
text: qsTr("Supprimer")
|
||||
onClicked: mainItem.contact.core.pictureUri = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
spacing: 100 * DefaultStyle.dp
|
||||
Layout.topMargin: 50 * DefaultStyle.dp
|
||||
Layout.bottomMargin: 50 * DefaultStyle.dp
|
||||
ColumnLayout {
|
||||
spacing: 20 * DefaultStyle.dp
|
||||
TextInput {
|
||||
label: qsTr("Prénom")
|
||||
initialText: contact.core.givenName
|
||||
onEditingFinished: contact.core.givenName = text
|
||||
backgroundColor: DefaultStyle.grey_0
|
||||
}
|
||||
TextInput {
|
||||
label: qsTr("Nom")
|
||||
initialText: contact.core.familyName
|
||||
onEditingFinished: contact.core.familyName = text
|
||||
backgroundColor: DefaultStyle.grey_0
|
||||
}
|
||||
TextInput {
|
||||
label: qsTr("Entreprise")
|
||||
initialText: contact.core.organization
|
||||
onEditingFinished: contact.core.organization = text
|
||||
backgroundColor: DefaultStyle.grey_0
|
||||
}
|
||||
TextInput {
|
||||
label: qsTr("Fonction")
|
||||
initialText: contact.core.job
|
||||
onEditingFinished: contact.core.job = text
|
||||
backgroundColor: DefaultStyle.grey_0
|
||||
}
|
||||
Item{Layout.fillHeight: true}
|
||||
}
|
||||
Control.ScrollView {
|
||||
Layout.fillHeight: true
|
||||
contentHeight: content.height
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.rightMargin: 10 * DefaultStyle.dp
|
||||
spacing: 20 * DefaultStyle.dp
|
||||
Repeater {
|
||||
model: VariantList {
|
||||
model: mainItem.contact && mainItem.contact.core.addresses || []
|
||||
}
|
||||
delegate: RowLayout {
|
||||
TextInput {
|
||||
label: modelData.label
|
||||
onEditingFinished: {
|
||||
if (text.length != 0) mainItem.contact.core.setAddressAt(index, text)
|
||||
}
|
||||
initialText: modelData.address
|
||||
backgroundColor: DefaultStyle.grey_0
|
||||
}
|
||||
Button {
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
background: Item{}
|
||||
contentItem: Image {
|
||||
anchors.fill: parent
|
||||
source: AppIcons.closeX
|
||||
}
|
||||
onClicked: mainItem.contact.core.removeAddress(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
TextInput {
|
||||
label: qsTr("Adresse SIP")
|
||||
backgroundColor: DefaultStyle.grey_0
|
||||
onEditingFinished: {
|
||||
if (text.length != 0) mainItem.contact.core.appendAddress(text)
|
||||
setText("")
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Repeater {
|
||||
// phone numbers
|
||||
model: VariantList {
|
||||
model: mainItem.contact && mainItem.contact.core.phoneNumbers || []
|
||||
}
|
||||
delegate: RowLayout {
|
||||
TextInput {
|
||||
label: modelData.label
|
||||
initialText: modelData.address
|
||||
onEditingFinished: {
|
||||
if (text.length != 0) mainItem.contact.core.setPhoneNumberAt(index, qsTr("Téléphone"), text)
|
||||
}
|
||||
backgroundColor: DefaultStyle.grey_0
|
||||
}
|
||||
Button {
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
background: Item{}
|
||||
contentItem: Image {
|
||||
anchors.fill: parent
|
||||
source: AppIcons.closeX
|
||||
}
|
||||
onClicked: mainItem.contact.core.removePhoneNumber(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
TextInput {
|
||||
label: qsTr("Phone")
|
||||
backgroundColor: DefaultStyle.grey_0
|
||||
onEditingFinished: {
|
||||
if (text.length != 0) mainItem.contact.core.appendPhoneNumber(label, text)
|
||||
setText("")
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Item{Layout.fillHeight: true}
|
||||
}
|
||||
Control.ScrollBar.vertical: Control.ScrollBar{
|
||||
id: scrollbar
|
||||
active: true
|
||||
interactive: true
|
||||
policy: Control.ScrollBar.AsNeeded
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 15 * DefaultStyle.dp
|
||||
}
|
||||
Control.ScrollBar.horizontal: Control.ScrollBar{
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.bottomMargin: 100 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 165 * DefaultStyle.dp
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
enabled: mainItem.contact && mainItem.contact.core.givenName.length > 0
|
||||
text: mainItem.saveButtonText
|
||||
onClicked: {
|
||||
mainItem.contact.core.save()
|
||||
mainItem.closeEdition()
|
||||
}
|
||||
}
|
||||
}
|
||||
164
Linphone/view/Item/Contact/ContactsList.qml
Normal file
164
Linphone/view/Item/Contact/ContactsList.qml
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import Linphone
|
||||
import UtilsCpp 1.0
|
||||
|
||||
ListView {
|
||||
id: mainItem
|
||||
Layout.preferredHeight: contentHeight
|
||||
height: contentHeight
|
||||
visible: count > 0
|
||||
|
||||
property string searchBarText
|
||||
|
||||
property bool hoverEnabled: true
|
||||
property bool contactMenuVisible: true
|
||||
property bool initialHeadersVisible: true
|
||||
|
||||
property FriendGui selectedContact: model.getAt(currentIndex) || null
|
||||
|
||||
onCurrentIndexChanged: selectedContact = model.getAt(currentIndex) || null
|
||||
onCountChanged: {
|
||||
selectedContact = model.getAt(currentIndex) || null
|
||||
}
|
||||
|
||||
signal contactSelected(var contact)
|
||||
signal contactStarredChanged()
|
||||
|
||||
onContactStarredChanged: model.forceUpdate()
|
||||
|
||||
model: MagicSearchProxy {
|
||||
searchText: searchBarText.length === 0 ? "*" : searchBarText
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
id: itemDelegate
|
||||
height: 56 * DefaultStyle.dp
|
||||
width: mainItem.width
|
||||
property var previousItem : mainItem.model.count > 0 && index > 0 ? mainItem.model.getAt(index-1) : null
|
||||
property var previousDisplayName: previousItem ? previousItem.core.displayName : ""
|
||||
property var displayName: modelData.core.displayName
|
||||
Connections {
|
||||
target: modelData.core
|
||||
onStarredChanged: mainItem.contactStarredChanged()
|
||||
}
|
||||
Text {
|
||||
id: initial
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.preferredWidth: 20 * DefaultStyle.dp
|
||||
opacity: (!previousItem || !previousDisplayName.startsWith(displayName[0])) ? 1 : 0
|
||||
text: displayName[0]
|
||||
color: DefaultStyle.main2_400
|
||||
font {
|
||||
pixelSize: 20 * DefaultStyle.dp
|
||||
weight: 500 * DefaultStyle.dp
|
||||
capitalization: Font.AllUppercase
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
id: contactDelegate
|
||||
anchors.left: initial.right
|
||||
anchors.leftMargin: 10 * DefaultStyle.dp
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
z: 1
|
||||
Avatar {
|
||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||
contact: modelData
|
||||
}
|
||||
Text {
|
||||
text: itemDelegate.displayName
|
||||
font.pixelSize: 14 * DefaultStyle.dp
|
||||
font.capitalization: Font.Capitalize
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
PopupButton {
|
||||
id: friendPopup
|
||||
z: 1
|
||||
hoverEnabled: mainItem.hoverEnabled
|
||||
visible: mainItem.contactMenuVisible && (contactArea.containsMouse || hovered || popup.opened)
|
||||
popup.x: 0
|
||||
popup.padding: 10 * DefaultStyle.dp
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 5 * DefaultStyle.dp
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
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 {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: contactArea
|
||||
hoverEnabled: mainItem.hoverEnabled
|
||||
anchors.fill: contactDelegate
|
||||
height: mainItem.height
|
||||
Rectangle {
|
||||
anchors.fill: contactArea
|
||||
opacity: 0.7
|
||||
color: DefaultStyle.main2_100
|
||||
visible: contactArea.containsMouse || friendPopup.hovered || mainItem.currentIndex === index
|
||||
}
|
||||
onClicked: {
|
||||
mainItem.currentIndex = index
|
||||
mainItem.contactSelected(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,8 @@ Item {
|
|||
onEnablePersonalCameraChanged: console.log ("enable camera", enablePersonalCamera)
|
||||
property color color: DefaultStyle.grey_600
|
||||
property int radius: 15 * DefaultStyle.dp
|
||||
property var peerAddress: call ? UtilsCpp.getDisplayName(call.core.peerAddress) : null
|
||||
property var peerAddressObj: call ? UtilsCpp.getDisplayName(call.core.peerAddress) : null
|
||||
property string peerAddress: peerAddressObj ? peerAddressObj.value : ""
|
||||
property var identityAddress: account ? UtilsCpp.getDisplayName(account.core.identityAddress) : null
|
||||
|
||||
Rectangle {
|
||||
|
|
@ -42,7 +43,7 @@ Item {
|
|||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 15 * DefaultStyle.dp
|
||||
visible: mainItem.call && mainItem.call != undefined
|
||||
text: mainItem.peerAddress ? mainItem.peerAddress.value : ""
|
||||
text: mainItem.peerAddress
|
||||
color: DefaultStyle.grey_0
|
||||
font {
|
||||
pixelSize: 22 * DefaultStyle.dp
|
||||
|
|
@ -99,8 +100,8 @@ Item {
|
|||
anchors.leftMargin: 10 * DefaultStyle.dp
|
||||
anchors.bottomMargin: 10 * DefaultStyle.dp
|
||||
width: txtMeter.width
|
||||
text: mainItem.call && mainItem.peerAddress
|
||||
? mainItem.peerAddress.value
|
||||
text: mainItem.peerAddress.length != 0
|
||||
? mainItem.peerAddress
|
||||
: mainItem.account && mainItem.identityAddress
|
||||
? mainItem.identityAddress.value
|
||||
: ""
|
||||
|
|
|
|||
|
|
@ -1,140 +0,0 @@
|
|||
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 searchBarText
|
||||
|
||||
property bool contactMenuVisible: true
|
||||
property bool initialHeadersVisible: true
|
||||
|
||||
signal contactSelected(var contact)
|
||||
|
||||
model: MagicSearchProxy {
|
||||
searchText: searchBarText.length === 0 ? "*" : searchBarText
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
Item {
|
||||
width: mainItem.width
|
||||
Layout.preferredWidth: 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 {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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: {
|
||||
mainItem.contactSelected(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
39
Linphone/view/Item/IconLabelButton.qml
Normal file
39
Linphone/view/Item/IconLabelButton.qml
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
import Linphone
|
||||
|
||||
MouseArea {
|
||||
id: mainItem
|
||||
property string iconSource
|
||||
property string text
|
||||
property color color: DefaultStyle.main2_600
|
||||
property int iconSize: 17 * DefaultStyle.dp
|
||||
property int textSize: 14 * DefaultStyle.dp
|
||||
property int textWeight: 400 * DefaultStyle.dp
|
||||
hoverEnabled: true
|
||||
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
width: content.implicitWidth
|
||||
RowLayout {
|
||||
id: content
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
EffectImage {
|
||||
Layout.preferredWidth: mainItem.iconSize
|
||||
Layout.preferredHeight: mainItem.iconSize
|
||||
width: mainItem.iconSize
|
||||
height: mainItem.iconSize
|
||||
source: mainItem.iconSource
|
||||
colorizationColor: mainItem.color
|
||||
}
|
||||
Text {
|
||||
width: implicitWidth
|
||||
Layout.fillWidth: true
|
||||
text: mainItem.text
|
||||
color: mainItem.color
|
||||
font {
|
||||
pixelSize: mainItem.textSize
|
||||
weight: mainItem.textWeight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,15 +24,16 @@ Control.Popup {
|
|||
color: DefaultStyle.grey_100
|
||||
radius: 20 * DefaultStyle.dp
|
||||
}
|
||||
MultiEffect {
|
||||
id: effect
|
||||
anchors.fill: parent
|
||||
source: numPadBackground
|
||||
shadowEnabled: true
|
||||
shadowColor: DefaultStyle.grey_1000
|
||||
shadowOpacity: 0.8
|
||||
shadowBlur: 1
|
||||
}
|
||||
// MultiEffect {
|
||||
// id: effect
|
||||
// anchors.fill: parent
|
||||
// source: numPadBackground
|
||||
// shadowEnabled: true
|
||||
// shadowColor: DefaultStyle.grey_1000
|
||||
// shadowOpacity: 0.1
|
||||
// shadowVerticalOffset: -200 * DefaultStyle.dp
|
||||
// shadowBlur: 1
|
||||
// }
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: parent.height / 2
|
||||
|
|
|
|||
17
Linphone/view/Item/RoundedBackgroundControl.qml
Normal file
17
Linphone/view/Item/RoundedBackgroundControl.qml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls as Control
|
||||
import Linphone
|
||||
|
||||
Control.Control {
|
||||
width: 360 * DefaultStyle.dp
|
||||
property color backgroundColor
|
||||
topPadding: 10 * DefaultStyle.dp
|
||||
bottomPadding: 10 * DefaultStyle.dp
|
||||
leftPadding: 10 * DefaultStyle.dp
|
||||
rightPadding: 10 * DefaultStyle.dp
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 15 * DefaultStyle.dp
|
||||
color: mainItem.backgroundColor ? mainItem.backgroundColor : DefaultStyle.grey_0
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,8 @@ ColumnLayout {
|
|||
property var validator: RegularExpressionValidator{}
|
||||
property bool fillWidth: false
|
||||
property bool enableBackgroundColors: true
|
||||
property color backgroundColor: DefaultStyle.grey_100
|
||||
property color backgroundBorderColor: DefaultStyle.grey_200
|
||||
property string initialText
|
||||
|
||||
property bool enableErrorText: false
|
||||
|
|
@ -26,7 +28,11 @@ ColumnLayout {
|
|||
readonly property string text: textField.text
|
||||
readonly property bool hasActiveFocus: textField.activeFocus
|
||||
|
||||
Component.onCompleted: setText(initialText)
|
||||
signal editingFinished()
|
||||
|
||||
Component.onCompleted: {
|
||||
setText(initialText)
|
||||
}
|
||||
|
||||
function setText(text) {
|
||||
textField.text = text
|
||||
|
|
@ -60,14 +66,12 @@ ColumnLayout {
|
|||
Layout.preferredWidth: mainItem.textInputWidth
|
||||
Layout.preferredHeight: 49 * DefaultStyle.dp
|
||||
radius: 79 * DefaultStyle.dp
|
||||
color: mainItem.enableBackgroundColors ? DefaultStyle.grey_100 : "transparent"
|
||||
border.color: mainItem.enableBackgroundColors
|
||||
? mainItem.errorTextVisible
|
||||
? DefaultStyle.danger_500main
|
||||
: textField.activeFocus
|
||||
? DefaultStyle.main1_500_main
|
||||
: DefaultStyle.grey_200
|
||||
: "transparent"
|
||||
color: mainItem.backgroundColor
|
||||
border.color: mainItem.errorTextVisible
|
||||
? DefaultStyle.danger_500main
|
||||
: textField.activeFocus
|
||||
? DefaultStyle.main1_500_main
|
||||
: mainItem.backgroundBorderColor
|
||||
|
||||
Control.TextField {
|
||||
id: textField
|
||||
|
|
@ -94,6 +98,15 @@ ColumnLayout {
|
|||
color: DefaultStyle.main1_500_main
|
||||
width: 2 * DefaultStyle.dp
|
||||
}
|
||||
onEditingFinished: {
|
||||
mainItem.editingFinished()
|
||||
}
|
||||
|
||||
Keys.onPressed: (event)=> {
|
||||
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
||||
textField.focus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
Control.Button {
|
||||
id: eyeButton
|
||||
|
|
|
|||
|
|
@ -19,23 +19,124 @@ Item {
|
|||
property bool showDefaultItem: true
|
||||
signal noItemButtonPressed()
|
||||
|
||||
Control.SplitView {
|
||||
id: splitView
|
||||
anchors.fill: parent
|
||||
// Control.SplitView {
|
||||
// id: splitView
|
||||
// anchors.fill: parent
|
||||
// anchors.topMargin: 10 * DefaultStyle.dp
|
||||
|
||||
handle: Rectangle {
|
||||
implicitWidth: 8 * DefaultStyle.dp
|
||||
color: Control.SplitHandle.hovered ? DefaultStyle.grey_200 : DefaultStyle.grey_100
|
||||
}
|
||||
// handle: Rectangle {
|
||||
// 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
|
||||
// clip: true
|
||||
// color: DefaultStyle.grey_100
|
||||
// StackLayout {
|
||||
// currentIndex: mainItem.showDefaultItem ? 0 : 1
|
||||
// anchors.fill: parent
|
||||
// ColumnLayout {
|
||||
// id: defaultItem
|
||||
// Layout.fillWidth: true
|
||||
// Layout.fillHeight: true
|
||||
|
||||
// RowLayout {
|
||||
// Layout.fillHeight: true
|
||||
// Layout.fillWidth: true
|
||||
// Layout.alignment: Qt.AlignHCenter
|
||||
// Item {
|
||||
// Layout.fillWidth: true
|
||||
// }
|
||||
// ColumnLayout {
|
||||
// spacing: 30 * DefaultStyle.dp
|
||||
// Item {
|
||||
// Layout.fillHeight: true
|
||||
// }
|
||||
// Image {
|
||||
// Layout.alignment: Qt.AlignHCenter
|
||||
// source: AppIcons.noItemImage
|
||||
// Layout.preferredWidth: 359 * DefaultStyle.dp
|
||||
// Layout.preferredHeight: 314 * DefaultStyle.dp
|
||||
// fillMode: Image.PreserveAspectFit
|
||||
// }
|
||||
// Text {
|
||||
// text: mainItem.emptyListText
|
||||
// Layout.alignment: Qt.AlignHCenter
|
||||
// font {
|
||||
// pixelSize: 22 * DefaultStyle.dp
|
||||
// weight: 800 * DefaultStyle.dp
|
||||
// }
|
||||
// }
|
||||
// Button {
|
||||
// Layout.alignment: Qt.AlignHCenter
|
||||
// contentItem: RowLayout {
|
||||
// Layout.alignment: Qt.AlignVCenter
|
||||
// EffectImage {
|
||||
// colorizationColor: DefaultStyle.grey_0
|
||||
// source: mainItem.newItemIconSource
|
||||
// width: 24 * DefaultStyle.dp
|
||||
// height: 24 * DefaultStyle.dp
|
||||
// fillMode: Image.PreserveAspectFit
|
||||
// }
|
||||
// Text {
|
||||
// text: mainItem.noItemButtonText
|
||||
// wrapMode: Text.WordWrap
|
||||
// color: DefaultStyle.grey_0
|
||||
// font {
|
||||
// weight: 600 * DefaultStyle.dp
|
||||
// pixelSize: 18 * DefaultStyle.dp
|
||||
// family: DefaultStyle.defaultFont
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// onPressed: mainItem.noItemButtonPressed()
|
||||
// }
|
||||
// Item {
|
||||
// Layout.fillHeight: true
|
||||
// }
|
||||
// }
|
||||
// Item {
|
||||
// Layout.fillWidth: true
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
// ColumnLayout {
|
||||
// id: rightPanelItem
|
||||
// Layout.fillWidth: true
|
||||
// Layout.fillHeight: true
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 10 * DefaultStyle.dp
|
||||
spacing: 0
|
||||
ColumnLayout {
|
||||
id: leftPanel
|
||||
Control.SplitView.preferredWidth: 350 * DefaultStyle.dp
|
||||
Control.SplitView.minimumWidth: 350 * DefaultStyle.dp
|
||||
Layout.preferredWidth: 403 * DefaultStyle.dp
|
||||
Layout.minimumWidth: 403 * DefaultStyle.dp
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: false
|
||||
}
|
||||
Rectangle {
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 1 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_200
|
||||
}
|
||||
Rectangle {
|
||||
id: rightPanel
|
||||
clip: true
|
||||
color: DefaultStyle.grey_100
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
StackLayout {
|
||||
currentIndex: mainItem.showDefaultItem ? 0 : 1
|
||||
anchors.fill: parent
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ AbstractMainPage {
|
|||
|
||||
onNoItemButtonPressed: goToNewCall()
|
||||
|
||||
showDefaultItem: listStackView.currentItem.listView ? listStackView.currentItem.listView.count === 0 : true
|
||||
showDefaultItem: listStackView.currentItem.listView && listStackView.currentItem.listView.count === 0 && listStackView.currentItem.listView.model.sourceModel.count === 0 || false
|
||||
|
||||
function goToNewCall() {
|
||||
listStackView.push(newCallItem)
|
||||
|
|
@ -51,6 +51,7 @@ AbstractMainPage {
|
|||
id: historyListItem
|
||||
|
||||
ColumnLayout {
|
||||
property alias listView: historyListView
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: listStackView.sideMargin
|
||||
|
|
@ -91,7 +92,9 @@ AbstractMainPage {
|
|||
}
|
||||
Connections {
|
||||
target: deleteHistoryPopup
|
||||
onAccepted: historyListView.model.removeAllEntries()
|
||||
onAccepted: {
|
||||
historyListView.model.removeAllEntries()
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
removeHistory.close()
|
||||
|
|
@ -156,6 +159,7 @@ AbstractMainPage {
|
|||
model: CallHistoryProxy{
|
||||
filterText: searchBar.text
|
||||
}
|
||||
|
||||
currentIndex: -1
|
||||
|
||||
spacing: 10 * DefaultStyle.dp
|
||||
|
|
@ -205,7 +209,7 @@ AbstractMainPage {
|
|||
anchors.verticalCenter: parent.verticalCenter
|
||||
Text {
|
||||
id: friendAddress
|
||||
property var remoteAddress: modelData ? UtilsCpp.getDisplayName(modelData.core.remoteAddress) : undefined
|
||||
property var remoteAddress: modelData ? UtilsCpp.getDisplayName(modelData.core.remoteAddress) : null
|
||||
text: remoteAddress ? remoteAddress.value : ""
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
|
|
@ -288,18 +292,13 @@ AbstractMainPage {
|
|||
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
|
||||
console.log("visible", visible)
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: mainItem
|
||||
onShowDefaultItemChanged: mainItem.showDefaultItem = mainItem.showDefaultItem && historyListView.count === 0 && historyListView.visible
|
||||
onListViewUpdated: {
|
||||
historyListView.model.updateView()
|
||||
}
|
||||
|
|
@ -312,7 +311,7 @@ AbstractMainPage {
|
|||
Control.ScrollBar {
|
||||
id: scrollbar
|
||||
active: true
|
||||
policy: Control.ScrollBar.AlwaysOn
|
||||
policy: Control.ScrollBar.AsNeeded
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
|
|
@ -322,10 +321,6 @@ AbstractMainPage {
|
|||
Component {
|
||||
id: newCallItem
|
||||
ColumnLayout {
|
||||
Control.StackView.onActivating: {
|
||||
mainItem.showDefaultItem = false
|
||||
}
|
||||
Control.StackView.onDeactivating: mainItem.showDefaultItem = true
|
||||
RowLayout {
|
||||
Layout.leftMargin: listStackView.sideMargin
|
||||
Layout.rightMargin: listStackView.sideMargin
|
||||
|
|
@ -350,214 +345,141 @@ AbstractMainPage {
|
|||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
CallContactsLists {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
// 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
|
||||
UtilsCpp.createCall(address)
|
||||
// var window = UtilsCpp.getCallsWindow()
|
||||
}
|
||||
// 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
|
||||
UtilsCpp.createCall(address)
|
||||
// var window = UtilsCpp.getCallsWindow()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rightPanelContent: RowLayout {
|
||||
rightPanelContent: Control.StackView {
|
||||
id: rightPanelStackView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
visible: mainItem.selectedRowHistoryGui != undefined
|
||||
Layout.topMargin: 45 * DefaultStyle.dp
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
initialItem: emptySelection
|
||||
Connections {
|
||||
target: mainItem
|
||||
onSelectedRowHistoryGuiChanged: {
|
||||
if (mainItem.selectedRowHistoryGui) rightPanelStackView.replace(contactDetailComp, Control.StackView.Immediate)
|
||||
else rightPanelStackView.replace(emptySelection, Control.StackView.Immediate)
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
spacing: 30 * DefaultStyle.dp
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Item {
|
||||
Layout.preferredHeight: detailAvatar.height
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Avatar {
|
||||
id: detailAvatar
|
||||
anchors.centerIn: parent
|
||||
width: 100 * DefaultStyle.dp
|
||||
height: 100 * DefaultStyle.dp
|
||||
address: mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.remoteAddress || ""
|
||||
}
|
||||
PopupButton {
|
||||
id: detailOptions
|
||||
anchors.left: detailAvatar.right
|
||||
anchors.leftMargin: 30 * DefaultStyle.dp
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
popup.x: width
|
||||
popup.contentItem: ColumnLayout {
|
||||
Button {
|
||||
background: Item {}
|
||||
contentItem: IconLabel {
|
||||
text: qsTr("Ajouter aux contacts")
|
||||
iconSource: AppIcons.plusCircle
|
||||
}
|
||||
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()
|
||||
}
|
||||
onCurrentItemChanged: {
|
||||
}
|
||||
}
|
||||
Component{
|
||||
id: emptySelection
|
||||
Item{}
|
||||
}
|
||||
Component {
|
||||
id: contactDetailComp
|
||||
ContactLayout {
|
||||
id: contactDetail
|
||||
visible: mainItem.selectedRowHistoryGui != undefined
|
||||
property var remoteName: mainItem.selectedRowHistoryGui ? UtilsCpp.getDisplayName(mainItem.selectedRowHistoryGui.core.remoteAddress) : null
|
||||
contactAddress: mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.remoteAddress || ""
|
||||
contactName: remoteName ? remoteName.value : ""
|
||||
anchors.top: rightPanelStackView.top
|
||||
anchors.bottom: rightPanelStackView.bottom
|
||||
anchors.topMargin: 45 * DefaultStyle.dp
|
||||
anchors.bottomMargin: 45 * DefaultStyle.dp
|
||||
buttonContent: PopupButton {
|
||||
id: detailOptions
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 30 * DefaultStyle.dp
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
popup.x: width
|
||||
popup.contentItem: ColumnLayout {
|
||||
Button {
|
||||
background: Item {}
|
||||
contentItem: IconLabel {
|
||||
text: qsTr("Ajouter aux contacts")
|
||||
iconSource: AppIcons.plusCircle
|
||||
}
|
||||
Button {
|
||||
background: Item {}
|
||||
contentItem: IconLabel {
|
||||
text: qsTr("Copier l'adresse SIP")
|
||||
iconSource: AppIcons.copy
|
||||
}
|
||||
onClicked: console.debug("[CallPage.qml] TODO : copy SIP address")
|
||||
onClicked: {
|
||||
// console.debug("[CallPage.qml] TODO : add to contact")
|
||||
var friendGui = Qt.createQmlObject('import Linphone
|
||||
FriendGui{
|
||||
}', contactDetail)
|
||||
detailOptions.close()
|
||||
friendGui.core.givenName = UtilsCpp.getGivenNameFromFullName(contactDetail.contactName)
|
||||
friendGui.core.familyName = UtilsCpp.getFamilyNameFromFullName(contactDetail.contactName)
|
||||
friendGui.core.appendAddress(contactDetail.contactAddress)
|
||||
friendGui.core.defaultAddress = contactDetail.contactAddress
|
||||
rightPanelStackView.push(editContact, {"contact": friendGui, "title": qsTr("Ajouter contact"), "saveButtonText": qsTr("Créer")})
|
||||
}
|
||||
Button {
|
||||
background: Item {}
|
||||
contentItem: IconLabel {
|
||||
text: qsTr("Bloquer")
|
||||
iconSource: AppIcons.empty
|
||||
}
|
||||
onClicked: console.debug("[CallPage.qml] TODO : block user")
|
||||
}
|
||||
Button {
|
||||
background: Item {}
|
||||
contentItem: IconLabel {
|
||||
text: qsTr("Copier l'adresse SIP")
|
||||
iconSource: AppIcons.copy
|
||||
}
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 2 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_400
|
||||
onClicked: UtilsCpp.copyToClipboard(mainItem.selectedRowHistoryGui && mainItem.selectedRowHistoryGui.core.remoteAddress)
|
||||
}
|
||||
Button {
|
||||
background: Item {}
|
||||
enabled: false
|
||||
contentItem: IconLabel {
|
||||
text: qsTr("Bloquer")
|
||||
iconSource: AppIcons.empty
|
||||
}
|
||||
Button {
|
||||
background: Item {}
|
||||
contentItem: IconLabel {
|
||||
text: qsTr("Supprimer l'historique")
|
||||
iconSource: AppIcons.trashCan
|
||||
colorizationColor: DefaultStyle.danger_500main
|
||||
}
|
||||
Connections {
|
||||
target: deleteForUserPopup
|
||||
onAccepted: detailListView.model.removeEntriesWithFilter()
|
||||
}
|
||||
onClicked: {
|
||||
detailOptions.close()
|
||||
deleteForUserPopup.open()
|
||||
}
|
||||
onClicked: console.debug("[CallPage.qml] TODO : block user")
|
||||
}
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 2 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_400
|
||||
}
|
||||
Button {
|
||||
background: Item {}
|
||||
contentItem: IconLabel {
|
||||
text: qsTr("Supprimer l'historique")
|
||||
iconSource: AppIcons.trashCan
|
||||
colorizationColor: DefaultStyle.danger_500main
|
||||
}
|
||||
Connections {
|
||||
target: deleteForUserPopup
|
||||
onAccepted: detailListView.model.removeEntriesWithFilter()
|
||||
}
|
||||
onClicked: {
|
||||
detailOptions.close()
|
||||
deleteForUserPopup.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
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 : ""
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Text {
|
||||
id: contactAddress
|
||||
text: mainItem.selectedRowHistoryGui ? mainItem.selectedRowHistoryGui.core.remoteAddress : ""
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font {
|
||||
pixelSize: 12 * DefaultStyle.dp
|
||||
weight: 300 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Text {
|
||||
// connection status
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
spacing: 40 * DefaultStyle.dp
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
// Layout.fillHeight: true
|
||||
Item {Layout.fillWidth: true}
|
||||
LabelButton {
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp//image.width
|
||||
Layout.preferredHeight: image.height
|
||||
image.source: AppIcons.phone
|
||||
label: qsTr("Appel")
|
||||
button.onClicked: {
|
||||
var addr = mainItem.selectedRowHistoryGui.core.remoteAddress
|
||||
var addressEnd = "@sip.linphone.org"
|
||||
if (!addr.endsWith(addressEnd)) addr += addressEnd
|
||||
UtilsCpp.createCall(addr)
|
||||
}
|
||||
}
|
||||
LabelButton {
|
||||
Layout.preferredWidth: image.width
|
||||
Layout.preferredHeight: image.height
|
||||
image.source: AppIcons.chatTeardropText
|
||||
label: qsTr("Message")
|
||||
button.onClicked: console.debug("[CallPage.qml] TODO : open conversation")
|
||||
}
|
||||
LabelButton {
|
||||
Layout.preferredWidth: image.width
|
||||
Layout.preferredHeight: image.height
|
||||
image.source: AppIcons.videoCamera
|
||||
label: qsTr("Appel Video")
|
||||
button.onClicked: {
|
||||
var addr = mainItem.selectedRowHistoryGui.core.remoteAddress
|
||||
var addressEnd = "@sip.linphone.org"
|
||||
if(!addr.endsWith(addressEnd)) addr += addressEnd
|
||||
UtilsCpp.createCall(addr)
|
||||
console.log("[CallPage.qml] TODO : enable video")
|
||||
}
|
||||
}
|
||||
Item {Layout.fillWidth: true}
|
||||
|
||||
}
|
||||
|
||||
Control.Control {
|
||||
detailContent: Control.Control {
|
||||
id: detailControl
|
||||
Layout.preferredWidth: detailListView.width + leftPadding + rightPadding
|
||||
implicitHeight: 430 * DefaultStyle.dp + topPadding + bottomPadding
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: 30 * DefaultStyle.dp
|
||||
|
||||
topPadding: 16 * DefaultStyle.dp
|
||||
bottomPadding: 21 * DefaultStyle.dp
|
||||
leftPadding: 17 * DefaultStyle.dp
|
||||
rightPadding: 17 * DefaultStyle.dp
|
||||
// Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: 360 * DefaultStyle.dp
|
||||
|
||||
background: Rectangle {
|
||||
id: detailListBackground
|
||||
width: parent.width
|
||||
height: detailListView.height
|
||||
color: DefaultStyle.grey_0
|
||||
radius: 15 * DefaultStyle.dp
|
||||
anchors.fill: detailListView
|
||||
}
|
||||
ListView {
|
||||
|
||||
contentItem: ListView {
|
||||
id: detailListView
|
||||
width: 360 * DefaultStyle.dp
|
||||
height: Math.min(detailControl.implicitHeight, contentHeight)
|
||||
anchors.centerIn: detailListBackground
|
||||
anchors.bottomMargin: 21 * DefaultStyle.dp
|
||||
spacing: 10 * DefaultStyle.dp
|
||||
width: parent.width
|
||||
height: Math.min(detailControl.height, contentHeight)
|
||||
|
||||
spacing: 20 * DefaultStyle.dp
|
||||
clip: true
|
||||
|
||||
onCountChanged: {
|
||||
|
|
@ -570,10 +492,11 @@ AbstractMainPage {
|
|||
delegate: Item {
|
||||
width:detailListView.width
|
||||
height: 56 * DefaultStyle.dp
|
||||
// anchors.topMargin: 5 * DefaultStyle.dp
|
||||
// anchors.bottomMargin: 5 * DefaultStyle.dp
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 20 * DefaultStyle.dp
|
||||
anchors.rightMargin: 20 * DefaultStyle.dp
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
RowLayout {
|
||||
|
|
@ -619,6 +542,7 @@ AbstractMainPage {
|
|||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Text {
|
||||
|
|
@ -633,9 +557,11 @@ AbstractMainPage {
|
|||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
Component {
|
||||
id: editContact
|
||||
ContactEdition {
|
||||
onCloseEdition: rightPanelStackView.pop(Control.StackView.Immediate)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
574
Linphone/view/Page/Main/ContactPage.qml
Normal file
574
Linphone/view/Page/Main/ContactPage.qml
Normal file
|
|
@ -0,0 +1,574 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls as Control
|
||||
import Linphone
|
||||
import UtilsCpp 1.0
|
||||
|
||||
AbstractMainPage {
|
||||
id: mainItem
|
||||
noItemButtonText: qsTr("Ajouter un contact")
|
||||
emptyListText: qsTr("Aucun contact pour le moment")
|
||||
newItemIconSource: AppIcons.newCall
|
||||
|
||||
// disable left panel contact list interaction while a contact is being edited
|
||||
property bool leftPanelEnabled: true
|
||||
property FriendGui selectedContact
|
||||
signal forceListsUpdate()
|
||||
|
||||
onNoItemButtonPressed: createNewContact()
|
||||
|
||||
function createNewContact() {
|
||||
console.debug("[ContactPage]User: create new contact")
|
||||
var friendGui = Qt.createQmlObject('import Linphone
|
||||
FriendGui{
|
||||
}', contactDetail)
|
||||
rightPanelStackView.replace(editContact, {"contact": friendGui, "title": qsTr("Nouveau contact"), "saveButtonText": qsTr("Créer")})
|
||||
}
|
||||
|
||||
showDefaultItem: contactList.model.sourceModel.count === 0
|
||||
|
||||
function goToNewCall() {
|
||||
listStackView.replace(newCallItem)
|
||||
}
|
||||
|
||||
leftPanelContent: ColumnLayout {
|
||||
id: leftPanel
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
property int sideMargin: 25 * DefaultStyle.dp
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: leftPanel.sideMargin
|
||||
Layout.rightMargin: leftPanel.sideMargin
|
||||
|
||||
Text {
|
||||
text: qsTr("Contacts")
|
||||
color: DefaultStyle.main2_700
|
||||
font.pixelSize: 29 * DefaultStyle.dp
|
||||
font.weight: 800 * DefaultStyle.dp
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Control.Button {
|
||||
|
||||
background: Item {
|
||||
visible: false
|
||||
}
|
||||
contentItem: Image {
|
||||
source: AppIcons.plusCircle
|
||||
width: 30 * DefaultStyle.dp
|
||||
sourceSize.width: 30 * DefaultStyle.dp
|
||||
fillMode: Image.PreserveAspectFit
|
||||
}
|
||||
onClicked: {
|
||||
mainItem.createNewContact()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.topMargin: 30 * DefaultStyle.dp
|
||||
Layout.leftMargin: leftPanel.sideMargin
|
||||
enabled: mainItem.leftPanelEnabled
|
||||
SearchBar {
|
||||
id: searchBar
|
||||
Layout.rightMargin: leftPanel.sideMargin
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Rechercher un contact")
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Control.ScrollBar {
|
||||
id: contactsScrollbar
|
||||
active: true
|
||||
interactive: true
|
||||
policy: Control.ScrollBar.AsNeeded
|
||||
// Layout.fillWidth: true
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
// Layout.alignment: Qt.AlignRight
|
||||
// x: mainItem.x + mainItem.width - width
|
||||
// anchors.left: control.right
|
||||
}
|
||||
Control.ScrollView {
|
||||
id: listLayout
|
||||
anchors.fill: parent
|
||||
Layout.leftMargin: leftPanel.sideMargin
|
||||
Layout.rightMargin: leftPanel.sideMargin
|
||||
Layout.topMargin: 25 * DefaultStyle.dp
|
||||
rightPadding: leftPanel.sideMargin
|
||||
contentWidth: width - leftPanel.sideMargin
|
||||
contentHeight: content.height
|
||||
clip: true
|
||||
Control.ScrollBar.vertical: contactsScrollbar
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
width: parent.width
|
||||
// anchors.fill: parent
|
||||
spacing: 15 * DefaultStyle.dp
|
||||
Text {
|
||||
text: qsTr("Aucun contact")
|
||||
font {
|
||||
pixelSize: 16 * DefaultStyle.dp
|
||||
weight: 800 * DefaultStyle.dp
|
||||
}
|
||||
visible: contactList.count === 0 && favoriteList.count === 0
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
ColumnLayout {
|
||||
visible: favoriteList.count > 0
|
||||
RowLayout {
|
||||
Text {
|
||||
text: qsTr("Favoris")
|
||||
font {
|
||||
pixelSize: 16 * DefaultStyle.dp
|
||||
weight: 800 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Button {
|
||||
background: Item{}
|
||||
contentItem: Image {
|
||||
source: favoriteList.visible ? AppIcons.upArrow : AppIcons.downArrow
|
||||
}
|
||||
onClicked: favoriteList.visible = !favoriteList.visible
|
||||
}
|
||||
}
|
||||
ContactsList{
|
||||
id: favoriteList
|
||||
hoverEnabled: mainItem.leftPanelEnabled
|
||||
Layout.fillWidth: true
|
||||
onContactStarredChanged: contactList.model.forceUpdate()
|
||||
Connections {
|
||||
target: mainItem
|
||||
onForceListsUpdate: {
|
||||
contactList.model.forceUpdate()
|
||||
}
|
||||
}
|
||||
model: MagicSearchProxy {
|
||||
searchText: searchBar.text.length === 0 ? "*" : searchBar.text
|
||||
sourceFlags: LinphoneEnums.MagicSearchSource.FavoriteFriends
|
||||
aggregationFlag: LinphoneEnums.MagicSearchAggregation.Friend
|
||||
}
|
||||
onSelectedContactChanged: {
|
||||
if (selectedContact) {
|
||||
contactList.currentIndex = -1
|
||||
}
|
||||
mainItem.selectedContact = selectedContact
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
visible: contactList.count > 0
|
||||
RowLayout {
|
||||
Text {
|
||||
text: qsTr("All contacts")
|
||||
font {
|
||||
pixelSize: 16 * DefaultStyle.dp
|
||||
weight: 800 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Button {
|
||||
background: Item{}
|
||||
contentItem: Image {
|
||||
source: contactList.visible ? AppIcons.upArrow : AppIcons.downArrow
|
||||
}
|
||||
onClicked: contactList.visible = !contactList.visible
|
||||
}
|
||||
}
|
||||
ContactsList{
|
||||
id: contactList
|
||||
hoverEnabled: mainItem.leftPanelEnabled
|
||||
Layout.fillWidth: true
|
||||
searchBarText: searchBar.text
|
||||
onContactStarredChanged: favoriteList.model.forceUpdate()
|
||||
Connections {
|
||||
target: mainItem
|
||||
onForceListsUpdate: {
|
||||
contactList.model.forceUpdate()
|
||||
}
|
||||
}
|
||||
onSelectedContactChanged: {
|
||||
if (selectedContact) {
|
||||
favoriteList.currentIndex = -1
|
||||
}
|
||||
mainItem.selectedContact = selectedContact
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
rightPanelContent: Control.StackView {
|
||||
id: rightPanelStackView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
initialItem: contactDetail
|
||||
Binding {
|
||||
mainItem.showDefaultItem: false
|
||||
when: rightPanelStackView.currentItem.objectName == "contactEdition"
|
||||
restoreMode: Binding.RestoreBinding
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: contactDetail
|
||||
RowLayout {
|
||||
visible: mainItem.selectedContact != undefined
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Control.StackView.onActivated:
|
||||
mainItem.leftPanelEnabled = true
|
||||
Control.StackView.onDeactivated: mainItem.leftPanelEnabled = false
|
||||
ContactLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.topMargin: 45 * DefaultStyle.dp
|
||||
Layout.leftMargin: 74 * DefaultStyle.dp
|
||||
contact: mainItem.selectedContact
|
||||
Layout.preferredWidth: 360 * DefaultStyle.dp
|
||||
buttonContent: Button {
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
background: Item{}
|
||||
contentItem: Image {
|
||||
anchors.fill: parent
|
||||
source: AppIcons.pencil
|
||||
}
|
||||
onClicked: rightPanelStackView.replace(editContact, Control.StackView.Immediate)
|
||||
}
|
||||
detailContent: ColumnLayout {
|
||||
Layout.fillWidth: false
|
||||
Layout.preferredWidth: 360 * DefaultStyle.dp
|
||||
spacing: 32 * DefaultStyle.dp
|
||||
ColumnLayout {
|
||||
spacing: 15 * DefaultStyle.dp
|
||||
Text {
|
||||
text: qsTr("Informations")
|
||||
font {
|
||||
pixelSize: 16 * DefaultStyle.dp
|
||||
weight: 800 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
|
||||
RoundedBackgroundControl {
|
||||
Layout.preferredHeight: Math.min(226 * DefaultStyle.dp, addrList.contentHeight + topPadding + bottomPadding)
|
||||
height: Math.min(226 * DefaultStyle.dp, addrList.contentHeight)
|
||||
Layout.fillWidth: true
|
||||
contentItem: ListView {
|
||||
id: addrList
|
||||
width: 360 * DefaultStyle.dp
|
||||
height: contentHeight
|
||||
clip: true
|
||||
model: VariantList {
|
||||
model: mainItem.selectedContact ? mainItem.selectedContact.core.allAdresses : []
|
||||
}
|
||||
// model: contactDetail.selectedContact && contactDetail.selectedContact.core.addresses
|
||||
delegate: Item {
|
||||
width: addrList.width
|
||||
height: 70 * DefaultStyle.dp
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 5 * DefaultStyle.dp
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
// Layout.fillHeight: true
|
||||
// Layout.alignment: Qt.AlignVCenter
|
||||
Layout.topMargin: 10 * DefaultStyle.dp
|
||||
Layout.bottomMargin: 10 * DefaultStyle.dp
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
// TODO change with domain
|
||||
text: modelData.label
|
||||
font {
|
||||
pixelSize: 13 * DefaultStyle.dp
|
||||
weight: 700 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: modelData.address
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Button {
|
||||
background: Item{}
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
contentItem: Image {
|
||||
anchors.fill: parent
|
||||
source: AppIcons.phone
|
||||
width: 24 * DefaultStyle.dp
|
||||
height: 24 * DefaultStyle.dp
|
||||
}
|
||||
onClicked: {
|
||||
UtilsCpp.createCall(modelData.address)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: index != addrList.model.count - 1
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 1 * DefaultStyle.dp
|
||||
Layout.rightMargin: 3 * DefaultStyle.dp
|
||||
Layout.leftMargin: 3 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_200
|
||||
clip: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
RoundedBackgroundControl {
|
||||
visible: companyText.text.length != 0 || jobText.text.length != 0
|
||||
Layout.fillWidth: true
|
||||
// Layout.fillHeight: true
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
// height: 100 * DefaultStyle.dp
|
||||
RowLayout {
|
||||
height: 50 * DefaultStyle.dp
|
||||
Text {
|
||||
text: qsTr("Company :")
|
||||
font {
|
||||
pixelSize: 13 * DefaultStyle.dp
|
||||
weight: 700 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Text {
|
||||
id: companyText
|
||||
text: mainItem.selectedContact && mainItem.selectedContact.core.organization
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
height: 50 * DefaultStyle.dp
|
||||
Text {
|
||||
text: qsTr("Job :")
|
||||
font {
|
||||
pixelSize: 13 * DefaultStyle.dp
|
||||
weight: 700 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Text {
|
||||
id: jobText
|
||||
text: mainItem.selectedContact && mainItem.selectedContact.core.job
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
visible: false
|
||||
Text {
|
||||
text: qsTr("Medias")
|
||||
font {
|
||||
pixelSize: 16 * DefaultStyle.dp
|
||||
weight: 800 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
Button {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: DefaultStyle.grey_0
|
||||
radius: 15 * DefaultStyle.dp
|
||||
}
|
||||
contentItem: RowLayout {
|
||||
Image {
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
source: AppIcons.shareNetwork
|
||||
}
|
||||
Text {
|
||||
text: qsTr("Show media shared")
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
weight: 400 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: console.debug("TODO : go to shared media")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
spacing: 10 * DefaultStyle.dp
|
||||
ColumnLayout {
|
||||
visible: false
|
||||
RowLayout {
|
||||
Text {
|
||||
text: qsTr("Confiance")
|
||||
font {
|
||||
pixelSize: 16 * DefaultStyle.dp
|
||||
weight: 800 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
}
|
||||
RoundedBackgroundControl {
|
||||
contentItem: ColumnLayout {
|
||||
Text {
|
||||
text: qsTr("Niveau de confiance - Appareils vérifiés")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
Text {
|
||||
text: qsTr("Other actions")
|
||||
font {
|
||||
pixelSize: 16 * DefaultStyle.dp
|
||||
weight: 800 * DefaultStyle.dp
|
||||
}
|
||||
}
|
||||
RoundedBackgroundControl {
|
||||
Layout.preferredWidth: 360 * DefaultStyle.dp
|
||||
contentItem: ColumnLayout {
|
||||
width: parent.width
|
||||
|
||||
IconLabelButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15 * DefaultStyle.dp
|
||||
Layout.rightMargin: 15 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 50 * DefaultStyle.dp
|
||||
iconSize: 24 * DefaultStyle.dp
|
||||
iconSource: AppIcons.pencil
|
||||
text: qsTr("Edit")
|
||||
onClicked: rightPanelStackView.replace(editContact, Control.StackView.Immediate)
|
||||
}
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15 * DefaultStyle.dp
|
||||
Layout.rightMargin: 15 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 1 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_200
|
||||
}
|
||||
IconLabelButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15 * DefaultStyle.dp
|
||||
Layout.rightMargin: 15 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 50 * DefaultStyle.dp
|
||||
iconSize: 24 * DefaultStyle.dp
|
||||
iconSource: mainItem.selectedContact && mainItem.selectedContact.core.starred ? AppIcons.heartFill : AppIcons.heart
|
||||
text: mainItem.selectedContact && mainItem.selectedContact.core.starred ? qsTr("Remove from favourites") : qsTr("Add to favourites")
|
||||
onClicked: if (mainItem.selectedContact) mainItem.selectedContact.core.lSetStarred(!mainItem.selectedContact.core.starred)
|
||||
}
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15 * DefaultStyle.dp
|
||||
Layout.rightMargin: 15 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 1 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_200
|
||||
}
|
||||
IconLabelButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15 * DefaultStyle.dp
|
||||
Layout.rightMargin: 15 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 50 * DefaultStyle.dp
|
||||
iconSize: 24 * DefaultStyle.dp
|
||||
iconSource: AppIcons.shareNetwork
|
||||
text: qsTr("Share")
|
||||
onClicked: console.log("TODO : share contact")
|
||||
}
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15 * DefaultStyle.dp
|
||||
Layout.rightMargin: 15 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 1 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_200
|
||||
}
|
||||
IconLabelButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15 * DefaultStyle.dp
|
||||
Layout.rightMargin: 15 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 50 * DefaultStyle.dp
|
||||
iconSize: 24 * DefaultStyle.dp
|
||||
iconSource: AppIcons.bellSlash
|
||||
text: qsTr("Mute")
|
||||
onClicked: console.log("TODO : mute contact")
|
||||
}
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15 * DefaultStyle.dp
|
||||
Layout.rightMargin: 15 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 1 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_200
|
||||
}
|
||||
IconLabelButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15 * DefaultStyle.dp
|
||||
Layout.rightMargin: 15 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 50 * DefaultStyle.dp
|
||||
iconSize: 24 * DefaultStyle.dp
|
||||
iconSource: AppIcons.empty
|
||||
text: qsTr("Block")
|
||||
onClicked: console.log("TODO : block contact")
|
||||
}
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15 * DefaultStyle.dp
|
||||
Layout.rightMargin: 15 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 1 * DefaultStyle.dp
|
||||
color: DefaultStyle.main2_200
|
||||
}
|
||||
IconLabelButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15 * DefaultStyle.dp
|
||||
Layout.rightMargin: 15 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 50 * DefaultStyle.dp
|
||||
iconSize: 24 * DefaultStyle.dp
|
||||
iconSource: AppIcons.trashCan
|
||||
color: DefaultStyle.danger_500main
|
||||
text: qsTr("Delete this contact")
|
||||
onClicked: mainItem.selectedContact.core.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO : find device by friend
|
||||
}
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: editContact
|
||||
ContactEdition {
|
||||
id: contactEdition
|
||||
property string objectName: "contactEdition"
|
||||
contact: mainItem.selectedContact
|
||||
onCloseEdition: {
|
||||
mainItem.forceListsUpdate()
|
||||
rightPanelStackView.replace(contactDetail, Control.StackView.Immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -38,8 +38,8 @@ ListView{
|
|||
Text{
|
||||
// Store the VariantObject and use value on this object. Do not use value in one line because of looping signals.
|
||||
property var displayName: UtilsCpp.getDisplayName($modelData.identityAddress)
|
||||
text: displayName.value
|
||||
onTextChanged: console.log('[ProtoAccounts] Async account displayName: ' +$modelData.identityAddress + " => " +text)
|
||||
text: displayName ? displayName.value : ""
|
||||
onTextChanged: console.log("[ProtoAccounts] Async account displayName: " +$modelData.identityAddress + " => " +text)
|
||||
}
|
||||
Text{
|
||||
text: $modelData.registrationState == LinphoneEnums.RegistrationState.Ok
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ Window{
|
|||
}
|
||||
TextInput{
|
||||
placeholderText: 'Name'
|
||||
initialText: contact.core.name
|
||||
onTextChanged: contact.core.name = text
|
||||
initialText: contact.core.givenName
|
||||
onTextChanged: contact.core.givenName = text
|
||||
}
|
||||
TextInput{
|
||||
placeholderText: 'Address'
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ QtObject {
|
|||
property string outgoingCallRejected: "image://internal/outgoing_call_rejected.svg"
|
||||
property string microphone: "image://internal/microphone.svg"
|
||||
property string microphoneSlash: "image://internal/microphone-slash.svg"
|
||||
property string camera: "image://internal/camera.svg"
|
||||
property string videoCamera: "image://internal/video-camera.svg"
|
||||
property string videoCameraSlash: "image://internal/video-camera-slash.svg"
|
||||
property string speaker: "image://internal/speaker-high.svg"
|
||||
|
|
@ -67,4 +68,9 @@ QtObject {
|
|||
property string heartFill: "image://internal/heart-fill.svg"
|
||||
property string recordFill: "image://internal/record-fill.svg"
|
||||
property string mediaEncryptionZrtpPq: "image://internal/media_encryption_zrtp_pq.svg"
|
||||
}
|
||||
property string pencil: "image://internal/pencil-simple.svg"
|
||||
property string shareNetwork: "image://internal/share-network.svg"
|
||||
property string bell: "image://internal/bell-simple.svg"
|
||||
property string bellSlash: "image://internal/bell-simple-slash.svg"
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue