Commit 1de0129e authored by Ronan Abhamon's avatar Ronan Abhamon

fix(ui/views/App/Main/ContactEdit): smart edition

parent 40f5c1a4
......@@ -195,7 +195,7 @@ void CallsListModel::removeCall (const shared_ptr<linphone::Call> &call) {
} catch (const out_of_range &) {
// Can be a bug. Or the call model not exists because the linphone call state
// `CallStateIncomingReceived`/`CallStateOutgoingInit` was not notified.
qWarning() << QStringLiteral("Unable to found call in:") << callModel;
qWarning() << QStringLiteral("Unable to found linphone call:") << &(*call);
return;
}
......
......@@ -31,28 +31,39 @@ using namespace std;
// =============================================================================
ContactModel::ContactModel (QObject *parent, shared_ptr<linphone::Friend> linphoneFriend) : QObject(parent) {
Q_ASSERT(linphoneFriend != nullptr);
mLinphoneFriend = linphoneFriend;
mVcard = make_shared<VcardModel>(linphoneFriend->getVcard());
App::getInstance()->getEngine()->setObjectOwnership(mVcard.get(), QQmlEngine::CppOwnership);
mVcardModel = new VcardModel(linphoneFriend->getVcard());
App::getInstance()->getEngine()->setObjectOwnership(mVcardModel, QQmlEngine::CppOwnership);
mLinphoneFriend->setData("contact-model", *this);
}
ContactModel::ContactModel (QObject *parent, VcardModel *vcard) : QObject(parent) {
Q_ASSERT(vcard != nullptr);
ContactModel::ContactModel (QObject *parent, VcardModel *vcardModel) : QObject(parent) {
Q_ASSERT(vcardModel != nullptr);
QQmlEngine *engine = App::getInstance()->getEngine();
if (engine->objectOwnership(vcard) == QQmlEngine::CppOwnership)
throw invalid_argument("A contact is already linked to this vcard.");
if (engine->objectOwnership(vcardModel) == QQmlEngine::CppOwnership) {
qWarning() << QStringLiteral("A contact is already linked to this vcard:") << vcardModel;
abort();
}
mLinphoneFriend = linphone::Friend::newFromVcard(vcard->mVcard);
Q_ASSERT(vcardModel->mVcard != nullptr);
mLinphoneFriend = linphone::Friend::newFromVcard(vcardModel->mVcard);
mLinphoneFriend->setData("contact-model", *this);
mVcard.reset(vcard);
mVcardModel = vcardModel;
engine->setObjectOwnership(vcardModel, QQmlEngine::CppOwnership);
engine->setObjectOwnership(vcard, QQmlEngine::CppOwnership);
qInfo() << QStringLiteral("Create contact from vcard:") << this << vcardModel;
}
// -----------------------------------------------------------------------------
void ContactModel::refreshPresence () {
Presence::PresenceStatus status = static_cast<Presence::PresenceStatus>(
mLinphoneFriend->getConsolidatedPresence()
......@@ -62,15 +73,17 @@ void ContactModel::refreshPresence () {
emit presenceLevelChanged(Presence::getPresenceLevel(status));
}
// -----------------------------------------------------------------------------
void ContactModel::startEdit () {
mLinphoneFriend->edit();
mOldSipAddresses = mVcard->getSipAddresses();
mOldSipAddresses = mVcardModel->getSipAddresses();
}
void ContactModel::endEdit () {
mLinphoneFriend->done();
QVariantList sipAddresses = mVcard->getSipAddresses();
QVariantList sipAddresses = mVcardModel->getSipAddresses();
QSet<QString> done;
for (const auto &variantA : mOldSipAddresses) {
......@@ -104,13 +117,13 @@ next:
}
void ContactModel::abortEdit () {
// TODO: call linphone friend abort function when available.
// mLinphoneFriend->abort();
mOldSipAddresses.clear();
emit contactUpdated();
}
// -----------------------------------------------------------------------------
Presence::PresenceStatus ContactModel::getPresenceStatus () const {
return static_cast<Presence::PresenceStatus>(mLinphoneFriend->getConsolidatedPresence());
}
......@@ -118,3 +131,24 @@ Presence::PresenceStatus ContactModel::getPresenceStatus () const {
Presence::PresenceLevel ContactModel::getPresenceLevel () const {
return Presence::getPresenceLevel(getPresenceStatus());
}
// -----------------------------------------------------------------------------
VcardModel *ContactModel::getVcardModel () const {
return mVcardModel;
}
void ContactModel::setVcardModel (VcardModel *vcardModel) {
Q_ASSERT(vcardModel != nullptr);
Q_ASSERT(vcardModel != mVcardModel);
QQmlEngine *engine = App::getInstance()->getEngine();
engine->setObjectOwnership(vcardModel, QQmlEngine::CppOwnership);
engine->setObjectOwnership(mVcardModel, QQmlEngine::JavaScriptOwnership);
qInfo() << QStringLiteral("Set vcard on contact:") << this << vcardModel;
qInfo() << QStringLiteral("Remove vcard on contact:") << this << mVcardModel;
mLinphoneFriend->setVcard(vcardModel->mVcard);
mVcardModel = vcardModel;
}
......@@ -33,29 +33,30 @@ class ContactModel : public QObject {
Q_PROPERTY(Presence::PresenceStatus presenceStatus READ getPresenceStatus NOTIFY presenceStatusChanged);
Q_PROPERTY(Presence::PresenceLevel presenceLevel READ getPresenceLevel NOTIFY presenceLevelChanged);
Q_PROPERTY(VcardModel * vcard READ getVcardModelPtr NOTIFY contactUpdated);
Q_PROPERTY(VcardModel * vcard READ getVcardModel WRITE setVcardModel NOTIFY contactUpdated);
// Grant access to `mLinphoneFriend`.
friend class ContactsListModel;
friend class ContactsListProxyModel;
friend class SmartSearchBarModel;
public:
ContactModel (QObject *parent, std::shared_ptr<linphone::Friend> linphoneFriend);
ContactModel (QObject *parent, VcardModel *vcard);
ContactModel (QObject *parent, VcardModel *vcardModel);
~ContactModel () = default;
std::shared_ptr<VcardModel> getVcardModel () const {
return mVcard;
}
void refreshPresence ();
Q_INVOKABLE void startEdit ();
Q_INVOKABLE void endEdit ();
Q_INVOKABLE void abortEdit ();
VcardModel *getVcardModel () const;
void setVcardModel (VcardModel *vcardModel);
signals:
void contactUpdated ();
void presenceStatusChanged (Presence::PresenceStatus status);
void presenceLevelChanged (Presence::PresenceLevel level);
void sipAddressAdded (const QString &sipAddress);
......@@ -65,13 +66,9 @@ private:
Presence::PresenceStatus getPresenceStatus () const;
Presence::PresenceLevel getPresenceLevel () const;
VcardModel *getVcardModelPtr () const {
return mVcard.get();
}
QVariantList mOldSipAddresses;
std::shared_ptr<VcardModel> mVcard;
VcardModel *mVcardModel;
std::shared_ptr<linphone::Friend> mLinphoneFriend;
};
......
......@@ -71,6 +71,8 @@ inline shared_ptr<belcard::BelCardPhoto> findBelCardPhoto (const list<shared_ptr
// -----------------------------------------------------------------------------
VcardModel::VcardModel (shared_ptr<linphone::Vcard> vcard) : mVcard(vcard) {}
VcardModel::~VcardModel () {
// If it's a detached Vcard, the linked photo must be destroyed from fs.
if (App::getInstance()->getEngine()->objectOwnership(this) != QQmlEngine::CppOwnership) {
......@@ -87,7 +89,16 @@ VcardModel::~VcardModel () {
if (!QFile::remove(imagePath))
qWarning() << QStringLiteral("Unable to remove `%1`.").arg(imagePath);
}
qInfo() << QStringLiteral("Destroy detached vcard:") << this;
} else
qInfo() << QStringLiteral("Destroy attached vcard:") << this;
}
// -----------------------------------------------------------------------------
VcardModel *VcardModel::clone () const {
return new VcardModel(mVcard->clone());
}
// -----------------------------------------------------------------------------
......@@ -113,7 +124,7 @@ QString VcardModel::getAvatar () const {
// No path found.
if (!photo)
return "";
return QStringLiteral("");
// Returns right path.
return QStringLiteral("image://%1/%2").arg(AvatarProvider::PROVIDER_ID).arg(
......
......@@ -29,7 +29,7 @@
// =============================================================================
class VcardModel : public QObject {
friend class ContactModel;
friend class ContactModel; // Grant access to `mVcard`.
Q_OBJECT;
......@@ -42,13 +42,15 @@ class VcardModel : public QObject {
Q_PROPERTY(QVariantList urls READ getUrls NOTIFY vcardUpdated);
public:
VcardModel (std::shared_ptr<linphone::Vcard> vcard) : mVcard(vcard) {}
VcardModel (std::shared_ptr<linphone::Vcard> vcard);
~VcardModel ();
QString getUsername () const;
QVariantList getSipAddresses () const;
Q_INVOKABLE VcardModel *clone () const;
Q_INVOKABLE bool addSipAddress (const QString &sipAddress);
Q_INVOKABLE void removeSipAddress (const QString &sipAddress);
Q_INVOKABLE bool updateSipAddress (const QString &oldSipAddress, const QString &sipAddress);
......
......@@ -16,7 +16,6 @@ RowLayout {
property alias title: text.text
property bool readOnly: false
property int inputMethodHints
property var defaultData: []
property var minValues
readonly property int count: values.count
......@@ -193,15 +192,5 @@ RowLayout {
}
model: ListModel {}
// -------------------------------------------------------------------------
// Init values.
// -------------------------------------------------------------------------
Component.onCompleted: {
if (defaultData) {
setData(defaultData)
}
}
}
}
......@@ -332,7 +332,7 @@ function extractProperties (obj, pattern) {
// -----------------------------------------------------------------------------
// Returns an array from a `object` or `array` argument.
// Returns an array from an `object` or `array` argument.
function ensureArray (obj) {
if (isArray(obj)) {
return obj
......@@ -502,18 +502,6 @@ function includes (obj, value, startIndex) {
// -----------------------------------------------------------------------------
function invert (obj) {
var out = {}
for (var key in obj) {
out[key] = obj[key]
}
return out
}
// -----------------------------------------------------------------------------
function isArray (array) {
return (array instanceof Array)
}
......
......@@ -16,31 +16,37 @@ function handleCreation () {
if (!contact) {
var vcard = Linphone.CoreManager.createDetachedVcardModel()
contactEdit._vcard = vcard
if (sipAddress && sipAddress.length > 0) {
vcard.addSipAddress(sipAddress)
}
contactEdit._vcard = vcard
contactEdit._edition = true
} else {
contactEdit._vcard = contact.vcard
}
}
function handleDestruction () {
var contact = contactEdit._contact
if (contactEdit._edition && contact) {
contact.abortEdit()
function handleVcardChanged (vcard) {
if (!vcard) {
vcard = {}
}
addresses.setData(vcard.sipAddresses)
companies.setData(vcard.companies)
emails.setData(vcard.emails)
urls.setData(vcard.urls)
}
// -----------------------------------------------------------------------------
function editContact () {
contactEdit._contact.startEdit()
var contact = contactEdit._contact
contact.startEdit()
contactEdit._vcard = contact.vcard.clone()
contactEdit._edition = true
window.lockView({
......@@ -64,12 +70,14 @@ function removeContact () {
function save () {
var contact = contactEdit._contact
var vcard = contactEdit._vcard
if (contact) {
contact.vcard = vcard
contact.endEdit()
window.unlockView()
} else {
contactEdit._contact = Linphone.ContactsListModel.addContact(contactEdit._vcard)
contactEdit._contact = Linphone.ContactsListModel.addContact(vcard)
}
contactEdit._edition = false
......@@ -79,9 +87,11 @@ function cancel () {
var contact = contactEdit._contact
if (contact) {
contactEdit._vcard = contact.vcard
contact.abortEdit()
contactEdit._edition = false
window.unlockView()
contactEdit._edition = false
} else {
window.setView('Contacts')
}
......@@ -104,51 +114,41 @@ function setUsername (username) {
// -----------------------------------------------------------------------------
function handleSipAddressChanged (sipAddresses, index, defaultValue, newValue) {
function handleValueChanged (fields, index, defaultValue, newValue, add, update) {
if (newValue === defaultValue) {
return
}
var vcard = contactEdit._vcard
var soFarSoGood = (defaultValue.length === 0)
? vcard.addSipAddress(newValue)
: vcard.updateSipAddress(defaultValue, newValue)
? vcard[add](newValue)
: vcard[update](defaultValue, newValue)
sipAddresses.setInvalid(index, !soFarSoGood)
fields.setInvalid(index, !soFarSoGood)
}
function handleCompanyChanged (companies, index, defaultValue, newValue) {
var vcard = contactEdit._vcard
var soFarSoGood = (defaultValue.length === 0)
? vcard.addCompany(newValue)
: vcard.updateCompany(defaultValue, newValue)
companies.setInvalid(index, !soFarSoGood)
function handleSipAddressChanged () {
var args = Array.prototype.slice.call(arguments)
args.push('addSipAddress', 'updateSipAddress')
handleValueChanged.apply(this, args)
}
function handleEmailChanged (emails, index, defaultValue, newValue) {
var vcard = contactEdit._vcard
var soFarSoGood = (defaultValue.length === 0)
? vcard.addEmail(newValue)
: vcard.updateEmail(defaultValue, newValue)
emails.setInvalid(index, !soFarSoGood)
function handleCompanyChanged () {
var args = Array.prototype.slice.call(arguments)
args.push('addCompany', 'updateCompany')
handleValueChanged.apply(this, args)
}
function handleUrlChanged (urls, index, defaultValue, newValue) {
var url = Utils.extractFirstUri(newValue)
if (url === defaultValue) {
return
}
var vcard = contactEdit._vcard
var soFarSoGood = url && (
defaultValue.length === 0
? vcard.addUrl(newValue)
: vcard.updateUrl(defaultValue, newValue)
)
function handleEmailChanged () {
var args = Array.prototype.slice.call(arguments)
args.push('addEmail', 'updateEmail')
handleValueChanged.apply(this, args)
}
urls.setInvalid(index, !soFarSoGood)
function handleUrlChanged () {
var args = Array.prototype.slice.call(arguments)
args.push('addUrl', 'updateUrl')
handleValueChanged.apply(this, args)
}
// -----------------------------------------------------------------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment