conf creation loading+error; fix info popup layout
move contact edition in contact page (switch to contact tab if creation requested)
fix contact creation + select new contact on creation
conference info list : creation signal (to finish when conference scheduler is updated, see comment)
fix crash if no vcard
fix calendar ui
+spacings
layout polish (! on string in meetinglist)
This commit is contained in:
Gaelle Braud 2024-04-23 09:23:00 +02:00
parent abba6cffaa
commit eb5b3b5141
48 changed files with 809 additions and 510 deletions

View file

@ -102,7 +102,7 @@ public:
void onLoggerInitialized(); void onLoggerInitialized();
QQuickWindow *getCallsWindow(QVariant callGui); QQuickWindow *getCallsWindow(QVariant callGui = QVariant());
void setCallsWindowProperty(const char *id, QVariant property); void setCallsWindowProperty(const char *id, QVariant property);
void closeCallsWindow(); void closeCallsWindow();

View file

@ -136,7 +136,15 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
mCallModelConnection->invokeToModel([this]() { mCallModel->stopRecording(); }); mCallModelConnection->invokeToModel([this]() { mCallModel->stopRecording(); });
}); });
mCallModelConnection->makeConnectToModel(&CallModel::recordingChanged, [this](bool recording) { mCallModelConnection->makeConnectToModel(&CallModel::recordingChanged, [this](bool recording) {
mCallModelConnection->invokeToCore([this, recording]() { setRecording(recording); }); mCallModelConnection->invokeToCore([this, recording]() {
setRecording(recording);
if (recording == false) {
Utils::showInformationPopup(tr("Enregistrement terminé"),
tr("L'appel a été enregistré dans le fichier : %1")
.arg(QString::fromStdString(mCallModel->getRecordFile())),
true, App::getInstance()->getCallsWindow());
}
});
}); });
mCallModelConnection->makeConnectToCore(&CallCore::lVerifyAuthenticationToken, [this](bool verified) { mCallModelConnection->makeConnectToCore(&CallCore::lVerifyAuthenticationToken, [this](bool verified) {
mCallModelConnection->invokeToModel( mCallModelConnection->invokeToModel(

View file

@ -194,33 +194,37 @@ void ConferenceInfoCore::setSelf(QSharedPointer<ConferenceInfoCore> me) {
&ConferenceInfoModel::schedulerStateChanged, [this](linphone::ConferenceScheduler::State state) { &ConferenceInfoModel::schedulerStateChanged, [this](linphone::ConferenceScheduler::State state) {
auto confInfoState = mConferenceInfoModel->getState(); auto confInfoState = mConferenceInfoModel->getState();
QString uri; QString uri;
if (state == linphone::ConferenceScheduler::State::Ready) if (state == linphone::ConferenceScheduler::State::Ready) {
uri = mConferenceInfoModel->getConferenceScheduler()->getUri(); uri = mConferenceInfoModel->getConferenceScheduler()->getUri();
}
mConfInfoModelConnection->invokeToCore([this, state = LinphoneEnums::fromLinphone(state), mConfInfoModelConnection->invokeToCore([this, state = LinphoneEnums::fromLinphone(state),
infoState = LinphoneEnums::fromLinphone(confInfoState), infoState = LinphoneEnums::fromLinphone(confInfoState),
uri] { uri] {
lDebug() << "scheduler state changed" << state;
setConferenceSchedulerState(state); setConferenceSchedulerState(state);
setConferenceInfoState(infoState); setConferenceInfoState(infoState);
if (state == LinphoneEnums::ConferenceSchedulerState::Ready) { if (state == LinphoneEnums::ConferenceSchedulerState::Ready) {
setUri(uri); setUri(uri);
mConfInfoModelConnection->invokeToModel([this, uri] {
CoreModel::getInstance()->conferenceInfoCreated(
mConferenceInfoModel->getConferenceInfo());
});
} }
setConferenceSchedulerState(state);
});
});
mConfInfoModelConnection->makeConnectToModel(
&ConferenceInfoModel::infoStateChanged, [this](linphone::ConferenceInfo::State state) {
auto uri = mConferenceInfoModel->getConferenceScheduler()->getUri();
mConfInfoModelConnection->invokeToCore([this, infoState = LinphoneEnums::fromLinphone(state), uri] {
setConferenceInfoState(infoState);
}); });
}); });
mConfInfoModelConnection->makeConnectToModel( mConfInfoModelConnection->makeConnectToModel(
&ConferenceInfoModel::invitationsSent, &ConferenceInfoModel::invitationsSent,
[this](const std::list<std::shared_ptr<linphone::Address>> &failedInvitations) { [this](const std::list<std::shared_ptr<linphone::Address>> &failedInvitations) {});
lDebug() << "invitations sent";
});
} else { // Create } else { // Create
mCoreModelConnection = QSharedPointer<SafeConnection<ConferenceInfoCore, CoreModel>>( mCoreModelConnection = QSharedPointer<SafeConnection<ConferenceInfoCore, CoreModel>>(
new SafeConnection<ConferenceInfoCore, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater); new SafeConnection<ConferenceInfoCore, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater);
mCoreModelConnection->makeConnectToModel(
&CoreModel::conferenceInfoReceived,
[this](const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) {
lDebug() << "CONF INFO RECEIVED ==================";
});
} }
} }
} }
@ -566,6 +570,11 @@ void ConferenceInfoCore::save() {
}); });
} else { } else {
mCoreModelConnection->invokeToModel([this, thisCopy]() { mCoreModelConnection->invokeToModel([this, thisCopy]() {
if (CoreModel::getInstance()->getCore()->getDefaultAccount()->getState() !=
linphone::RegistrationState::Ok) {
Utils::showInformationPopup(tr("Erreur"), tr("Votre compte est déconnecté"), false);
return;
}
auto linphoneConf = auto linphoneConf =
CoreModel::getInstance()->getCore()->findConferenceInformationFromUri(ToolModel::interpretUrl(mUri)); CoreModel::getInstance()->getCore()->findConferenceInformationFromUri(ToolModel::interpretUrl(mUri));

View file

@ -68,7 +68,17 @@ void ConferenceInfoList::setSelf(QSharedPointer<ConferenceInfoList> me) {
int currentDateIndex = sort(*items); int currentDateIndex = sort(*items);
add(*items); add(*items);
updateHaveCurrentDate(); updateHaveCurrentDate();
setCurrentDateIndex(mHaveCurrentDate ? currentDateIndex + 1 : currentDateIndex); if (mLastConfInfoInserted) {
int index = -1;
// TODO : uncomment when linphone conference scheduler updated
// and model returns the scheduler conferenceInfo uri
index = findConfInfoIndexByUri(mLastConfInfoInserted->getUri());
// int index2;
// get(mLastConfInfoInserted.get(), &index2);
if (index != -1) setCurrentDateIndex(index);
else setCurrentDateIndex(mHaveCurrentDate ? currentDateIndex + 1 : currentDateIndex);
mLastConfInfoInserted = nullptr;
} else setCurrentDateIndex(mHaveCurrentDate ? currentDateIndex + 1 : currentDateIndex);
delete items; delete items;
}); });
}); });
@ -76,10 +86,20 @@ void ConferenceInfoList::setSelf(QSharedPointer<ConferenceInfoList> me) {
mCoreModelConnection->makeConnectToModel(&CoreModel::defaultAccountChanged, &ConferenceInfoList::lUpdate); mCoreModelConnection->makeConnectToModel(&CoreModel::defaultAccountChanged, &ConferenceInfoList::lUpdate);
mCoreModelConnection->makeConnectToModel(&CoreModel::conferenceInfoReceived, &ConferenceInfoList::lUpdate); mCoreModelConnection->makeConnectToModel(&CoreModel::conferenceInfoReceived, &ConferenceInfoList::lUpdate);
mCoreModelConnection->makeConnectToModel(&CoreModel::conferenceStateChanged, [this] { mCoreModelConnection->makeConnectToModel(
lDebug() << "list: conf state changed"; &CoreModel::conferenceInfoCreated, [this](const std::shared_ptr<linphone::ConferenceInfo> &confInfo) {
lUpdate(); auto confInfoCore = ConferenceInfoCore::create(confInfo);
}); auto haveConf =
std::find_if(mList.begin(), mList.end(), [confInfoCore](const QSharedPointer<QObject> &item) {
auto isConfInfo = item.objectCast<ConferenceInfoCore>();
if (!isConfInfo) return false;
return isConfInfo->getUri() == confInfoCore->getUri();
});
if (haveConf == mList.end()) {
mLastConfInfoInserted = confInfoCore;
emit lUpdate();
}
});
mCoreModelConnection->makeConnectToModel( mCoreModelConnection->makeConnectToModel(
&CoreModel::callCreated, [this](const std::shared_ptr<linphone::Call> &call) { &CoreModel::callCreated, [this](const std::shared_ptr<linphone::Call> &call) {
lDebug() << "call created" << Utils::coreStringToAppString(call->getRemoteAddress()->asString()); lDebug() << "call created" << Utils::coreStringToAppString(call->getRemoteAddress()->asString());
@ -128,19 +148,13 @@ void ConferenceInfoList::setCurrentDateIndex(int index) {
} }
} }
QSharedPointer<ConferenceInfoCore> int ConferenceInfoList::findConfInfoIndexByUri(const QString &uri) {
ConferenceInfoList::get(std::shared_ptr<linphone::ConferenceInfo> conferenceInfo) const { auto items = getSharedList<ConferenceInfoCore>();
auto uri = Utils::coreStringToAppString(conferenceInfo->getUri()->asStringUriOnly()); for (int i = 0; i < items.size(); ++i) {
for (auto item : mList) { if (!items[i]) continue;
auto model = item.objectCast<ConferenceInfoCore>(); if (items[i]->getUri() == uri) return i;
if (model) {
auto confUri = model->getUri();
if (confUri == uri) {
return model;
}
}
} }
return nullptr; return -1;
} }
QSharedPointer<ConferenceInfoCore> QSharedPointer<ConferenceInfoCore>
@ -160,13 +174,6 @@ ConferenceInfoList::build(const std::shared_ptr<linphone::ConferenceInfo> &confe
} else return nullptr; } else return nullptr;
} }
void ConferenceInfoList::remove(const int &row) {
// List is modified asynchronously
// so no need to specify the begin/endRemoveRows
auto item = mList[row].objectCast<ConferenceInfoCore>();
if (item) emit item->lDeleteConferenceInfo();
}
QHash<int, QByteArray> ConferenceInfoList::roleNames() const { QHash<int, QByteArray> ConferenceInfoList::roleNames() const {
QHash<int, QByteArray> roles; QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$modelData"; roles[Qt::DisplayRole] = "$modelData";

View file

@ -46,10 +46,9 @@ public:
int getCurrentDateIndex() const; int getCurrentDateIndex() const;
void setCurrentDateIndex(int index); void setCurrentDateIndex(int index);
QSharedPointer<ConferenceInfoCore> get(std::shared_ptr<linphone::ConferenceInfo> conferenceInfo) const; int findConfInfoIndexByUri(const QString &uri);
QSharedPointer<ConferenceInfoCore> build(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo) const;
void remove(const int &row); QSharedPointer<ConferenceInfoCore> build(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo) const;
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
@ -64,6 +63,8 @@ signals:
private: private:
QSharedPointer<SafeConnection<ConferenceInfoList, CoreModel>> mCoreModelConnection; QSharedPointer<SafeConnection<ConferenceInfoList, CoreModel>> mCoreModelConnection;
std::shared_ptr<CoreModel> mCoreModel;
QSharedPointer<ConferenceInfoCore> mLastConfInfoInserted;
bool mHaveCurrentDate = false; bool mHaveCurrentDate = false;
int mCurrentDateIndex = -1; int mCurrentDateIndex = -1;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT

View file

@ -32,7 +32,6 @@ ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : SortFilterProxy(pare
invalidate(); invalidate();
updateCurrentDateIndex(); updateCurrentDateIndex();
}); });
connect(this, &ConferenceInfoProxy::lUpdate, mList.get(), &ConferenceInfoList::lUpdate);
connect(mList.get(), &ConferenceInfoList::haveCurrentDateChanged, [this] { connect(mList.get(), &ConferenceInfoList::haveCurrentDateChanged, [this] {
invalidate(); invalidate();
updateCurrentDateIndex(); updateCurrentDateIndex();
@ -77,10 +76,9 @@ bool ConferenceInfoProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sou
if (ciCore) { if (ciCore) {
if (!ciCore->getSubject().contains(mSearchText)) return false; if (!ciCore->getSubject().contains(mSearchText)) return false;
QDateTime currentDateTime = QDateTime::currentDateTimeUtc(); QDateTime currentDateTime = QDateTime::currentDateTimeUtc();
// TODO : use enums if (mFilterType == int(ConferenceInfoProxy::ConferenceInfoFiltering::None)) {
if (mFilterType == 0) {
return true; return true;
} else if (mFilterType == 1) { } else if (mFilterType == int(ConferenceInfoProxy::ConferenceInfoFiltering::Future)) {
auto res = ciCore->getEndDateTimeUtc() >= currentDateTime; auto res = ciCore->getEndDateTimeUtc() >= currentDateTime;
return res; return res;
} else return mFilterType == -1; } else return mFilterType == -1;
@ -88,4 +86,4 @@ bool ConferenceInfoProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sou
return !mList->haveCurrentDate(); return !mList->haveCurrentDate();
} }
return false; return false;
} }

View file

@ -33,30 +33,31 @@ class ConferenceInfoProxy : public SortFilterProxy, public AbstractObject {
Q_PROPERTY(bool haveCurrentDate READ haveCurrentDate NOTIFY haveCurrentDateChanged) Q_PROPERTY(bool haveCurrentDate READ haveCurrentDate NOTIFY haveCurrentDateChanged)
Q_PROPERTY(int currentDateIndex READ getCurrentDateIndex NOTIFY currentDateIndexChanged) Q_PROPERTY(int currentDateIndex READ getCurrentDateIndex NOTIFY currentDateIndexChanged)
public:
enum ConferenceInfoFiltering { None = 0, Future = 1 };
Q_ENUM(ConferenceInfoFiltering)
public: public:
ConferenceInfoProxy(QObject *parent = Q_NULLPTR); ConferenceInfoProxy(QObject *parent = Q_NULLPTR);
~ConferenceInfoProxy(); ~ConferenceInfoProxy();
QString getSearchText() const; QString getSearchText() const;
void setSearchText(const QString &search); void setSearchText(const QString &search);
bool haveCurrentDate() const; bool haveCurrentDate() const;
int getCurrentDateIndex() const; int getCurrentDateIndex() const;
void updateCurrentDateIndex(); void updateCurrentDateIndex();
protected: protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
// Do not use the sort feature. We cannot retrieve indexes with mapToSource because Qt return -1 for items that are not displayed. // Do not use the sort feature. We cannot retrieve indexes with mapToSource because Qt return -1 for items that are
// We need it to know where // not displayed. We need it to know where The workaround is to implement ourself the sort into the List.
// The workaround is to implement ourself the sort into the List. // bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
//bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
signals: signals:
void searchTextChanged(); void searchTextChanged();
void haveCurrentDateChanged(); void haveCurrentDateChanged();
void currentDateIndexChanged(); void currentDateIndexChanged();
void lUpdate();
private: private:
QString mSearchText; QString mSearchText;

View file

@ -54,10 +54,12 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact) : QObje
mPresenceTimestamp = mFriendModel->getPresenceTimestamp(); mPresenceTimestamp = mFriendModel->getPresenceTimestamp();
mPictureUri = Utils::coreStringToAppString(contact->getPhoto()); mPictureUri = Utils::coreStringToAppString(contact->getPhoto());
auto vcard = contact->getVcard(); auto vcard = contact->getVcard();
mOrganization = Utils::coreStringToAppString(vcard->getOrganization()); if (vcard) {
mJob = Utils::coreStringToAppString(vcard->getJobTitle()); mOrganization = Utils::coreStringToAppString(vcard->getOrganization());
mGivenName = Utils::coreStringToAppString(vcard->getGivenName()); mJob = Utils::coreStringToAppString(vcard->getJobTitle());
mFamilyName = Utils::coreStringToAppString(vcard->getFamilyName()); mGivenName = Utils::coreStringToAppString(vcard->getGivenName());
mFamilyName = Utils::coreStringToAppString(vcard->getFamilyName());
}
auto addresses = contact->getAddresses(); auto addresses = contact->getAddresses();
for (auto &address : addresses) { for (auto &address : addresses) {
mAddressList.append( mAddressList.append(
@ -451,8 +453,8 @@ void FriendCore::remove() {
if (mFriendModel) { // Update if (mFriendModel) { // Update
mFriendModelConnection->invokeToModel([this]() { mFriendModelConnection->invokeToModel([this]() {
auto contact = mFriendModel->getFriend(); auto contact = mFriendModel->getFriend();
// emit CoreModel::getInstance()->friendRemoved(contact);
contact->remove(); contact->remove();
emit CoreModel::getInstance()->friendRemoved();
mFriendModelConnection->invokeToCore([this]() { removed(this); }); mFriendModelConnection->invokeToCore([this]() { removed(this); });
}); });
} }
@ -506,22 +508,24 @@ void FriendCore::save() { // Save Values to model
auto contact = core->createFriend(); auto contact = core->createFriend();
auto friendModel = Utils::makeQObject_ptr<FriendModel>(contact); auto friendModel = Utils::makeQObject_ptr<FriendModel>(contact);
friendModel->setSelf(friendModel); friendModel->setSelf(friendModel);
mCoreModelConnection->invokeToCore([this, thisCopy, friendModel] { mCoreModelConnection->invokeToCore([this, thisCopy, friendModel, contact] {
mFriendModel = friendModel; mFriendModel = friendModel;
mCoreModelConnection->invokeToModel([this, thisCopy] { mCoreModelConnection->invokeToModel([this, thisCopy, contact] {
auto core = CoreModel::getInstance()->getCore();
thisCopy->writeIntoModel(mFriendModel); thisCopy->writeIntoModel(mFriendModel);
thisCopy->deleteLater(); thisCopy->deleteLater();
bool created =
(core->getDefaultFriendList()->addFriend(contact) == linphone::FriendList::Status::OK);
if (created) {
core->getDefaultFriendList()->updateSubscriptions();
emit CoreModel::getInstance()->friendCreated(contact);
}
mCoreModelConnection->invokeToCore([this, created]() {
if (created) setSelf(mCoreModelConnection->mCore);
setIsSaved(created);
});
}); });
}); });
bool created = (core->getDefaultFriendList()->addFriend(contact) == linphone::FriendList::Status::OK);
if (created) {
core->getDefaultFriendList()->updateSubscriptions();
emit CoreModel::getInstance()->friendAdded();
}
mCoreModelConnection->invokeToCore([this, created]() {
if (created) setSelf(mCoreModelConnection->mCore);
setIsSaved(created);
});
} }
}); });
} }

View file

@ -72,7 +72,6 @@ void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
&MagicSearchModel::aggregationFlagChanged, [this](LinphoneEnums::MagicSearchAggregation flag) { &MagicSearchModel::aggregationFlagChanged, [this](LinphoneEnums::MagicSearchAggregation flag) {
mModelConnection->invokeToCore([this, flag]() { setAggregationFlag(flag); }); mModelConnection->invokeToCore([this, flag]() { setAggregationFlag(flag); });
}); });
mModelConnection->makeConnectToModel( mModelConnection->makeConnectToModel(
&MagicSearchModel::searchResultsReceived, &MagicSearchModel::searchResultsReceived,
[this](const std::list<std::shared_ptr<linphone::SearchResult>> &results) { [this](const std::list<std::shared_ptr<linphone::SearchResult>> &results) {
@ -83,12 +82,14 @@ void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
contact = FriendCore::create(it->getFriend()); contact = FriendCore::create(it->getFriend());
contacts->append(contact); contacts->append(contact);
} else if (auto address = it->getAddress()) { } else if (auto address = it->getAddress()) {
contact = FriendCore::create(nullptr); auto linphoneFriend = CoreModel::getInstance()->getCore()->createFriend();
contact = FriendCore::create(linphoneFriend);
contact->setGivenName(Utils::coreStringToAppString(address->asStringUriOnly())); contact->setGivenName(Utils::coreStringToAppString(address->asStringUriOnly()));
contact->appendAddress(Utils::coreStringToAppString(address->asStringUriOnly())); contact->appendAddress(Utils::coreStringToAppString(address->asStringUriOnly()));
contacts->append(contact); contacts->append(contact);
} else if (!it->getPhoneNumber().empty()) { } else if (!it->getPhoneNumber().empty()) {
contact = FriendCore::create(it->getFriend()); auto linphoneFriend = CoreModel::getInstance()->getCore()->createFriend();
contact = FriendCore::create(linphoneFriend);
contact->setGivenName(Utils::coreStringToAppString(it->getPhoneNumber())); contact->setGivenName(Utils::coreStringToAppString(it->getPhoneNumber()));
contact->appendPhoneNumber(tr("Phone"), Utils::coreStringToAppString(it->getPhoneNumber())); contact->appendPhoneNumber(tr("Phone"), Utils::coreStringToAppString(it->getPhoneNumber()));
contacts->append(contact); contacts->append(contact);
@ -99,6 +100,26 @@ void MagicSearchList::setSelf(QSharedPointer<MagicSearchList> me) {
delete contacts; delete contacts;
}); });
}); });
mCoreModelConnection = QSharedPointer<SafeConnection<MagicSearchList, CoreModel>>(
new SafeConnection<MagicSearchList, CoreModel>(me, CoreModel::getInstance()), &QObject::deleteLater);
mCoreModelConnection->makeConnectToModel(
&CoreModel::friendCreated, [this](const std::shared_ptr<linphone::Friend> &f) {
auto friendCore = FriendCore::create(f);
auto haveContact =
std::find_if(mList.begin(), mList.end(), [friendCore](const QSharedPointer<QObject> &item) {
return item.objectCast<FriendCore>()->getDefaultAddress() == friendCore->getDefaultAddress();
});
if (haveContact == mList.end()) {
connect(friendCore.get(), &FriendCore::removed, this, qOverload<QObject *>(&MagicSearchList::remove));
add(friendCore);
int index = -1;
get(friendCore.get(), &index);
if (index != -1) {
emit friendCreated(index);
}
}
});
} }
void MagicSearchList::setResults(const QList<QSharedPointer<FriendCore>> &contacts) { void MagicSearchList::setResults(const QList<QSharedPointer<FriendCore>> &contacts) {
@ -109,6 +130,9 @@ void MagicSearchList::setResults(const QList<QSharedPointer<FriendCore>> &contac
add(contacts); add(contacts);
} }
void MagicSearchList::addResult(const QSharedPointer<FriendCore> &contact) {
}
void MagicSearchList::setSearch(const QString &search) { void MagicSearchList::setSearch(const QString &search) {
if (!search.isEmpty()) { if (!search.isEmpty()) {
lSearch(search); lSearch(search);

View file

@ -42,6 +42,7 @@ public:
void setSelf(QSharedPointer<MagicSearchList> me); void setSelf(QSharedPointer<MagicSearchList> me);
void setSearch(const QString &search); void setSearch(const QString &search);
void setResults(const QList<QSharedPointer<FriendCore>> &contacts); void setResults(const QList<QSharedPointer<FriendCore>> &contacts);
void addResult(const QSharedPointer<FriendCore> &contact);
int getSourceFlags() const; int getSourceFlags() const;
void setSourceFlags(int flags); void setSourceFlags(int flags);
@ -59,6 +60,8 @@ signals:
void sourceFlagsChanged(int sourceFlags); void sourceFlagsChanged(int sourceFlags);
void aggregationFlagChanged(LinphoneEnums::MagicSearchAggregation flag); void aggregationFlagChanged(LinphoneEnums::MagicSearchAggregation flag);
void friendCreated(int index);
private: private:
int mSourceFlags; int mSourceFlags;
LinphoneEnums::MagicSearchAggregation mAggregationFlag; LinphoneEnums::MagicSearchAggregation mAggregationFlag;

View file

@ -20,14 +20,17 @@
#include "MagicSearchProxy.hpp" #include "MagicSearchProxy.hpp"
#include "MagicSearchList.hpp" #include "MagicSearchList.hpp"
#include "core/friend/FriendGui.hpp"
MagicSearchProxy::MagicSearchProxy(QObject *parent) : SortFilterProxy(parent) { MagicSearchProxy::MagicSearchProxy(QObject *parent) : SortFilterProxy(parent) {
mList = MagicSearchList::create(); mList = MagicSearchList::create();
connect(mList.get(), &MagicSearchList::sourceFlagsChanged, this, &MagicSearchProxy::sourceFlagsChanged); connect(mList.get(), &MagicSearchList::sourceFlagsChanged, this, &MagicSearchProxy::sourceFlagsChanged);
connect(mList.get(), &MagicSearchList::aggregationFlagChanged, this, &MagicSearchProxy::aggregationFlagChanged); connect(mList.get(), &MagicSearchList::aggregationFlagChanged, this, &MagicSearchProxy::aggregationFlagChanged);
connect(mList.get(), &MagicSearchList::friendCreated, this, [this](int index) {
auto proxyIndex = mapFromSource(sourceModel()->index(index, 0));
emit friendCreated(proxyIndex.row());
});
setSourceModel(mList.get()); setSourceModel(mList.get());
connect(CoreModel::getInstance().get(), &CoreModel::friendRemoved, this,
[this] { emit mList->lSearch(mSearchText); });
connect(this, &MagicSearchProxy::forceUpdate, [this] { emit mList->lSearch(mSearchText); }); connect(this, &MagicSearchProxy::forceUpdate, [this] { emit mList->lSearch(mSearchText); });
sort(0); sort(0);
} }
@ -58,4 +61,19 @@ LinphoneEnums::MagicSearchAggregation MagicSearchProxy::getAggregationFlag() con
void MagicSearchProxy::setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag) { void MagicSearchProxy::setAggregationFlag(LinphoneEnums::MagicSearchAggregation flag) {
qobject_cast<MagicSearchList *>(sourceModel())->lSetAggregationFlag(flag); qobject_cast<MagicSearchList *>(sourceModel())->lSetAggregationFlag(flag);
}
bool MagicSearchProxy::lessThan(const QModelIndex &left, const QModelIndex &right) const {
auto l = sourceModel()->data(left);
auto r = sourceModel()->data(right);
auto lIsFriend = l.value<FriendGui *>();
auto rIsFriend = r.value<FriendGui *>();
if (lIsFriend && rIsFriend) {
auto lName = lIsFriend->getCore()->getDisplayName().toLower();
auto rName = rIsFriend->getCore()->getDisplayName().toLower();
return lName < rName;
}
return true;
} }

View file

@ -55,10 +55,12 @@ signals:
void sourceFlagsChanged(int sourceFlags); void sourceFlagsChanged(int sourceFlags);
void aggregationFlagChanged(LinphoneEnums::MagicSearchAggregation aggregationFlag); void aggregationFlagChanged(LinphoneEnums::MagicSearchAggregation aggregationFlag);
void forceUpdate(); void forceUpdate();
void friendCreated(int index);
protected: protected:
QString mSearchText; QString mSearchText;
QSharedPointer<MagicSearchList> mList; QSharedPointer<MagicSearchList> mList;
virtual bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
}; };
#endif #endif

View file

@ -0,0 +1,32 @@
<svg width="28" height="26" viewBox="0 0 28 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_3638_14815)" filter="url(#filter0_d_3638_14815)">
<g filter="url(#filter1_d_3638_14815)">
<path d="M21.125 9.25C21.125 9.4725 21.059 9.69001 20.9354 9.87502C20.8118 10.06 20.6361 10.2042 20.4305 10.2894C20.225 10.3745 19.9988 10.3968 19.7805 10.3534C19.5623 10.31 19.3618 10.2028 19.2045 10.0455C19.0472 9.88816 18.94 9.68771 18.8966 9.46948C18.8532 9.25125 18.8755 9.02505 18.9606 8.81948C19.0458 8.61391 19.19 8.43821 19.375 8.3146C19.56 8.19098 19.7775 8.125 20 8.125C20.2984 8.125 20.5845 8.24353 20.7955 8.4545C21.0065 8.66548 21.125 8.95163 21.125 9.25ZM20 15.625C19.7775 15.625 19.56 15.691 19.375 15.8146C19.19 15.9382 19.0458 16.1139 18.9606 16.3195C18.8755 16.525 18.8532 16.7512 18.8966 16.9695C18.94 17.1877 19.0472 17.3882 19.2045 17.5455C19.3618 17.7028 19.5623 17.81 19.7805 17.8534C19.9988 17.8968 20.225 17.8745 20.4305 17.7894C20.6361 17.7042 20.8118 17.56 20.9354 17.375C21.059 17.19 21.125 16.9725 21.125 16.75C21.125 16.4516 21.0065 16.1655 20.7955 15.9545C20.5845 15.7435 20.2984 15.625 20 15.625ZM11 10.75C10.7033 10.75 10.4133 10.838 10.1666 11.0028C9.91997 11.1676 9.72771 11.4019 9.61418 11.676C9.50065 11.9501 9.47094 12.2517 9.52882 12.5426C9.5867 12.8336 9.72956 13.1009 9.93934 13.3107C10.1491 13.5204 10.4164 13.6633 10.7074 13.7212C10.9983 13.7791 11.2999 13.7494 11.574 13.6358C11.8481 13.5223 12.0824 13.33 12.2472 13.0834C12.412 12.8367 12.5 12.5467 12.5 12.25C12.5 11.8522 12.342 11.4706 12.0607 11.1893C11.7794 10.908 11.3978 10.75 11 10.75ZM23.75 6.25V19.75C23.75 20.1478 23.592 20.5294 23.3107 20.8107C23.0294 21.092 22.6478 21.25 22.25 21.25H5.75C5.35218 21.25 4.97064 21.092 4.68934 20.8107C4.40804 20.5294 4.25 20.1478 4.25 19.75V6.25C4.25 5.85218 4.40804 5.47064 4.68934 5.18934C4.97064 4.90804 5.35218 4.75 5.75 4.75H22.25C22.6478 4.75 23.0294 4.90804 23.3107 5.18934C23.592 5.47064 23.75 5.85218 23.75 6.25ZM17.75 12.25H22.25V6.25H17.75V12.25ZM14.7266 16.5625C14.4839 15.6563 13.9084 14.875 13.115 14.3744C13.5363 13.9555 13.8238 13.421 13.941 12.8386C14.0582 12.2562 13.9999 11.652 13.7733 11.1028C13.5468 10.5536 13.1623 10.084 12.6686 9.75358C12.1748 9.42315 11.5941 9.24675 11 9.24675C10.4059 9.24675 9.82517 9.42315 9.33143 9.75358C8.8377 10.084 8.45319 10.5536 8.22666 11.1028C8.00012 11.652 7.94175 12.2562 8.05896 12.8386C8.17616 13.421 8.46366 13.9555 8.885 14.3744C8.09211 14.8755 7.51681 15.6566 7.27344 16.5625C7.22371 16.7552 7.25257 16.9598 7.35366 17.1312C7.45475 17.3026 7.6198 17.4268 7.8125 17.4766C8.0052 17.5263 8.20975 17.4974 8.38118 17.3963C8.55259 17.2952 8.67683 17.1302 8.72656 16.9375C8.97406 15.9766 9.95094 15.25 11 15.25C12.0491 15.25 13.0269 15.9747 13.2734 16.9375C13.3232 17.1302 13.4474 17.2952 13.6188 17.3963C13.7902 17.4974 13.9948 17.5263 14.1875 17.4766C14.3802 17.4268 14.5452 17.3026 14.6463 17.1312C14.7474 16.9598 14.7763 16.7552 14.7266 16.5625ZM22.25 19.75V13.75H17.75V19.75H22.25Z" fill="white"/>
</g>
</g>
<defs>
<filter id="filter0_d_3638_14815" x="-2" y="-3" width="32" height="32" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3638_14815"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3638_14815" result="shape"/>
</filter>
<filter id="filter1_d_3638_14815" x="0.25" y="0.75" width="27.5" height="24.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3638_14815"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3638_14815" result="shape"/>
</filter>
<clipPath id="clip0_3638_14815">
<rect width="24" height="24" fill="white" transform="translate(2 1)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,80H168V56h48ZM40,56H152V200H40ZM216,200H168V136h48v64ZM180,88a12,12,0,1,1,12,12A12,12,0,0,1,180,88Zm24,80a12,12,0,1,1-12-12A12,12,0,0,1,204,168Zm-68.25-2a39.76,39.76,0,0,0-17.19-23.34,32,32,0,1,0-45.12,0A39.84,39.84,0,0,0,56.25,166a8,8,0,0,0,15.5,4c2.64-10.25,13.06-18,24.25-18s21.62,7.73,24.25,18a8,8,0,1,0,15.5-4ZM80,120a16,16,0,1,1,16,16A16,16,0,0,1,80,120Z"></path></svg>

After

Width:  |  Height:  |  Size: 582 B

View file

@ -185,7 +185,6 @@ void CallModel::stopRecording() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mMonitor->stopRecording(); mMonitor->stopRecording();
emit recordingChanged(mMonitor->getParams()->isRecording()); emit recordingChanged(mMonitor->getParams()->isRecording());
// TODO : display notification
} }
void CallModel::setRecordFile(const std::string &path) { void CallModel::setRecordFile(const std::string &path) {

View file

@ -45,6 +45,10 @@ void ConferenceInfoModel::createConferenceScheduler() {
mustBeInLinphoneThread(getClassName() + "::createConferenceScheduler()"); mustBeInLinphoneThread(getClassName() + "::createConferenceScheduler()");
} }
std::shared_ptr<linphone::ConferenceInfo> ConferenceInfoModel::getConferenceInfo() const {
return mConferenceInfo;
}
std::shared_ptr<ConferenceSchedulerModel> ConferenceInfoModel::getConferenceScheduler() const { std::shared_ptr<ConferenceSchedulerModel> ConferenceInfoModel::getConferenceScheduler() const {
return mConferenceSchedulerModel; return mConferenceSchedulerModel;
} }
@ -106,7 +110,9 @@ QString ConferenceInfoModel::getOrganizerName() const {
} }
QString ConferenceInfoModel::getOrganizerAddress() const { QString ConferenceInfoModel::getOrganizerAddress() const {
return Utils::coreStringToAppString(mConferenceInfo->getOrganizer()->asStringUriOnly()); if (auto organizer = mConferenceInfo->getOrganizer())
return Utils::coreStringToAppString(organizer->asStringUriOnly());
return QString();
} }
QString ConferenceInfoModel::getDescription() const { QString ConferenceInfoModel::getDescription() const {
@ -118,7 +124,7 @@ QString ConferenceInfoModel::getUri() const {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
if (auto uriAddr = mConferenceInfo->getUri()) { if (auto uriAddr = mConferenceInfo->getUri()) {
return Utils::coreStringToAppString(uriAddr->asString()); return Utils::coreStringToAppString(uriAddr->asString());
} else return QString(); } else return mConferenceSchedulerModel->getUri();
} }
std::list<std::shared_ptr<linphone::ParticipantInfo>> ConferenceInfoModel::getParticipantInfos() const { std::list<std::shared_ptr<linphone::ParticipantInfo>> ConferenceInfoModel::getParticipantInfos() const {

View file

@ -36,6 +36,8 @@ public:
void createConferenceScheduler(); void createConferenceScheduler();
std::shared_ptr<linphone::ConferenceInfo> getConferenceInfo() const;
std::shared_ptr<ConferenceSchedulerModel> getConferenceScheduler() const; std::shared_ptr<ConferenceSchedulerModel> getConferenceScheduler() const;
void setConferenceScheduler(const std::shared_ptr<ConferenceSchedulerModel> &model); void setConferenceScheduler(const std::shared_ptr<ConferenceSchedulerModel> &model);
QDateTime getDateTime() const; QDateTime getDateTime() const;

View file

@ -86,8 +86,6 @@ void ConferenceModel::startRecording() {
void ConferenceModel::stopRecording() { void ConferenceModel::stopRecording() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mMonitor->stopRecording(); mMonitor->stopRecording();
// emit recordingChanged(mMonitor->getParams()->isRecording());
// TODO : display notification
} }
void ConferenceModel::setRecordFile(const std::string &path) { void ConferenceModel::setRecordFile(const std::string &path) {

View file

@ -48,6 +48,10 @@ QString ConferenceSchedulerModel::getUri() {
} else return QString(); } else return QString();
} }
linphone::ConferenceScheduler::State ConferenceSchedulerModel::getState() const {
return mState;
}
void ConferenceSchedulerModel::setInfo(const std::shared_ptr<linphone::ConferenceInfo> &confInfo) { void ConferenceSchedulerModel::setInfo(const std::shared_ptr<linphone::ConferenceInfo> &confInfo) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mMonitor->setInfo(confInfo); mMonitor->setInfo(confInfo);
@ -60,6 +64,7 @@ void ConferenceSchedulerModel::cancelConference(const std::shared_ptr<linphone::
void ConferenceSchedulerModel::onStateChanged(const std::shared_ptr<linphone::ConferenceScheduler> &conferenceScheduler, void ConferenceSchedulerModel::onStateChanged(const std::shared_ptr<linphone::ConferenceScheduler> &conferenceScheduler,
linphone::ConferenceScheduler::State state) { linphone::ConferenceScheduler::State state) {
mState = state;
emit stateChanged(state); emit stateChanged(state);
} }

View file

@ -39,6 +39,7 @@ public:
~ConferenceSchedulerModel(); ~ConferenceSchedulerModel();
QString getUri(); QString getUri();
linphone::ConferenceScheduler::State getState() const;
void setInfo(const std::shared_ptr<linphone::ConferenceInfo> &confInfo); void setInfo(const std::shared_ptr<linphone::ConferenceInfo> &confInfo);
void cancelConference(const std::shared_ptr<linphone::ConferenceInfo> &confInfo); void cancelConference(const std::shared_ptr<linphone::ConferenceInfo> &confInfo);
@ -48,6 +49,7 @@ signals:
private: private:
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
linphone::ConferenceScheduler::State mState;
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
// LINPHONE // LINPHONE

View file

@ -56,8 +56,9 @@ public:
signals: signals:
void loggerInitialized(); void loggerInitialized();
void friendAdded(); void friendCreated(const std::shared_ptr<linphone::Friend> &f);
void friendRemoved(); void friendRemoved(const std::shared_ptr<linphone::Friend> &f);
void conferenceInfoCreated(const std::shared_ptr<linphone::ConferenceInfo> &confInfo);
void unreadNotificationsChanged(); void unreadNotificationsChanged();
private: private:

View file

@ -150,70 +150,90 @@ void FriendModel::setName(const QString &name) {
QString FriendModel::getGivenName() const { QString FriendModel::getGivenName() const {
auto vcard = mMonitor->getVcard(); auto vcard = mMonitor->getVcard();
bool created = false;
if (!vcard) { if (!vcard) {
mMonitor->createVcard(mMonitor->getName()); created = mMonitor->createVcard(mMonitor->getName());
} }
return Utils::coreStringToAppString(mMonitor->getVcard()->getGivenName()); if (mMonitor->getVcard()) return Utils::coreStringToAppString(mMonitor->getVcard()->getGivenName());
else return QString();
} }
void FriendModel::setGivenName(const QString &name) { void FriendModel::setGivenName(const QString &name) {
auto vcard = mMonitor->getVcard(); auto vcard = mMonitor->getVcard();
bool created = false;
if (!vcard) { if (!vcard) {
mMonitor->createVcard(mMonitor->getName()); created = mMonitor->createVcard(mMonitor->getName());
}
if (mMonitor->getVcard()) {
mMonitor->getVcard()->setGivenName(Utils::appStringToCoreString(name));
emit givenNameChanged(name);
} }
mMonitor->getVcard()->setGivenName(Utils::appStringToCoreString(name));
emit givenNameChanged(name);
} }
QString FriendModel::getFamilyName() const { QString FriendModel::getFamilyName() const {
auto vcard = mMonitor->getVcard(); auto vcard = mMonitor->getVcard();
bool created = false;
if (!vcard) { if (!vcard) {
mMonitor->createVcard(mMonitor->getName()); created = mMonitor->createVcard(mMonitor->getName());
} }
return Utils::coreStringToAppString(mMonitor->getVcard()->getFamilyName()); if (mMonitor->getVcard()) return Utils::coreStringToAppString(mMonitor->getVcard()->getFamilyName());
else return QString();
} }
void FriendModel::setFamilyName(const QString &name) { void FriendModel::setFamilyName(const QString &name) {
auto vcard = mMonitor->getVcard(); auto vcard = mMonitor->getVcard();
bool created = false;
if (!vcard) { if (!vcard) {
mMonitor->createVcard(mMonitor->getName()); created = mMonitor->createVcard(mMonitor->getName());
}
if (mMonitor->getVcard()) {
mMonitor->getVcard()->setFamilyName(Utils::appStringToCoreString(name));
emit familyNameChanged(name);
} }
mMonitor->getVcard()->setFamilyName(Utils::appStringToCoreString(name));
emit familyNameChanged(name);
} }
QString FriendModel::getOrganization() const { QString FriendModel::getOrganization() const {
auto vcard = mMonitor->getVcard(); auto vcard = mMonitor->getVcard();
bool created = false;
if (!vcard) { if (!vcard) {
mMonitor->createVcard(mMonitor->getName()); created = mMonitor->createVcard(mMonitor->getName());
} }
return Utils::coreStringToAppString(mMonitor->getVcard()->getOrganization()); if (mMonitor->getVcard()) return Utils::coreStringToAppString(mMonitor->getVcard()->getOrganization());
else return QString();
} }
void FriendModel::setOrganization(const QString &orga) { void FriendModel::setOrganization(const QString &orga) {
auto vcard = mMonitor->getVcard(); auto vcard = mMonitor->getVcard();
bool created = false;
if (!vcard) { if (!vcard) {
mMonitor->createVcard(mMonitor->getName()); created = mMonitor->createVcard(mMonitor->getName());
}
if (mMonitor->getVcard()) {
mMonitor->getVcard()->setOrganization(Utils::appStringToCoreString(orga));
emit organizationChanged(orga);
} }
mMonitor->getVcard()->setOrganization(Utils::appStringToCoreString(orga));
emit organizationChanged(orga);
} }
QString FriendModel::getJob() const { QString FriendModel::getJob() const {
auto vcard = mMonitor->getVcard(); auto vcard = mMonitor->getVcard();
bool created = false;
if (!vcard) { if (!vcard) {
mMonitor->createVcard(mMonitor->getName()); created = mMonitor->createVcard(mMonitor->getName());
} }
return Utils::coreStringToAppString(mMonitor->getVcard()->getJobTitle()); if (mMonitor->getVcard()) return Utils::coreStringToAppString(mMonitor->getVcard()->getJobTitle());
else return QString();
} }
void FriendModel::setJob(const QString &job) { void FriendModel::setJob(const QString &job) {
auto vcard = mMonitor->getVcard(); auto vcard = mMonitor->getVcard();
bool created = false;
if (!vcard) { if (!vcard) {
mMonitor->createVcard(mMonitor->getName()); created = mMonitor->createVcard(mMonitor->getName());
}
if (mMonitor->getVcard()) {
mMonitor->getVcard()->setJobTitle(Utils::appStringToCoreString(job));
emit jobChanged(job);
} }
mMonitor->getVcard()->setJobTitle(Utils::appStringToCoreString(job));
emit jobChanged(job);
} }
bool FriendModel::getStarred() const { bool FriendModel::getStarred() const {
@ -231,10 +251,12 @@ void FriendModel::onPresenceReceived(const std::shared_ptr<linphone::Friend> &co
QString FriendModel::getPictureUri() const { QString FriendModel::getPictureUri() const {
auto vcard = mMonitor->getVcard(); auto vcard = mMonitor->getVcard();
bool created = false;
if (!vcard) { if (!vcard) {
mMonitor->createVcard(mMonitor->getName()); created = mMonitor->createVcard(mMonitor->getName());
} }
return Utils::coreStringToAppString(mMonitor->getVcard()->getPhoto()); if (mMonitor->getVcard()) return Utils::coreStringToAppString(mMonitor->getVcard()->getPhoto());
else return QString();
} }
void FriendModel::setPictureUri(const QString &uri) { void FriendModel::setPictureUri(const QString &uri) {

View file

@ -30,11 +30,6 @@ DEFINE_ABSTRACT_OBJECT(MagicSearchModel)
MagicSearchModel::MagicSearchModel(const std::shared_ptr<linphone::MagicSearch> &data, QObject *parent) MagicSearchModel::MagicSearchModel(const std::shared_ptr<linphone::MagicSearch> &data, QObject *parent)
: ::Listener<linphone::MagicSearch, linphone::MagicSearchListener>(data, parent) { : ::Listener<linphone::MagicSearch, linphone::MagicSearchListener>(data, parent) {
mustBeInLinphoneThread(getClassName()); mustBeInLinphoneThread(getClassName());
// Removed is managed by FriendCore that allow to remove result automatically.
// No need to restart a new search in this case
connect(CoreModel::getInstance().get(), &CoreModel::friendAdded, this, [this]() {
if (!mLastSearch.isEmpty()) search(mLastSearch);
});
} }
MagicSearchModel::~MagicSearchModel() { MagicSearchModel::~MagicSearchModel() {

View file

@ -187,9 +187,9 @@ linphone::ConferenceInfo::State toLinphone(const LinphoneEnums::ConferenceInfoSt
LinphoneEnums::ConferenceInfoState fromLinphone(const linphone::ConferenceInfo::State &state); LinphoneEnums::ConferenceInfoState fromLinphone(const linphone::ConferenceInfo::State &state);
enum class ConferenceSchedulerState { enum class ConferenceSchedulerState {
AllocationPending = int(linphone::ConferenceScheduler::State::AllocationPending),
Error = int(linphone::ConferenceScheduler::State::Error),
Idle = int(linphone::ConferenceScheduler::State::Idle), Idle = int(linphone::ConferenceScheduler::State::Idle),
Error = int(linphone::ConferenceScheduler::State::Error),
AllocationPending = int(linphone::ConferenceScheduler::State::AllocationPending),
Ready = int(linphone::ConferenceScheduler::State::Ready), Ready = int(linphone::ConferenceScheduler::State::Ready),
Updating = int(linphone::ConferenceScheduler::State::Updating) Updating = int(linphone::ConferenceScheduler::State::Updating)
}; };

View file

@ -111,6 +111,9 @@ void Utils::createCall(const QString &sipAddress,
// TODO : change conf info only from qml // TODO : change conf info only from qml
// (bug si on est déjà en appel et qu'on lance une conf) // (bug si on est déjà en appel et qu'on lance une conf)
// demander à jonhatan pour le design : quand on est déjà en appel
// et qu'on join une conf on retourne donc sur la waiting room
// Comment on annule ? Si on ferme la fenêtre ça va finir l'appel en cours
void Utils::setupConference(ConferenceInfoGui *confGui) { void Utils::setupConference(ConferenceInfoGui *confGui) {
if (!confGui) return; if (!confGui) return;
auto window = App::getInstance()->getCallsWindow(QVariant()); auto window = App::getInstance()->getCallsWindow(QVariant());
@ -1124,6 +1127,10 @@ QString Utils::toDateMonthString(const QDateTime &date) {
return QLocale().toString(date, "MMMM"); return QLocale().toString(date, "MMMM");
} }
QString Utils::toDateMonthAndYearString(const QDateTime &date) {
return QLocale().toString(date, "MMMM yyyy");
}
bool Utils::isCurrentDay(QDateTime date) { bool Utils::isCurrentDay(QDateTime date) {
auto dateDayNum = date.date().day(); auto dateDayNum = date.date().day();
auto currentDate = QDateTime::currentDateTime(); auto currentDate = QDateTime::currentDateTime();
@ -1152,6 +1159,10 @@ bool Utils::datesAreEqual(const QDate &a, const QDate &b) {
return a.month() == b.month() && a.year() == b.year() && a.day() == b.day(); return a.month() == b.month() && a.year() == b.year() && a.day() == b.day();
} }
bool Utils::dateisInMonth(const QDate &a, int month, int year) {
return a.month() == month && a.year() == year;
}
QDateTime Utils::createDateTime(const QDate &date, int hour, int min) { QDateTime Utils::createDateTime(const QDate &date, int hour, int min) {
QTime time(hour, min); QTime time(hour, min);
return QDateTime(date, time); return QDateTime(date, time);
@ -1177,6 +1188,11 @@ QDateTime Utils::addSecs(QDateTime date, int secs) {
return date; return date;
} }
QDateTime Utils::addYears(QDateTime date, int years) {
date = date.addYears(years);
return date;
}
int Utils::getYear(const QDate &date) { int Utils::getYear(const QDate &date) {
return date.year(); return date.year();
} }

View file

@ -87,17 +87,20 @@ public:
Q_INVOKABLE static QString toDateHourString(const QDateTime &date); Q_INVOKABLE static QString toDateHourString(const QDateTime &date);
Q_INVOKABLE static QString toDateDayNameString(const QDateTime &date); Q_INVOKABLE static QString toDateDayNameString(const QDateTime &date);
Q_INVOKABLE static QString toDateMonthString(const QDateTime &date); Q_INVOKABLE static QString toDateMonthString(const QDateTime &date);
Q_INVOKABLE static QString toDateMonthAndYearString(const QDateTime &date);
Q_INVOKABLE static bool isCurrentDay(QDateTime date); Q_INVOKABLE static bool isCurrentDay(QDateTime date);
Q_INVOKABLE static bool isCurrentDay(QDate date); Q_INVOKABLE static bool isCurrentDay(QDate date);
Q_INVOKABLE static bool isCurrentMonth(QDate date); Q_INVOKABLE static bool isCurrentMonth(QDate date);
Q_INVOKABLE static bool isBeforeToday(QDate date); Q_INVOKABLE static bool isBeforeToday(QDate date);
Q_INVOKABLE static bool datesAreEqual(const QDate &a, const QDate &b); Q_INVOKABLE static bool datesAreEqual(const QDate &a, const QDate &b);
Q_INVOKABLE static bool dateisInMonth(const QDate &a, int month, int year);
Q_INVOKABLE static QDateTime createDateTime(const QDate &date, int hour, int min); Q_INVOKABLE static QDateTime createDateTime(const QDate &date, int hour, int min);
Q_INVOKABLE static QDateTime getCurrentDateTime(); Q_INVOKABLE static QDateTime getCurrentDateTime();
Q_INVOKABLE static QDateTime getCurrentDateTimeUtc(); Q_INVOKABLE static QDateTime getCurrentDateTimeUtc();
Q_INVOKABLE static int getYear(const QDate &date); Q_INVOKABLE static int getYear(const QDate &date);
Q_INVOKABLE static int secsTo(const QString &start, const QString &end); Q_INVOKABLE static int secsTo(const QString &start, const QString &end);
Q_INVOKABLE static QDateTime addSecs(QDateTime date, int secs); Q_INVOKABLE static QDateTime addSecs(QDateTime date, int secs);
Q_INVOKABLE static QDateTime addYears(QDateTime date, int years);
Q_INVOKABLE static QString generateLinphoneSipAddress(const QString &uri); Q_INVOKABLE static QString generateLinphoneSipAddress(const QString &uri);
Q_INVOKABLE static QString findAvatarByAddress(const QString &address); Q_INVOKABLE static QString findAvatarByAddress(const QString &address);
static QString generateSavedFilename(const QString &from, const QString &to); static QString generateSavedFilename(const QString &from, const QString &to);

View file

@ -275,7 +275,6 @@ Window {
Layout.preferredWidth: 30 * DefaultStyle.dp Layout.preferredWidth: 30 * DefaultStyle.dp
Layout.preferredHeight: 30 * DefaultStyle.dp Layout.preferredHeight: 30 * DefaultStyle.dp
// TODO : change with broadcast or meeting icon when available // TODO : change with broadcast or meeting icon when available
// +
imageSource: !mainWindow.call imageSource: !mainWindow.call
? AppIcons.meeting ? AppIcons.meeting
: (mainWindow.callState === LinphoneEnums.CallState.End : (mainWindow.callState === LinphoneEnums.CallState.End
@ -725,18 +724,16 @@ Window {
Connections { Connections {
target: participantsStack target: participantsStack
onCurrentItemChanged: { onCurrentItemChanged: {
console.log("changing title", participantsStack.currentItem == participantList)
if (participantsStack.currentItem == participantList) rightPanel.headerTitleText = qsTr("Participants (%1)").arg(participantList.count) if (participantsStack.currentItem == participantList) rightPanel.headerTitleText = qsTr("Participants (%1)").arg(participantList.count)
} }
} }
Connections { Connections {
target: rightPanel target: rightPanel
// TODO : chercher comment relier ces infos pour faire le add des participants onValidateRequested: {
//onValidateRequested: { participantList.model.addAddresses(participantsStack.selectedParticipants)
// participantList.model.addAddresses(participantsStack.selectedParticipants) participantsStack.pop()
// participantsStack.pop() participantsStack.participantAdded()
// participantsStack.participantAdded() }
//}
} }
} }
} }

View file

@ -26,6 +26,11 @@ Item {
transferSucceedPopup.open() transferSucceedPopup.open()
} }
function createContact(name, address) {
tabbar.currentIndex = 1
contactPage.createContact(name, address)
}
Timer { Timer {
id: autoClosePopup id: autoClosePopup
interval: 5000 interval: 5000
@ -119,7 +124,7 @@ Item {
{icon: AppIcons.phone, selectedIcon: AppIcons.phoneSelected, label: qsTr("Appels")}, {icon: AppIcons.phone, selectedIcon: AppIcons.phoneSelected, label: qsTr("Appels")},
{icon: AppIcons.adressBook, selectedIcon: AppIcons.adressBookSelected, label: qsTr("Contacts")}, {icon: AppIcons.adressBook, selectedIcon: AppIcons.adressBookSelected, label: qsTr("Contacts")},
{icon: AppIcons.chatTeardropText, selectedIcon: AppIcons.chatTeardropTextSelected, label: qsTr("Conversations")}, {icon: AppIcons.chatTeardropText, selectedIcon: AppIcons.chatTeardropTextSelected, label: qsTr("Conversations")},
{icon: AppIcons.usersThree, selectedIcon: AppIcons.usersThreeSelected, label: qsTr("Réunions")} {icon: AppIcons.videoconference, selectedIcon: AppIcons.videoconferenceSelected, label: qsTr("Réunions")}
] ]
} }
@ -269,9 +274,8 @@ Item {
Item {Layout.fillWidth: true} Item {Layout.fillWidth: true}
} }
onClicked: { onClicked: {
var currentItem = mainStackLayout.children[mainStackLayout.currentIndex] mainItem.createContact(magicSearchBar.text, sipAddr.text)
listPopup.close() listPopup.close()
currentItem.createContact(magicSearchBar.text, sipAddr.text)
} }
} }
} }
@ -360,8 +364,13 @@ Item {
Layout.topMargin: 24 * DefaultStyle.dp Layout.topMargin: 24 * DefaultStyle.dp
CallPage { CallPage {
id: callPage id: callPage
onCreateContactRequested: (name, address) => {
mainItem.createContact(name, address)
}
}
ContactPage{
id: contactPage
} }
ContactPage{}
Item{} Item{}
//ConversationPage{} //ConversationPage{}
MeetingPage{} MeetingPage{}

View file

@ -33,6 +33,10 @@ ApplicationWindow {
mainWindowStackView.currentItem.transferCallSucceed() mainWindowStackView.currentItem.transferCallSucceed()
} }
function removeFromPopupLayout(index) {
popupLayout.popupList.splice(index, 1)
}
Component { Component {
id: popupComp id: popupComp
InformationPopup{} InformationPopup{}
@ -42,26 +46,44 @@ ApplicationWindow {
infoPopup.index = popupLayout.popupList.length infoPopup.index = popupLayout.popupList.length
popupLayout.popupList.push(infoPopup) popupLayout.popupList.push(infoPopup)
infoPopup.open() infoPopup.open()
infoPopup.closePopup.connect(removeFromPopupLayout)
}
function showLoadingPopup(text) {
loadingPopup.text = text
loadingPopup.open()
}
function closeLoadingPopup() {
loadingPopup.close()
} }
ColumnLayout { ColumnLayout {
id: popupLayout id: popupLayout
anchors.fill: parent anchors.fill: parent
Layout.alignment: Qt.AlignBottom Layout.alignment: Qt.AlignBottom
property int nextY: mainWindow.height property int nextY: mainWindow.height
property list<Popup> popupList property list<InformationPopup> popupList
property int popupCount: popupList.length property int popupCount: popupList.length
spacing: 15 spacing: 15 * DefaultStyle.dp
onPopupCountChanged: { onPopupCountChanged: {
nextY = mainWindow.height nextY = mainWindow.height
for(var i = 0; i < popupCount; ++i) { for(var i = 0; i < popupCount; ++i) {
popupList[i].y = nextY - popupList[i].height popupList[i].y = nextY - popupList[i].height
popupList[i].index = i
nextY = nextY - popupList[i].height - 15 nextY = nextY - popupList[i].height - 15
} }
} }
} }
LoadingPopup {
id: loadingPopup
modal: true
closePolicy: Popup.NoAutoClose
anchors.centerIn: parent
padding: 20 * DefaultStyle.dp
underlineColor: DefaultStyle.main1_500_main
radius: 15 * DefaultStyle.dp
}
AccountProxy { AccountProxy {
// TODO : change this so it does not display the main page for one second // TODO : change this so it does not display the main page for one second
// when we fail trying to connect the first account (account is added and // when we fail trying to connect the first account (account is added and

View file

@ -14,6 +14,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Layout/FormItemLayout.qml view/Layout/FormItemLayout.qml
view/Layout/Mosaic.qml view/Layout/Mosaic.qml
view/Layout/RightPanelLayout.qml
view/Layout/Section.qml view/Layout/Section.qml
view/Item/Account/Accounts.qml view/Item/Account/Accounts.qml
@ -58,6 +59,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Item/ErrorText.qml view/Item/ErrorText.qml
view/Item/IconLabelButton.qml view/Item/IconLabelButton.qml
view/Item/InformationPopup.qml view/Item/InformationPopup.qml
view/Item/LoadingPopup.qml
view/Item/MovableMouseArea.qml view/Item/MovableMouseArea.qml
view/Item/NumericPad.qml view/Item/NumericPad.qml
view/Item/PhoneNumberComboBox.qml view/Item/PhoneNumberComboBox.qml

View file

@ -7,35 +7,39 @@ import Linphone
import ConstantsCpp 1.0 import ConstantsCpp 1.0
import UtilsCpp 1.0 import UtilsCpp 1.0
// TODO : spacing
ListView { ListView {
id: mainItem id: mainItem
// width: 400 * DefaultStyle.dp
// height: 400 * DefaultStyle.dp
snapMode: ListView.SnapOneItem snapMode: ListView.SnapOneItem
orientation: Qt.Horizontal orientation: Qt.Horizontal
clip: true clip: true
property int maxYears: 5 property int maxYears: 5
readonly property var currentDate: new Date() readonly property var currentDate: new Date()
highlightMoveDuration: 100 highlightMoveDuration: 100
// height: contentHeight
property var selectedDate property var selectedDate
property int currentMonth: calendarModel.monthAt(currentIndex) + 1 //january is index 0
property int currentYear: calendarModel.yearAt(currentIndex)
onCurrentYearChanged: console.log("currentyear", currentYear)
onCurrentMonthChanged: console.log("current month", currentMonth)
model: Control.CalendarModel { model: Control.CalendarModel {
id: calendarModel id: calendarModel
from: new Date() from: new Date()
// TODO : dynamically add 5 years to: UtilsCpp.addYears(new Date(), 5)
to: new Date(2025, 12, 31)
} }
delegate: ColumnLayout { delegate: ColumnLayout {
width: mainItem.width width: mainItem.width
height: mainItem.height height: mainItem.height
property int currentMonth: model.month
spacing: 18 * DefaultStyle.dp
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: 38 * DefaultStyle.dp
Text { Text {
// TODO (high prio): don't use javascript, C++ text: UtilsCpp.toDateMonthAndYearString(new Date(model.year, model.month, 15))// 15 because of timezones that can change the date for localeString
text: new Date(model.year, model.month, 15).toLocaleString(Qt.locale(ConstantsCpp.DefaultLocale), 'MMMM yyyy')// 15 because of timezones that can change the date for localeString
font { font {
pixelSize: 14 * DefaultStyle.dp pixelSize: 14 * DefaultStyle.dp
weight: 700 * DefaultStyle.dp weight: 700 * DefaultStyle.dp
@ -52,7 +56,7 @@ ListView {
icon.height: height icon.height: height
background: Item{} background: Item{}
icon.source: AppIcons.leftArrow icon.source: AppIcons.leftArrow
onClicked: if (mainItem.currentIndex > 0) --mainItem.currentIndex onClicked: if (mainItem.currentIndex > 0) mainItem.currentIndex = mainItem.currentIndex - 1
} }
Button { Button {
Layout.preferredWidth: 20 * DefaultStyle.dp Layout.preferredWidth: 20 * DefaultStyle.dp
@ -61,62 +65,69 @@ ListView {
icon.height: height icon.height: height
background: Item{} background: Item{}
icon.source: AppIcons.rightArrow icon.source: AppIcons.rightArrow
onClicked: if (mainItem.currentIndex < mainItem.count) ++mainItem.currentIndex onClicked: if (mainItem.currentIndex < mainItem.count) mainItem.currentIndex = mainItem.currentIndex + 1
}
}
Control.DayOfWeekRow {
locale: monthGrid.locale
Layout.column: 1
Layout.fillWidth: true
delegate: Text {
text: model.shortName
color: DefaultStyle.main2_400
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
}
} }
} }
Control.MonthGrid { ColumnLayout {
id: monthGrid spacing: 12 * DefaultStyle.dp
Layout.fillWidth: true Control.DayOfWeekRow {
Layout.fillHeight: true locale: monthGrid.locale
Layout.column: 1
year: model.year Layout.fillWidth: true
month: model.month delegate: Text {
// locale: Qt.locale("en_US") text: model.shortName
delegate: Item { color: DefaultStyle.main2_400
property bool isSelectedDay: mainItem.selectedDate ? UtilsCpp.datesAreEqual(mainItem.selectedDate, model.date) : false horizontalAlignment: Text.AlignHCenter
Rectangle { verticalAlignment: Text.AlignVCenter
anchors.centerIn: parent
width: 30 * DefaultStyle.dp
height: 30 * DefaultStyle.dp
radius: 50 * DefaultStyle.dp
color: isSelectedDay ? DefaultStyle.main1_500_main : "transparent"
}
Text {
anchors.centerIn: parent
text: monthGrid.locale.toString(model.date, "d")
color: isSelectedDay
? DefaultStyle.grey_0
: UtilsCpp.isCurrentDay(model.date)
? DefaultStyle.main1_500_main
: UtilsCpp.isCurrentMonth(model.date)
? DefaultStyle.main2_700
: DefaultStyle.main2_400
font { font {
pixelSize: 12 * DefaultStyle.dp pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp weight: 300 * DefaultStyle.dp
} }
} }
} }
onClicked: (date) => {
if (UtilsCpp.isBeforeToday(date)) return; Control.MonthGrid {
mainItem.selectedDate = date id: monthGrid
} Layout.fillWidth: true
} Layout.fillHeight: true
year: model.year
month: model.month
property var curDate: model.date
onMonthChanged: console.log("cur date changed", month)
locale: Qt.locale(ConstantsCpp.DefaultLocale)
delegate: Item {
property bool isSelectedDay: mainItem.selectedDate ? UtilsCpp.datesAreEqual(mainItem.selectedDate, model.date) : false
// width: 30 * DefaultStyle.dp
// height: 30 * DefaultStyle.dp
Rectangle {
anchors.centerIn: parent
width: 30 * DefaultStyle.dp
height: 30 * DefaultStyle.dp
radius: 50 * DefaultStyle.dp
color: isSelectedDay ? DefaultStyle.main1_500_main : "transparent"
}
Text {
anchors.centerIn: parent
text: UtilsCpp.toDateDayString(model.date)
color: isSelectedDay
? DefaultStyle.grey_0
: UtilsCpp.isCurrentDay(model.date)
? DefaultStyle.main1_500_main
: UtilsCpp.dateisInMonth(model.date, mainItem.currentMonth, mainItem.currentYear)
? DefaultStyle.main2_700
: DefaultStyle.main2_400
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
}
}
}
onClicked: (date) => {
if (UtilsCpp.isBeforeToday(date)) return;
mainItem.selectedDate = date
}
}
}
} }
} }

View file

@ -1,6 +1,7 @@
import QtQuick import QtQuick
import QtQuick.Controls as Control import QtQuick.Controls as Control
import QtQuick.Effects import QtQuick.Effects
import QtQuick.Layouts
import Linphone import Linphone
ComboBox { ComboBox {
@ -25,7 +26,12 @@ ComboBox {
width: 321 * DefaultStyle.dp width: 321 * DefaultStyle.dp
height: 270 * DefaultStyle.dp height: 270 * DefaultStyle.dp
closePolicy: Popup.NoAutoClose closePolicy: Popup.NoAutoClose
topPadding: 25 * DefaultStyle.dp
bottomPadding: 24 * DefaultStyle.dp
leftPadding: 21 * DefaultStyle.dp
rightPadding: 19 * DefaultStyle.dp
background: Item { background: Item {
anchors.fill: parent
Rectangle { Rectangle {
id: calendarBg id: calendarBg
anchors.fill: parent anchors.fill: parent

View file

@ -19,7 +19,7 @@ Button {
background: Rectangle { background: Rectangle {
anchors.fill: parent anchors.fill: parent
color: mainItem.backgroundColor color: mainItem.backgroundColor
radius: mainItem.width * 1.29 radius: mainItem.width /2
} }
icon.source: checkedIconUrl && mainItem.checked ? checkedIconUrl : iconUrl icon.source: checkedIconUrl && mainItem.checked ? checkedIconUrl : iconUrl
icon.width: width * 0.58 icon.width: width * 0.58

View file

@ -7,265 +7,281 @@ import QtQuick.Layouts
import Linphone import Linphone
import UtilsCpp 1.0 import UtilsCpp 1.0
ColumnLayout { RightPanelLayout {
id: mainItem id: mainItem
property FriendGui contact property FriendGui contact
Connections {
target: contact.core
onIsSavedChanged: {
if (contact.core.isSaved) {
var mainWin = UtilsCpp.getMainWindow()
UtilsCpp.smartShowWindow(mainWin)
mainWin.goToContactDetail(contact)
}
}
}
property string title: qsTr("Modifier contact") property string title: qsTr("Modifier contact")
property string saveButtonText: qsTr("Enregistrer") property string saveButtonText: qsTr("Enregistrer")
property string oldPictureUri property string oldPictureUri
signal closeEdition() signal closeEdition()
Rectangle { headerContent: [
Layout.alignment: Qt.AlignTop | Qt.AlignLeft Text {
Layout.fillWidth: true anchors.left: parent.left
Layout.preferredHeight: 40 * DefaultStyle.dp anchors.leftMargin: 31 * DefaultStyle.dp
Text { anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left text: mainItem.title
anchors.leftMargin: 10 * DefaultStyle.dp font {
text: mainItem.title pixelSize: 20 * DefaultStyle.dp
font { weight: 800 * DefaultStyle.dp
pixelSize: 20 * DefaultStyle.dp }
weight: 800 * DefaultStyle.dp },
Button {
background: Item{}
anchors.right: parent.right
anchors.rightMargin: 41 * DefaultStyle.dp
anchors.verticalCenter: parent.verticalCenter
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
icon.source: AppIcons.closeX
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
onClicked: {
// contact.core.pictureUri = mainItem.oldPictureUri
mainItem.contact.core.undo()
mainItem.closeEdition()
}
} }
} ]
Button {
background: Item{}
anchors.right: parent.right
anchors.rightMargin: 10 * DefaultStyle.dp
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
icon.source: AppIcons.closeX
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
onClicked: {
// contact.core.pictureUri = mainItem.oldPictureUri
mainItem.contact.core.undo()
mainItem.closeEdition()
}
}
} content: ColumnLayout {
ColumnLayout { anchors.centerIn: parent
Layout.alignment: Qt.AlignHCenter // anchors.leftMargin: 103 * DefaultStyle.dp
Layout.topMargin: 69 * DefaultStyle.dp ColumnLayout {
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 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 { IconLabelButton {
visible: !mainItem.contact || mainItem.contact.core.pictureUri.length === 0
Layout.preferredWidth: width Layout.preferredWidth: width
Layout.preferredHeight: 17 * DefaultStyle.dp Layout.preferredHeight: 17 * DefaultStyle.dp
iconSource: AppIcons.pencil iconSource: AppIcons.camera
iconSize: 17 * DefaultStyle.dp iconSize: 17 * DefaultStyle.dp
text: qsTr("Modifier") text: qsTr("Ajouter une image")
onClicked: fileDialog.open() onClicked: fileDialog.open()
} }
FileDialog { RowLayout {
id: fileDialog visible: mainItem.contact && mainItem.contact.core.pictureUri.length != 0
currentFolder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0] Layout.alignment: Qt.AlignHCenter
onAccepted: { IconLabelButton {
mainItem.oldPictureUri = mainItem.contact.core.pictureUri Layout.preferredWidth: width
var avatarPath = UtilsCpp.createAvatar( selectedFile ) Layout.preferredHeight: 17 * DefaultStyle.dp
if(avatarPath){ iconSource: AppIcons.pencil
mainItem.contact.core.pictureUri = avatarPath 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 {
IconLabelButton { Layout.preferredHeight: 17 * DefaultStyle.dp
Layout.preferredHeight: 17 * DefaultStyle.dp Layout.preferredWidth: width
Layout.preferredWidth: width iconSize: 17 * DefaultStyle.dp
iconSize: 17 * DefaultStyle.dp iconSource: AppIcons.trashCan
iconSource: AppIcons.trashCan text: qsTr("Supprimer")
text: qsTr("Supprimer") onClicked: mainItem.contact.core.pictureUri = ""
onClicked: mainItem.contact.core.pictureUri = "" }
} }
} }
} RowLayout {
RowLayout { Layout.alignment: Qt.AlignHCenter
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
FormItemLayout {
label: qsTr("Prénom")
contentItem: TextField {
initialText: contact.core.givenName
onEditingFinished: contact.core.givenName = text
backgroundColor: DefaultStyle.grey_0
}
}
FormItemLayout {
label: qsTr("Nom")
contentItem: TextField {
initialText: contact.core.familyName
onEditingFinished: contact.core.familyName = text
backgroundColor: DefaultStyle.grey_0
}
}
FormItemLayout {
label: qsTr("Entreprise")
contentItem: TextField {
initialText: contact.core.organization
onEditingFinished: contact.core.organization = text
backgroundColor: DefaultStyle.grey_0
}
}
FormItemLayout {
label: qsTr("Fonction")
contentItem: TextField {
initialText: contact.core.job
onEditingFinished: contact.core.job = text
backgroundColor: DefaultStyle.grey_0
}
}
Item{Layout.fillHeight: true}
}
Control.ScrollView {
Layout.fillHeight: true Layout.fillHeight: true
contentHeight: content.height Layout.fillWidth: true
spacing: 100 * DefaultStyle.dp
Layout.topMargin: 50 * DefaultStyle.dp
Layout.bottomMargin: 50 * DefaultStyle.dp
ColumnLayout { ColumnLayout {
id: content
anchors.rightMargin: 10 * DefaultStyle.dp
spacing: 20 * DefaultStyle.dp spacing: 20 * DefaultStyle.dp
Repeater { FormItemLayout {
model: VariantList { label: qsTr("Prénom")
model: mainItem.contact && mainItem.contact.core.addresses || [] contentItem: TextField {
} initialText: contact.core.givenName
delegate: RowLayout { onEditingFinished: contact.core.givenName = text
FormItemLayout { backgroundColor: DefaultStyle.grey_0
label: modelData.label
contentItem: TextField {
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.setAddressAt(index, qsTr("Address SIP"), text)
}
initialText: modelData.address
backgroundColor: DefaultStyle.grey_0
}
}
Button {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
background: Item{}
icon.source: AppIcons.closeX
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
onClicked: mainItem.contact.core.removeAddress(index)
}
} }
} }
RowLayout { FormItemLayout {
FormItemLayout { label: qsTr("Nom")
label: qsTr("Adresse SIP") contentItem: TextField {
contentItem: TextField { initialText: contact.core.familyName
backgroundColor: DefaultStyle.grey_0 onEditingFinished: contact.core.familyName = text
onEditingFinished: { backgroundColor: DefaultStyle.grey_0
if (text.length != 0) mainItem.contact.core.appendAddress(text)
text = ""
}
}
}
Item {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
} }
} }
Repeater { FormItemLayout {
// phone numbers label: qsTr("Entreprise")
model: VariantList { contentItem: TextField {
model: mainItem.contact && mainItem.contact.core.phoneNumbers || [] initialText: contact.core.organization
} onEditingFinished: contact.core.organization = text
delegate: RowLayout { backgroundColor: DefaultStyle.grey_0
FormItemLayout {
label: modelData.label
contentItem: TextField {
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{}
icon.source: AppIcons.closeX
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
onClicked: mainItem.contact.core.removePhoneNumber(index)
}
} }
} }
RowLayout { FormItemLayout {
FormItemLayout { label: qsTr("Fonction")
label: qsTr("Phone") contentItem: TextField {
contentItem: TextField { initialText: contact.core.job
backgroundColor: DefaultStyle.grey_0 onEditingFinished: contact.core.job = text
onEditingFinished: { backgroundColor: DefaultStyle.grey_0
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} Item{Layout.fillHeight: true}
} }
Control.ScrollBar.vertical: Control.ScrollBar{ Control.ScrollView {
id: scrollbar Layout.fillHeight: true
active: true contentHeight: content.height
interactive: true ColumnLayout {
policy: Control.ScrollBar.AsNeeded id: content
anchors.top: parent.top anchors.rightMargin: 10 * DefaultStyle.dp
anchors.bottom: parent.bottom spacing: 20 * DefaultStyle.dp
anchors.right: parent.right Repeater {
anchors.leftMargin: 15 * DefaultStyle.dp model: VariantList {
} model: mainItem.contact && mainItem.contact.core.addresses || []
Control.ScrollBar.horizontal: Control.ScrollBar{ }
visible: false delegate: FormItemLayout {
label: modelData.label
contentItem: RowLayout {
TextField {
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.setAddressAt(index, qsTr("Address SIP"), text)
}
initialText: modelData.address
backgroundColor: DefaultStyle.grey_0
Layout.preferredWidth: width
Layout.preferredHeight: height
}
Button {
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.alignment: Qt.AlignVCenter
background: Item{}
icon.source: AppIcons.closeX
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
onClicked: mainItem.contact.core.removeAddress(index)
}
}
}
}
RowLayout {
FormItemLayout {
label: qsTr("Adresse SIP")
contentItem: TextField {
backgroundColor: DefaultStyle.grey_0
onEditingFinished: {
if (text.length != 0) mainItem.contact.core.appendAddress(text)
text = ""
}
}
}
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 {
FormItemLayout {
label: modelData.label
contentItem: TextField {
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{}
icon.source: AppIcons.closeX
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp
onClicked: mainItem.contact.core.removePhoneNumber(index)
}
}
}
RowLayout {
FormItemLayout {
label: qsTr("Phone")
contentItem: TextField {
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 { Button {
Layout.bottomMargin: 100 * DefaultStyle.dp Layout.bottomMargin: 100 * DefaultStyle.dp
Layout.preferredWidth: 165 * DefaultStyle.dp Layout.preferredWidth: 165 * DefaultStyle.dp
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
enabled: mainItem.contact && mainItem.contact.core.givenName.length > 0 enabled: mainItem.contact && mainItem.contact.core.givenName.length > 0
text: mainItem.saveButtonText text: mainItem.saveButtonText
leftPadding: 20 * DefaultStyle.dp leftPadding: 20 * DefaultStyle.dp
rightPadding: 20 * DefaultStyle.dp rightPadding: 20 * DefaultStyle.dp
topPadding: 11 * DefaultStyle.dp topPadding: 11 * DefaultStyle.dp
bottomPadding: 11 * DefaultStyle.dp bottomPadding: 11 * DefaultStyle.dp
onClicked: { onClicked: {
mainItem.contact.core.save() mainItem.contact.core.save()
mainItem.closeEdition() mainItem.closeEdition()
}
} }
} }
} }

View file

@ -4,6 +4,7 @@ import QtQuick.Controls as Control
import Linphone import Linphone
import UtilsCpp 1.0 import UtilsCpp 1.0
import ConstantsCpp 1.0
ListView { ListView {
id: mainItem id: mainItem
@ -40,11 +41,7 @@ ListView {
property FriendGui selectedContact: model.getAt(currentIndex) || null property FriendGui selectedContact: model.getAt(currentIndex) || null
onCurrentIndexChanged: selectedContact = model.getAt(currentIndex) || null onCurrentIndexChanged: selectedContact = model.getAt(currentIndex) || null
onCountChanged: {
selectedContact = model.getAt(currentIndex) || null
}
// signal contactSelected(var contact)
signal contactStarredChanged() signal contactStarredChanged()
signal contactDeletionRequested(FriendGui contact) signal contactDeletionRequested(FriendGui contact)
signal contactAddedToSelection() signal contactAddedToSelection()
@ -66,6 +63,9 @@ ListView {
model: MagicSearchProxy { model: MagicSearchProxy {
searchText: searchBarText.length === 0 ? "*" : searchBarText searchText: searchBarText.length === 0 ? "*" : searchBarText
onFriendCreated: (index) => {
mainItem.currentIndex = index
}
} }
Control.ScrollBar.vertical: ScrollBar { Control.ScrollBar.vertical: ScrollBar {
@ -85,9 +85,10 @@ ListView {
property var previousDisplayName: previousItem ? previousItem.core.displayName : "" property var previousDisplayName: previousItem ? previousItem.core.displayName : ""
property var displayName: modelData.core.displayName property var displayName: modelData.core.displayName
property bool display: !mainItem.showOnlyFavourites || modelData.core.starred property bool display: !mainItem.showOnlyFavourites || modelData.core.starred
visible: display visible: display
Connections { Connections {
enabled: modelData.core
target: modelData.core target: modelData.core
onStarredChanged: mainItem.contactStarredChanged() onStarredChanged: mainItem.contactStarredChanged()
} }
@ -98,7 +99,7 @@ ListView {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
width: 20 * DefaultStyle.dp width: 20 * DefaultStyle.dp
opacity: (!previousItem || !previousDisplayName.startsWith(displayName[0])) ? 1 : 0 opacity: (!previousItem || !previousDisplayName.toLocaleLowerCase(ConstantsCpp.DefaultLocale).startsWith(displayName[0].toLocaleLowerCase(ConstantsCpp.DefaultLocale))) ? 1 : 0
text: displayName[0] text: displayName[0]
color: DefaultStyle.main2_400 color: DefaultStyle.main2_400
font { font {

View file

@ -9,12 +9,11 @@ Popup {
property string title property string title
property string description property string description
property int index property int index
signal closePopup(int index)
onClosed: closePopup(index)
onAboutToShow: { onAboutToShow: {
autoClosePopup.restart() autoClosePopup.restart()
} }
onAboutToHide: {
popupLayout.popupList.splice(mainItem.index, 1)
}
closePolicy: Popup.NoAutoClose closePolicy: Popup.NoAutoClose
x : parent.x + parent.width - width x : parent.x + parent.width - width
// y : parent.y + parent.height - height // y : parent.y + parent.height - height

View file

@ -0,0 +1,32 @@
import QtQuick 2.15
import QtQuick.Layouts 1.3
import QtQuick.Controls
import Linphone
Popup {
id: mainItem
property string text
modal: true
closePolicy: Control.Popup.NoAutoClose
anchors.centerIn: parent
padding: 20 * DefaultStyle.dp
underlineColor: DefaultStyle.main1_500_main
radius: 15 * DefaultStyle.dp
// onAboutToShow: width = contentText.implicitWidth
contentItem: ColumnLayout {
spacing: 15 * DefaultStyle.dp
BusyIndicator{
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: 33 * DefaultStyle.dp
Layout.preferredHeight: 33 * DefaultStyle.dp
}
Text {
id: contentText
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.fillHeight: true
text: mainItem.text
font.pixelSize: 14 * DefaultStyle.dp
}
}
}

View file

@ -14,14 +14,14 @@ ListView {
property string searchBarText property string searchBarText
property bool hoverEnabled: true property bool hoverEnabled: true
property var delegateButtons property var delegateButtons
property ConferenceInfoGui selectedConference: model.getAt(currentIndex) || null property ConferenceInfoGui selectedConference: currentIndex != -1 ? model.getAt(currentIndex) : null
spacing: 8 * DefaultStyle.dp spacing: 8 * DefaultStyle.dp
currentIndex: confInfoProxy.currentDateIndex currentIndex: confInfoProxy.currentDateIndex
onCountChanged: selectedConference = model.getAt(currentIndex) || null onCountChanged: selectedConference = currentIndex != -1 ? model.getAt(currentIndex) : null
onCurrentIndexChanged: { onCurrentIndexChanged: {
selectedConference = currentIndex != confInfoProxy.currentDateIndex ? model.getAt(currentIndex) : null selectedConference = model.getAt(currentIndex)
} }
onVisibleChanged: if( visible) { onVisibleChanged: if( visible) {
mainItem.positionViewAtIndex(currentIndex, ListView.Center)// First approximative move mainItem.positionViewAtIndex(currentIndex, ListView.Center)// First approximative move
@ -34,16 +34,13 @@ ListView {
} }
// using highlight doesn't center, take time before moving and don't work for not visible item (like not loaded) // using highlight doesn't center, take time before moving and don't work for not visible item (like not loaded)
highlightFollowsCurrentItem: false highlightFollowsCurrentItem: false
function forceUpdate() {
confInfoProxy.lUpdate()
}
signal conferenceSelected(var contact) signal conferenceSelected(var contact)
model: ConferenceInfoProxy { model: ConferenceInfoProxy {
id: confInfoProxy id: confInfoProxy
searchText: searchBarText.length === 0 ? "" : searchBarText searchText: searchBarText.length === 0 ? "" : searchBarText
filterType: ConferenceInfoProxy.None
} }
section { section {
@ -91,12 +88,12 @@ ListView {
Layout.fillWidth: false Layout.fillWidth: false
Layout.preferredWidth: 32 * DefaultStyle.dp Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.minimumWidth: 32 * DefaultStyle.dp Layout.minimumWidth: 32 * DefaultStyle.dp
height: 51 * DefaultStyle.dp Layout.preferredHeight: 51 * DefaultStyle.dp
visible: !previousDateString || previousDateString != dateString visible: previousDateString.length == 0 || previousDateString != dateString
spacing: 0 spacing: 0
//anchors.leftMargin: 45 * DefaultStyle.dp
Text { Text {
Layout.preferredHeight: 19 * DefaultStyle.dp Layout.preferredHeight: 19 * DefaultStyle.dp
Layout.alignment: Qt.AlignCenter
text: day.substring(0,3) + '.' text: day.substring(0,3) + '.'
color: DefaultStyle.main2_500main color: DefaultStyle.main2_500main
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
@ -109,8 +106,8 @@ ListView {
} }
Rectangle { Rectangle {
id: dayNum id: dayNum
Layout.fillWidth: true Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.preferredHeight: width Layout.preferredHeight: 32 * DefaultStyle.dp
Layout.alignment: Qt.AlignCenter Layout.alignment: Qt.AlignCenter
radius: height/2 radius: height/2
property var isCurrentDay: UtilsCpp.isCurrentDay(dateTime) property var isCurrentDay: UtilsCpp.isCurrentDay(dateTime)
@ -118,9 +115,9 @@ ListView {
color: isCurrentDay ? DefaultStyle.main1_500_main : "transparent" color: isCurrentDay ? DefaultStyle.main1_500_main : "transparent"
Text { Text {
id: dayNumText
anchors.centerIn: parent anchors.centerIn: parent
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: UtilsCpp.toDateDayString(dateTime) text: UtilsCpp.toDateDayString(dateTime)
color: dayNum.isCurrentDay ? DefaultStyle.grey_0 : DefaultStyle.main2_500main color: dayNum.isCurrentDay ? DefaultStyle.grey_0 : DefaultStyle.main2_500main
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
@ -208,18 +205,16 @@ ListView {
} }
} }
// MouseArea {
// id: confArea
MouseArea { // hoverEnabled: mainItem.hoverEnabled
id: confArea // visible: !dateDay.visible && itemDelegate.haveModel
hoverEnabled: mainItem.hoverEnabled // anchors.fill: parent
visible: !dateDay.visible && itemDelegate.haveModel // cursorShape: Qt.PointingHandCursor
anchors.fill: parent // onClicked: {
cursorShape: Qt.PointingHandCursor // mainItem.currentIndex = index
onClicked: { // mainItem.conferenceSelected($modelData)
mainItem.currentIndex = index // }
mainItem.conferenceSelected($modelData) // }
}
}
} }
} }

View file

@ -5,7 +5,6 @@ import QtQuick.Controls as Control
import Linphone import Linphone
import UtilsCpp 1.0 import UtilsCpp 1.0
//TODO : spacing layout
ColumnLayout { ColumnLayout {
id: mainItem id: mainItem
spacing: 8 * DefaultStyle.dp spacing: 8 * DefaultStyle.dp
@ -18,7 +17,6 @@ ColumnLayout {
Connections { Connections {
target: mainItem.conferenceInfoGui.core target: mainItem.conferenceInfoGui.core
onSchedulerStateChanged: { onSchedulerStateChanged: {
console.log("scheduler state changed", mainItem.conferenceInfoGui.core.schedulerState)
if (mainItem.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Ready) { if (mainItem.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Ready) {
mainItem.saveSucceed(isCreation) mainItem.saveSucceed(isCreation)
} }

View file

@ -7,8 +7,8 @@ import Linphone
Control.TabBar { Control.TabBar {
id: mainItem id: mainItem
spacing: 15 * DefaultStyle.dp spacing: 32 * DefaultStyle.dp
topPadding: 20 * DefaultStyle.dp topPadding: 36 * DefaultStyle.dp
property var model property var model
readonly property alias cornerRadius: bottomLeftCorner.radius readonly property alias cornerRadius: bottomLeftCorner.radius

View file

@ -68,17 +68,17 @@ Item {
Component{ Component{
id: activeSpeakerComponent id: activeSpeakerComponent
ActiveSpeakerLayout{ ActiveSpeakerLayout{
Layout.Layout.fillWidth: true Layout.Layout.fillWidth: true
Layout.Layout.fillHeight: true Layout.Layout.fillHeight: true
call: mainItem.call call: mainItem.call
} }
} }
Component{ Component{
id: gridComponent id: gridComponent
GridLayout{ GridLayout{
Layout.Layout.fillWidth: true Layout.Layout.fillWidth: true
Layout.Layout.fillHeight: true Layout.Layout.fillHeight: true
call: mainItem.call call: mainItem.call
} }
} }
} }

View file

@ -55,7 +55,6 @@ ColumnLayout {
// Layout.fillWidth: true // Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
Avatar { Avatar {
// TODO : find friend and pass contact argument
id: detailAvatar id: detailAvatar
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
width: 100 * DefaultStyle.dp width: 100 * DefaultStyle.dp

View file

@ -0,0 +1,30 @@
import QtQuick 2.15
import QtQuick.Effects
import QtQuick.Layouts
import QtQuick.Controls as Control
import Linphone
import UtilsCpp 1.0
Item {
id: mainItem
property color panelColor: DefaultStyle.grey_100
property alias headerContent: rightPanelHeader.children
property alias content: rightPanelContent.children
Rectangle {
id: rightPanelHeader
color: DefaultStyle.grey_0
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 57 * DefaultStyle.dp
}
Rectangle {
id: rightPanelContent
color: mainItem.panelColor
anchors.top: rightPanelHeader.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
}
}

View file

@ -18,24 +18,8 @@ Item {
property color rightPanelColor: DefaultStyle.grey_100 property color rightPanelColor: DefaultStyle.grey_100
property alias leftPanelContent: leftPanel.children property alias leftPanelContent: leftPanel.children
property alias rightPanelStackView: rightPanelStackView property alias rightPanelStackView: rightPanelStackView
property alias contactEditionComp: contactEditionComp
property alias rightPanel: rightPanel property alias rightPanel: rightPanel
signal noItemButtonPressed() signal noItemButtonPressed()
signal contactEditionClosed()
function createContact(name, address) {
var friendGui = Qt.createQmlObject('import Linphone
FriendGui{
}', mainItem)
friendGui.core.givenName = UtilsCpp.getGivenNameFromFullName(name)
friendGui.core.familyName = UtilsCpp.getFamilyNameFromFullName(name)
friendGui.core.defaultAddress = address
rightPanelStackView.push(contactEditionComp, {"contact": friendGui, "title": qsTr("Nouveau contact"), "saveButtonText": qsTr("Créer")})
}
function editContact(friendGui) {
rightPanelStackView.push(contactEditionComp, {"contact": friendGui, "title": qsTr("Modifier contact"), "saveButtonText": qsTr("Enregistrer")})
}
// Control.SplitView { // Control.SplitView {
// id: splitView // id: splitView
@ -223,24 +207,8 @@ Item {
} }
} }
Item { Control.StackView {
Control.StackView { id: rightPanelStackView
id: rightPanelStackView
anchors.fill: parent
anchors.topMargin: 39 * DefaultStyle.dp
anchors.leftMargin: 39 * DefaultStyle.dp
}
}
// We need this component here as it is used in multiple subPages (Call and Contact pages)
Component {
id: contactEditionComp
ContactEdition {
property string objectName: "contactEdition"
onCloseEdition: {
rightPanelStackView.pop(Control.StackView.Immediate)
mainItem.contactEditionClosed()
}
}
} }
} }
} }

View file

@ -22,6 +22,7 @@ AbstractMainPage {
property bool isRegistered: account ? account.core.registrationState == LinphoneEnums.RegistrationState.Ok : false property bool isRegistered: account ? account.core.registrationState == LinphoneEnums.RegistrationState.Ok : false
property int selectedParticipantsCount property int selectedParticipantsCount
signal startGroupCallRequested() signal startGroupCallRequested()
signal createContactRequested(string name, string address)
Connections { Connections {
enabled: confInfoGui enabled: confInfoGui
@ -529,7 +530,7 @@ AbstractMainPage {
} }
onClicked: { onClicked: {
detailOptions.close() detailOptions.close()
mainItem.createContact(contactDetail.contactName, contactDetail.contactAddress) mainItem.createContactRequested(contactDetail.contactName, contactDetail.contactAddress)
} }
} }
Button { Button {

View file

@ -25,25 +25,28 @@ AbstractMainPage {
onNoItemButtonPressed: createContact("", "") onNoItemButtonPressed: createContact("", "")
function createContact(name, address) {
var friendGui = Qt.createQmlObject('import Linphone
FriendGui{
}', mainItem)
friendGui.core.givenName = UtilsCpp.getGivenNameFromFullName(name)
friendGui.core.familyName = UtilsCpp.getFamilyNameFromFullName(name)
friendGui.core.defaultAddress = address
rightPanelStackView.push(contactEdition, {"contact": friendGui, "title": qsTr("Nouveau contact"), "saveButtonText": qsTr("Créer")})
}
function editContact(friendGui) {
rightPanelStackView.push(contactEdition, {"contact": friendGui, "title": qsTr("Modifier contact"), "saveButtonText": qsTr("Enregistrer")})
}
// rightPanelStackView.initialItem: contactDetail // rightPanelStackView.initialItem: contactDetail
Binding { Binding {
mainItem.showDefaultItem: false mainItem.showDefaultItem: false
when: rightPanelStackView.currentItem && rightPanelStackView.currentItem.objectName == "contactEdition" when: rightPanelStackView.currentItem
restoreMode: Binding.RestoreBinding restoreMode: Binding.RestoreBinding
} }
Connections {
target: mainItem
onContactEditionClosed: {
mainItem.forceListsUpdate()
// mainItem.rightPanelStackView.replace(contactDetail, Control.StackView.Immediate)
}
}
showDefaultItem: contactList.model.sourceModel.count === 0 showDefaultItem: contactList.model.sourceModel.count === 0
function goToNewCall() {
listStackView.replace(newCallItem)
}
property MagicSearchProxy allFriends: MagicSearchProxy { property MagicSearchProxy allFriends: MagicSearchProxy {
searchText: searchBar.text.length === 0 ? "*" : searchBar.text searchText: searchBar.text.length === 0 ? "*" : searchBar.text
@ -107,6 +110,7 @@ AbstractMainPage {
id: searchBar id: searchBar
Layout.leftMargin: leftPanel.leftMargin Layout.leftMargin: leftPanel.leftMargin
Layout.rightMargin: leftPanel.rightMargin Layout.rightMargin: leftPanel.rightMargin
Layout.topMargin: 18 * DefaultStyle.dp
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: qsTr("Rechercher un contact") placeholderText: qsTr("Rechercher un contact")
} }
@ -223,6 +227,12 @@ AbstractMainPage {
contactMenuVisible: true contactMenuVisible: true
searchBarText: searchBar.text searchBarText: searchBar.text
model: allFriends model: allFriends
Connections {
target: allFriends
onFriendCreated: (index) => {
contactList.currentIndex = index
}
}
onSelectedContactChanged: { onSelectedContactChanged: {
if (selectedContact) { if (selectedContact) {
favoriteList.currentIndex = -1 favoriteList.currentIndex = -1
@ -592,4 +602,15 @@ AbstractMainPage {
} }
} }
} }
Component {
id: contactEdition
ContactEdition {
Control.StackView.onActivated: console.log("edit/create contact")
onCloseEdition: {
if (rightPanelStackView.depth <= 1) rightPanelStackView.clear()
else rightPanelStackView.pop(Control.StackView.Immediate)
}
}
}
} }

View file

@ -16,14 +16,13 @@ AbstractMainPage {
property bool leftPanelEnabled: true property bool leftPanelEnabled: true
property ConferenceInfoGui selectedConference property ConferenceInfoGui selectedConference
property int meetingListCount property int meetingListCount
signal newConfCreated()
signal returnRequested() signal returnRequested()
signal addParticipantsValidated(list<string> selectedParticipants) signal addParticipantsValidated(list<string> selectedParticipants)
Component.onCompleted: rightPanelStackView.push(overridenRightPanel, Control.StackView.Immediate) Component.onCompleted: rightPanelStackView.push(overridenRightPanel, Control.StackView.Immediate)
onSelectedConferenceChanged: { onSelectedConferenceChanged: {
overridenRightPanelStackView.clear() overridenRightPanelStackView.clear()
if (selectedConference) { if (selectedConference && selectedConference.core.haveModel) {
if (!overridenRightPanelStackView.currentItem || overridenRightPanelStackView.currentItem != meetingDetail) overridenRightPanelStackView.replace(meetingDetail, Control.StackView.Immediate) if (!overridenRightPanelStackView.currentItem || overridenRightPanelStackView.currentItem != meetingDetail) overridenRightPanelStackView.replace(meetingDetail, Control.StackView.Immediate)
} }
} }
@ -136,7 +135,6 @@ AbstractMainPage {
mainItem.selectedConference = conferenceList.selectedConference mainItem.selectedConference = conferenceList.selectedConference
} }
RowLayout { RowLayout {
visible: leftPanelStackView.currentItem == listLayout
enabled: mainItem.leftPanelEnabled enabled: mainItem.leftPanelEnabled
Layout.rightMargin: 39 * DefaultStyle.dp Layout.rightMargin: 39 * DefaultStyle.dp
spacing: 0 spacing: 0
@ -200,10 +198,6 @@ AbstractMainPage {
} }
Connections { Connections {
target: mainItem target: mainItem
onNewConfCreated: {
// TODO : manque un connect côté c++
conferenceList.forceUpdate()
}
} }
Control.ScrollBar.vertical: ScrollBar { Control.ScrollBar.vertical: ScrollBar {
id: meetingsScrollbar id: meetingsScrollbar
@ -222,8 +216,10 @@ AbstractMainPage {
Component { Component {
id: createConf id: createConf
ColumnLayout { ColumnLayout {
id: createConfLayout
property ConferenceInfoGui conferenceInfoGui property ConferenceInfoGui conferenceInfoGui
property bool isCreation property bool isCreation
spacing: 33 * DefaultStyle.dp
RowLayout { RowLayout {
width: 320 * DefaultStyle.dp width: 320 * DefaultStyle.dp
@ -235,6 +231,8 @@ AbstractMainPage {
Layout.preferredHeight: 24 * DefaultStyle.dp Layout.preferredHeight: 24 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp icon.height: 24 * DefaultStyle.dp
topPadding: 6 * DefaultStyle.dp
bottomPadding: 6 * DefaultStyle.dp
onClicked: { onClicked: {
meetingSetup.conferenceInfoGui.core.undo() meetingSetup.conferenceInfoGui.core.undo()
leftPanelStackView.pop() leftPanelStackView.pop()
@ -250,10 +248,20 @@ AbstractMainPage {
Layout.fillWidth: true Layout.fillWidth: true
} }
Button { Button {
Layout.preferredWidth: 57 * DefaultStyle.dp
topPadding: 6 * DefaultStyle.dp topPadding: 6 * DefaultStyle.dp
bottomPadding: 6 * DefaultStyle.dp bottomPadding: 6 * DefaultStyle.dp
text: qsTr("Créer") contentItem: Text {
textSize: 13 * DefaultStyle.dp text: qsTr("Créer")
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font {
pixelSize: 13 * DefaultStyle.dp
weight: 600 * DefaultStyle.dp
}
color: DefaultStyle.grey_0
}
onClicked: { onClicked: {
if (meetingSetup.conferenceInfoGui.core.subject.length === 0) { if (meetingSetup.conferenceInfoGui.core.subject.length === 0) {
UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence doit contenir un sujet"), false) UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La conférence doit contenir un sujet"), false)
@ -272,8 +280,23 @@ AbstractMainPage {
conferenceInfoGui: parent.conferenceInfoGui conferenceInfoGui: parent.conferenceInfoGui
isCreation: parent.isCreation isCreation: parent.isCreation
Layout.rightMargin: 35 * DefaultStyle.dp Layout.rightMargin: 35 * DefaultStyle.dp
Connections {
target: meetingSetup.conferenceInfoGui ? meetingSetup.conferenceInfoGui.core : null
onConferenceSchedulerStateChanged: {
var mainWin = UtilsCpp.getMainWindow()
if (meetingSetup.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.AllocationPending
|| meetingSetup.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Updating) {
mainWin.showLoadingPopup(qsTr("Création de la conférence en cours..."))
} else {
if (meetingSetup.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Error) {
UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("La création de la conférence a échoué"), false)
}
mainWin.closeLoadingPopup()
}
createConfLayout.enabled = meetingSetup.conferenceInfoGui.core.schedulerState != LinphoneEnums.ConferenceSchedulerState.AllocationPending
}
}
onSaveSucceed: { onSaveSucceed: {
mainItem.newConfCreated()
leftPanelStackView.pop() leftPanelStackView.pop()
UtilsCpp.showInformationPopup(qsTr("Nouvelle réunion"), qsTr("Réunion planifiée avec succès"), true) UtilsCpp.showInformationPopup(qsTr("Nouvelle réunion"), qsTr("Réunion planifiée avec succès"), true)
} }
@ -364,6 +387,15 @@ AbstractMainPage {
overridenRightPanelStackView.pop() overridenRightPanelStackView.pop()
} }
} }
Connections {
target: conferenceEdit.conferenceInfoGui ? conferenceEdit.conferenceInfoGui.core : null
onConferenceSchedulerStateChanged: {
var mainWin = UtilsCpp.getMainWindow()
if (conferenceEdit.conferenceInfoGui.core.schedulerState == LinphoneEnums.ConferenceSchedulerState.Error) {
UtilsCpp.showInformationPopup(qsTr("Erreur"), qsTr("L'édition de la conférence a échoué"), false)
}
}
}
} }
} }
} }
@ -382,12 +414,12 @@ AbstractMainPage {
Layout.preferredHeight: 24 * DefaultStyle.dp Layout.preferredHeight: 24 * DefaultStyle.dp
icon.width: 24 * DefaultStyle.dp icon.width: 24 * DefaultStyle.dp
icon.height: 24 * DefaultStyle.dp icon.height: 24 * DefaultStyle.dp
onClicked: mainItem.returnRequested() onClicked: container.pop()
} }
ColumnLayout { ColumnLayout {
spacing: 3 * DefaultStyle.dp spacing: 3 * DefaultStyle.dp
Text { Text {
text: qsTr("Appel de groupe") text: qsTr("Ajouter des participants")
color: DefaultStyle.main1_500_main color: DefaultStyle.main1_500_main
maximumLineCount: 1 maximumLineCount: 1
font { font {
@ -434,6 +466,7 @@ AbstractMainPage {
visible: mainItem.selectedConference visible: mainItem.selectedConference
spacing: 25 * DefaultStyle.dp spacing: 25 * DefaultStyle.dp
Section { Section {
Layout.topMargin: 58 * DefaultStyle.dp
visible: mainItem.selectedConference visible: mainItem.selectedConference
content: RowLayout { content: RowLayout {
spacing: 8 * DefaultStyle.dp spacing: 8 * DefaultStyle.dp

View file

@ -87,4 +87,6 @@ QtObject {
property string squaresFour: "image://internal/squares-four.svg" property string squaresFour: "image://internal/squares-four.svg"
property string handWaving: "image://internal/hand-waving.svg" property string handWaving: "image://internal/hand-waving.svg"
property string screencast: "image://internal/screencast.svg" property string screencast: "image://internal/screencast.svg"
property string videoconference: "image://internal/video-conference.svg"
property string videoconferenceSelected: "image://internal/video-conference-selected.svg"
} }